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"]
}| Параметр | Тип | Обязательное | Описание |
|---|---|---|---|
url | string | да | HTTPS URL (до 2000 символов) |
events | string[] | нет | Подписка на события (по умолчанию — все) |
Доступные события:
| Событие | Описание |
|---|---|
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 (без секретов).
Python
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.
Python
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-Signature | HMAC-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, полученного при создании.
Python
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", 200Retry-политика
Если ваш сервер не ответил 2xx, webhook будет повторён:
| Попытка | Задержка |
|---|---|
| 1 | 5 минут |
| 2 | 15 минут |
| 3 | 1 час |
| 4 | 6 часов |
| После 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 и не указывать на приватные адреса