Skip to Content

Webhooks

Webhooks позволяют получать уведомления при завершении генерации без необходимости polling. API отправляет POST-запрос на ваш URL с информацией о результате.

Два способа получать уведомления

1. Зарегистрированные webhooks

Создаёте webhook один раз — получаете уведомления обо всех генерациях. Поддерживает retry при ошибках доставки.

2. Ad-hoc webhook_url

Указываете webhook_url в каждом запросе генерации. Удобно для простых интеграций. Без retry.


Управление webhooks

POST /webhooks

Зарегистрировать новый webhook. Максимум 5 на аккаунт.

Запрос:

{ "url": "https://example.com/aidentika-webhook", "events": ["generation.completed", "generation.failed"] }
ПараметрТипОбязательноеОписание
urlstringдаHTTPS URL (до 2000 символов)
eventsstring[]нетПодписка на события (по умолчанию — все)

Доступные события:

СобытиеОписание
generation.completedГенерация фото/карточки завершена
generation.failedГенерация фото/карточки не удалась
edit.completedРедактирование завершено
edit.failedРедактирование не удалось
video.completedВидео сгенерировано
video.failedВидео не удалось

Ответ:

{ "id": 1, "url": "https://example.com/aidentika-webhook", "secret": "whsec_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456", "events": ["generation.completed", "generation.failed"], "is_active": true, "created_at": "2026-02-23T10:00:00Z" }

Важно: secret показывается только один раз при создании. Сохраните его для верификации подписей.

Ошибки:

  • 422 — URL не HTTPS, указывает на приватный IP, или неизвестные события
  • 422 — лимит 5 webhooks на аккаунт

GET /webhooks

Список всех webhooks (без секретов).

resp = requests.get(f"{BASE}/webhooks", headers=headers) for wh in resp.json()["webhooks"]: print(f"#{wh['id']}: {wh['url']} ({', '.join(wh['events'])})")
{ "webhooks": [ { "id": 1, "url": "https://example.com/aidentika-webhook", "events": ["generation.completed", "generation.failed"], "is_active": true, "created_at": "2026-02-23T10:00:00Z", "updated_at": "2026-02-23T10:00:00Z" } ] }

DELETE /webhooks/:id

Удалить webhook.

resp = requests.delete(f"{BASE}/webhooks/1", headers=headers) print(resp.json()) # {"deleted": true}

Формат доставки

При наступлении события API отправляет POST-запрос на URL webhook:

Заголовки

Content-Type: application/json X-Aidentika-Signature: sha256=a1b2c3d4e5f6... X-Aidentika-Event: generation.completed X-Aidentika-Delivery-Id: 42
ЗаголовокОписание
X-Aidentika-SignatureHMAC-SHA256 подпись тела запроса
X-Aidentika-EventНазвание события
X-Aidentika-Delivery-IdУникальный ID доставки

Тело запроса

{ "action_id": 12345, "project_id": 678, "card_id": 910, "type": "generate" }

Payload содержит идентификаторы. Для получения полных данных (result_url, status) используйте GET /status/:action_id.


Верификация подписи

Каждый webhook подписывается HMAC-SHA256 с использованием secret, полученного при создании.

import hmac import hashlib import json def verify_webhook(request_body: bytes, signature_header: str, secret: str) -> bool: """Проверить подпись webhook.""" expected = signature_header.removeprefix("sha256=") actual = hmac.new( secret.encode(), request_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, actual) # Использование (Flask) @app.route("/aidentika-webhook", methods=["POST"]) def handle_webhook(): body = request.get_data() signature = request.headers.get("X-Aidentika-Signature", "") if not verify_webhook(body, signature, WEBHOOK_SECRET): return "Invalid signature", 401 payload = json.loads(body) event = request.headers.get("X-Aidentika-Event") if event == "generation.completed": action_id = payload["action_id"] # Получить результат... return "OK", 200

Retry-политика

Если ваш сервер не ответил 2xx, webhook будет повторён:

ПопыткаЗадержка
15 минут
215 минут
31 час
46 часов
После 4Доставка прекращается

Ваш сервер должен:

  • Ответить 200–299 для подтверждения получения
  • Ответить за 10 секунд (таймаут)
  • Быть идемпотентным (одно событие может прийти несколько раз)

Требования к URL

  • Только HTTPS (HTTP не принимается)
  • URL не должен указывать на приватные/локальные адреса (127.0.0.1, 10.*, 192.168.* и т.д.)
  • Hostname должен резолвиться через DNS

Ad-hoc webhook_url

Вместо создания зарегистрированного webhook можно указать webhook_url в каждом запросе генерации:

{ "images": [...], "category_id": "cosmetics", "concept_id": "cosmetics_catalog", "webhook_url": "https://example.com/callback/order-123" }

Особенности:

  • Без retry (одна попытка)
  • Без подписи (нет HMAC)
  • Работает для /generate/photo, /generate/card, /generate/video, /edit/:id
  • URL должен быть HTTPS и не указывать на приватные адреса