---
title: "Use Case 4: Mock CRM lookup"
description: "HTTP-запит до mock API, збереження JSON у змінній, розгалуження ok / not_ok і Instance Settings для токена."
---

# Use Case 4: Mock CRM lookup

**Рівень:** базовий · **Модулі:** Scenario Builder, Instance Settings · **Action:** `action_send_request`

> **Перед стартом:** прочитайте [Mock vs production API](/uk/learn/implementer/training/concepts.md#mock-vs-production-api) і [Розгалуження: Router / switch](/uk/learn/implementer/training/concepts.md#router-branching).

## Необхідні права та доступ

| Що потрібно | Де в меню | Навіщо |
|-------------|-----------|--------|
| **Scenario Builder** | Меню → Scenario Builder | WaitForInput, send_request, Router |
| **Instance Settings** | Налаштування → Instance Settings | Ключ `training_api_token` для Bearer |

Якщо розділу немає в меню — перевірте права облікового запису або зверніться до підтримки ConnectiveOne.

## Бізнес-контекст

Бот перевіряє «клієнта» через зовнішній API. На навчанні використовуйте **mock URL** — не потрібна справжня CRM. Це патерн для production-інтеграцій: запит → змінна → розгалуження за результатом.

## Очікуваний результат

- GET до mock URL → JSON у змінній (напр. `crm_data`).
- Розгалуження: клієнт знайдено / не знайдено / помилка API.
- Edge **`not_ok`** / **`error`** → повідомлення клієнту (не тиша).
- Токен зберігається в Instance Settings, не в коді сценарію.

## Архітектура flow

```text
WaitForInput (phone) → action_send_request (GET mock)
   ├─ ok → Router → «Клієнт: {{crm_data.name}}»
   ├─ not_ok → «Тимчасово недоступно» (+ operator опційно)
   └─ (в ok) перевірка полів → «Новий клієнт»
```

## Покрокова реалізація

### Крок 0. Instance Settings

Settings → **Instance Settings** → ключ:

| Ключ | Значення (навчання) | Навіщо |
|------|---------------------|--------|
| `training_api_token` | будь-який рядок | Імітація Bearer-токена CRM |

У сценарії: `{{instance_settings.training_api_token}}` — секрет не в коді Action Jail.

---

### Крок 1. WaitForInput — телефон

| Параметр | Значення | Навіщо |
|----------|----------|--------|
| messageText | «Введіть номер телефону» | |
| outputVariable | `phone_raw` | Для URL або body ([Use Case 5](/uk/learn/implementer/training/basic/use-case-05-action-jail-phone.md) нормалізує) |
| Validation → type | `phone` *(або `none` на першому проході)* | Менше сміття в mock-запиті |

**Edges:** успішний ввід → `action_send_request`.

---

### Крок 2. Action — `action_send_request`

**Що робить action:** HTTP-запит до зовнішнього URL; при успіху зберігає тіло відповіді в constants; повертає подію `ok` / `not_ok`.

| node_params | Значення (mock) | Навіщо |
|-------------|-----------------|--------|
| `url` | `https://jsonplaceholder.typicode.com/users/1` | Стабільний JSON без реєстрації |
| `method` | `GET` | Lookup без body |
| `headers` | `{"Content-Type": "application/json"}` | Явний тип |
| `bearer_auth.token` | `{{instance_settings.training_api_token}}` | Патерн auth через Instance Settings |
| `save_responce` | `crm_data` | **Ім'я змінної** з відповіддю → `{{crm_data.name}}`, `{{crm_data.email}}` *(поле в Engine з історичною опечаткою `responce`)* |

Альтернатива: `response_mapping` — мапити окремі поля JSON у named constants.

**Edges:**

| Edge | Коли | Куди | Навіщо |
|------|------|------|--------|
| **`ok`** | HTTP успішний, є `response.data` | Router / MessageKeyboard «Знайдено: {{crm_data.name}}» | Happy path |
| **`not_ok`** | Мережа, 4xx/5xx, порожня відповідь | «Сервіс тимчасово недоступний» | **Обов'язково** — інакше тиша |
| `error` *(якщо є в Inspector)* | Збій action | Те саме або escalate | Failsafe |

Перевірка помилки: тимчасово підставте URL `https://jsonplaceholder.typicode.com/404` → має бути **`not_ok`**.

---

### Крок 3. Router — інтерпретація відповіді

**Нода:** Router (`action_router`), режим `first_match`.

| Правило | Навіщо |
|---------|--------|
| `{{crm_data.name}}` **not_empty** | «Клієнт знайдено: {{crm_data.name}}» |
| **Default branch** | «Новий клієнт — даних у CRM немає» |

**Альтернатива:** Action **`switch`** з тими самими умовами.

> Legacy **`if_else`** у старих сценаріях — та сама логіка; на навчанні використовуйте Router.

**Edges:** кожна гілка Router → MessageKeyboard.

---

### Крок 4. Тест у Runs

1. Runs → після `ok` у constants є об'єкт `crm_data`.
2. Зламаний URL → **`not_ok`** + ваше повідомлення.
3. Запишіть у [файл результатів](/uk/learn/implementer/training/results-template.md): який edge спрацював і які змінні в trace.

## Критерії приймання (self-check Runs)

- [ ] Happy path: після `ok` у trace є `crm_data` з полями JSON.
- [ ] URL 404 або зламаний → edge **`not_ok`**, клієнт бачить повідомлення.
- [ ] Edges **`ok`** і **`not_ok`** підключені на полотні.
- [ ] Токен береться з `{{instance_settings.training_api_token}}`.
- [ ] Router (або `switch`) коректно розрізняє «знайдено» і «новий клієнт».
- [ ] *(Опційно)* Той самий CRM-flow перезібрано через Instance Agent і звірено в Runs ([правило](/uk/learn/implementer/training/prerequisites.md#правило-instance-agent)).

## Типові помилки

| Симптом | Причина | Що зробити |
|---------|---------|------------|
| Бот «замовкає» після запиту | Немає edge **not_ok** | Підключити not_ok → MessageKeyboard |
| `{{crm_data.name}}` буквально | Невірний `save_responce` | Перевірити ім'я змінної в node_params |
| Завжди not_ok | Невірний URL або мережа | Перевірити URL у браузері |
| 401 у trace | Bearer не передано | Перевірити Instance Settings і `bearer_auth.token` |

## Пов'язана документація

- [Mock vs production API](/uk/learn/implementer/training/concepts.md#mock-vs-production-api)
- [send_request у actions-reference](/uk/actionjail/reference/actions-reference.md)
- [Action Jail — інтеграції](/uk/actionjail/how-to/integrator-embed-actions.md)
- [FAQ — CRM / mock](/uk/learn/implementer/training/reference/faq.md)
- Далі: [Use Case 5 — нормалізація телефону](/uk/learn/implementer/training/basic/use-case-05-action-jail-phone.md)
