Перейти к содержанию

Webhooks: обзор

После завершения верификации (успешного или по таймауту) мы отправляем POST-запрос на webhook_url, указанный при создании верификации.

Когда приходят

Событие type Когда
Успешная верификация verification.completed Пользователь позвонил с правильного номера. Приходит через 1–3 секунды после звонка.
Истечение TTL verification.expired За ttl_seconds (по умолчанию 300) звонок не поступил.

verification.failed

Есть третий событийный тип verification.failed — внутренняя ошибка обработки. По умолчанию он не отправляется наружу (в большинстве случаев восстанавливается автоматически). Если для вашего use-case нужно получать failed-события — напишите в саппорт.

Формат запроса

POST /your-endpoint HTTP/1.1
Host: your-app.example.com
Content-Type: application/json
User-Agent: TrueNum/1.0
X-Truenum-Signature: t=1748255418,v1=<hex_hmac_sha256>

{
  "type": "verification.completed",
  "verification_id": "ver_01HXYZ4K9P2N3M8R7Q5S6T0V1W",
  "phone": "+79991234567",
  "dial_number": "+74951234567",
  "client_ref": "user-1234",
  "caller_id": "+79991234567",
  "completed_at": "2026-05-26T12:30:18+00:00"
}

Поля тела

Поле Тип Описание
type string verification.completed или verification.expired.
verification_id string ID исходной верификации (тот же, что вернул POST /verifications/).
phone string Номер из запроса.
dial_number string Номер, на который пользователь звонил.
client_ref string Ваш идентификатор из запроса.
caller_id string Только в completed — реальный номер звонящего. Сравните с phone.
completed_at string (ISO 8601) Момент терминального события. Для completed — время звонка. Для expired — момент истечения TTL.

Игнорируйте незнакомые поля

Мы можем добавлять новые поля без выпуска новой версии API. Ваш парсер должен быть толерантен к дополнительным ключам.

Что должен делать ваш эндпоинт

  1. Принять POST, прочитать тело (raw bytes — для верификации подписи!).
  2. Проверить подпись X-Truenum-Signatureинструкция. Без проверки подписи — не доверяйте содержимому тела.
  3. Найти у себя верификацию по verification_id или client_ref.
  4. Сравнить caller_id с phone (для completed). При совпадении — отметьте номер как верифицированный.
  5. Ответить 2xx (рекомендуется 200 OK) в течение 10 секунд.

Что считается успехом

HTTP 2xx (200–299). Любой другой статус (включая 3xx redirect) или сетевая ошибка / таймаут — повторим. Подробнее — Ретраи.

Безопасность

  • Эндпоинт должен быть публичным (наш SSRF-гард на стороне API отклоняет приватные/loopback/link-local адреса в момент создания верификации; см. Безопасность).
  • Используйте HTTPS — TrueNum не отправляет webhook'и на HTTP, если только URL явно не помечен как dev.
  • Не полагайтесь на IP-источник для аутентификации — мы можем менять egress-адреса. Полагайтесь на HMAC-подпись.

Идемпотентность приёма

При ретраях один и тот же verification_id + type может прилететь несколько раз. Ваш обработчик должен быть идемпотентным:

def handle_webhook(payload: dict) -> None:
    # Грубая идемпотентность через UNIQUE constraint.
    try:
        WebhookEvent.objects.create(
            verification_id=payload["verification_id"],
            event_type=payload["type"],
        )
    except IntegrityError:
        return  # уже обработали
    # ... основная логика

Дашборд: журнал доставок

В дашборде → WebhooksDeliveries видны последние попытки доставки:

  • HTTP-код ответа вашего эндпоинта.
  • Количество попыток.
  • Тело запроса/ответа (для дебага).
  • Кнопка Retry — ручной перезапуск доставки.

Если webhook никак не доходит и автоматические ретраи исчерпаны (см. Ретраи), используйте Retry или поллинг через GET /api/v1/verifications/{id}/.