> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hubtalk.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Контракт для разработчика

> Что платформа присылает, что ждёт в ответе, как устроен маппинг, пробный вызов и ключи конфигурации.

# Контракт для разработчика

Раздел для того, кто поднимает HTTP-обработчик на стороне клиента.

## Запрос от платформы

Адрес, заголовки, параметры и тело собираются из полей формы с подстановкой `{{переменная}}`. Доступны переменные звонка (`from_number`, `to_number`, `direction` и всё, что настроено в агенте и кампании), результаты уже выполненных функций и — только в блоке после звонка — `call` и `analysis`.

Секреты в поля не вписываются: только ссылкой `{{env.ИМЯ_ПЕРЕМЕННОЙ}}`, значение подставляется платформой при выполнении. В истории звонка запрос сохраняется маскированным.

Таймаут запроса — поле функции, по умолчанию 10 с, потолок 30 с. Эффективный таймаут ещё урезается остатком бюджета блока: остаток берётся один раз на строку и становится потолком для каждой её функции.

## Ответ и маппинг

Из ответа платформа пишет в переменные сценария служебный набор (`<имя>_status`, `_success`, `_error`, `_result`, плюс глобальные `http_*`) и то, что перечислено в маппинге.

Маппинг — это словарь **«имя переменной → JSONPath в ответе»**; имя переменной здесь ключ, а не значение. В форме он и выглядит так: слева имя, справа путь (`balance ← $.data.balance`). Имена задаёт настройщик агента в кабинете, вы их не выбираете — договоритесь заранее, какие поля отдаёте.

## Решение о звонке

Чтобы остановить набор из кампании, верните поля, которые в маппинге положены в `call_decision`, `call_decision_reason` и `call_retry_after` (значения и последствия — в разделе [Решение о звонке в кампании](/ru/v4/platform/call-functions/campaign-decision)).

Минимальный обработчик, отменяющий звонок:

```python theme={null}
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        body = json.dumps({"decision": "cancel", "reason": "debt_paid"})
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(body.encode())

HTTPServer(("0.0.0.0", 8099), Handler).serve_forever()
```

В маппинге ответа функции: `call_decision ← $.decision`, `call_decision_reason ← $.reason`. Дальше — кампания с одним контактом: телефон не зазвонит, контакт закроется, в разбивке исходов появится «Отменены функцией».

## Пробный вызов

Кнопки «Проверить» и «Проверить блок» бьют в эндпоинт кабинета `POST /api/flows/{name}/call-functions/run`. Тело: `{function, phase: "pre"|"post", variables?, mock?, budget?}` либо `{functions: [...]}` для прогона всего блока. Для `phase="pre"` поле `budget` выбирает бюджет: `inbound` (10 с, по умолчанию) или `outbound` (60 с). Для `phase="post"` тело принимает `analysis` — заглушку результата аналитики.

В ответе: `status`, `elapsed_ms`, имена записанных переменных, маскированный запрос, `status_code`, номер строки и зависимости, дифф переменных, а также `when: {expression, result}` — как отработало условие. Для `phase="pre"` добавляется `decision` — как прочиталось ваше решение: `{action, reason, retry_after, retry_at, warning, declared}`.

## Ключи конфигурации платформы

| Ключ                                              | По умолчанию | Что задаёт                                                                   |
| ------------------------------------------------- | ------------ | ---------------------------------------------------------------------------- |
| `call_functions.pre_call_budget_seconds`          | 10           | бюджет до первой реплики (входящие, web)                                     |
| `call_functions.pre_call_budget_seconds_outbound` | 60           | бюджет до набора номера (исходящие)                                          |
| `call_functions.late_delivery`                    | включено     | доработка в фоне у входящих и web                                            |
| `call_functions.post_call_analysis_wait_seconds`  | 60           | сколько функции после звонка ждут оценку разговора; `0` — не ждать           |
| `call_functions.decision_pause_window`            | 20           | окно последних решений для защиты от массовой отмены; `0` — защита выключена |
| `call_functions.decision_pause_cancel_share`      | 1.0          | доля отмен в окне, при которой кампания встаёт на паузу                      |
