APIMaster.ai

APIMaster Webhooks для асинхронных задач

Получайте подписанные уведомления о завершении и ошибках для Seedance, видео и асинхронных задач генерации изображений, с повторными попытками, историей доставки и резервным опросом (polling).

Webhooks APIMaster для асинхронных задач

Используйте вебхуки в качестве основного механизма уведомлений для асинхронной генерации, а опрос (polling) оставьте в качестве резервного варианта. APIMaster отправляет подписанный HTTPS POST, когда отслеживаемая задача завершается или завершается с ошибкой. Уведомления не зависят от провайдера генерации и используют ваш ID задачи APIMaster.

Поддерживаемые модели и эндпоинты

Seedance включает все четыре модели: seedance-2.0, seedance-2.5, seedance-2.0-fast и seedance-2.0-mini. Используйте POST /v1/videos/generations или совместимый POST /v1/video/generations.

Уведомления для видео-задач также поддерживают MiniMax-H3, Kling Omni / Motion Control, Grok Imagine Video и Sora. Поддерживаемые рабочие процессы GPT Image 2 / 2.5 и Gemini image используют /v1/images/generations/async или поддерживаемый /v1/images/edits/async; Midjourney v8.2 / Niji 7 используют /v1/midjourney/generations. Доступность маршрутов и параметры генерации по-прежнему следуют руководству каждой модели. Синхронная генерация Seedream и Grok image, потоковый чат (chat streaming) и проверка ассетов Seedance не входят в этот контракт вебхуков генерации.

Проверьте GET /v1/webhook-capabilities?model=seedance-2.0-fast на предмет соответствия модели критериям. Используйте поддерживаемый асинхронный эндпоинт отправки; соответствие критериям не означает, что каждая операция с изображениями или каждый псевдоним модели поддерживают асинхронную генерацию.

Регистрация и проверка эндпоинта

Используйте ваш API-ключ в Authorization: Bearer YOUR_API_KEY. API-ключ может управлять эндпоинтами и событиями, принадлежащими его аккаунту. Храните его на вашем сервере.

curl --fail-with-body "https://apimaster.ai/v1/webhook-endpoints" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-server.example/webhooks/apimaster"}'

Ответ содержит endpoint.id, endpoint.key_id и signing_secret. Сохраните секрет подписи безопасно: он возвращается только один раз. Он отделен от вашего API-ключа и не может авторизовать генерацию или загрузки. URL должен быть публично доступным HTTPS эндпоинтом на порту 443. Приватные адреса и редиректы отклоняются. Разрешено до 20 эндпоинтов на аккаунт; URL-адреса неизменяемы, поэтому создавайте и проверяйте новый эндпоинт при изменении назначения.

После настройки вашего приемника подтвердите владение:

curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-endpoints/whep_example/verify" \
  -H "Authorization: Bearer YOUR_API_KEY"

APIMaster отправляет подписанное событие webhook.endpoint_verification, содержащее data.challenge. Верните HTTP 200 с {"challenge":"THE_RECEIVED_CHALLENGE"} в течение 10 секунд. Запрос на генерацию, ссылающийся на непроверенный, приостановленный или эндпоинт другого аккаунта, будет отклонен до отправки.

Общий тайм-аут HTTP-запроса составляет 10 секунд, включая DNS, подключение и TLS. Заголовки ответа должны поступить в течение 8 секунд после отправки запроса. Сохраните событие и сразу подтвердите получение.

Отправка задачи с уведомлениями

curl --fail-with-body "https://apimaster.ai/v1/videos/generations" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model":"seedance-2.5",
    "prompt":"A paper boat floating on a calm pond, slow camera movement.",
    "duration":4,
    "resolution":"480p",
    "aspect_ratio":"16:9",
    "notifications":{
      "webhook":{
        "endpoint_id":"whep_example",
        "events":["task.completed","task.failed"]
      }
    },
    "client_reference_id":"order_123"
  }'

Замените ID модели на любой из четырех ID Seedance, сохраняя его собственные поддерживаемые параметры. Сохраните ID задачи из обычного ответа на создание. client_reference_id — это необязательная бизнес-ссылка длиной не более 128 байт; это не ключ идемпотентности отправки. Не сочетайте notifications с устаревшими параметрами провайдера webhook или callback_url.

Для поддерживаемых многокомпонентных редактирований изображений отправьте notifications как строку JSON в поле формы и client_reference_id как отдельное поле формы:

curl --fail-with-body "https://apimaster.ai/v1/images/edits/async" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "model=gpt-image-2" \
  -F "prompt=Turn the reference into a watercolor illustration" \
  -F "image=@reference.png" \
  -F 'notifications={"webhook":{"endpoint_id":"whep_example","events":["task.completed","task.failed"]}}' \
  -F "client_reference_id=image_order_123"

В этой версии нет эндпоинта по умолчанию для всего аккаунта: указывайте эндпоинт в каждом запросе задачи. Вебхуки могут приходить раньше ответа на вашу отправку. Сохраняйте их, даже если ваше приложение еще не сохранило возвращенный ID задачи. Некоторые асинхронные рабочие процессы для изображений оборачивают синхронную генерацию у вышестоящего провайдера, поэтому сама отправка все еще может занимать время.

Полезные данные об успехе и ошибке

Уведомление об успехе содержит публичный ID задачи и аутентифицированную ссылку на видео:

{
  "id":"evt_example",
  "type":"task.completed",
  "api_version":"2026-10-03",
  "created_at":1791014400,
  "data":{
    "task_id":"task_example",
    "model":"seedance-2.5",
    "kind":"video",
    "status":"completed",
    "client_reference_id":"order_123",
    "completed_at":1791014400,
    "task_url":"https://apimaster.ai/v1/videos/task_example",
    "result":{
      "outputs":[{
        "output_id":"0",
        "type":"video",
        "url":"https://apimaster.ai/v1/videos/task_example/content",
        "authentication":"bearer",
        "expires_at":null
      }]
    },
    "error":null
  }
}

Ошибка использует ту же оболочку с type: "task.failed", data.status: "failed", data.result: null и объектом ошибки:

{
  "code":"generation_failed",
  "message":"The generation task failed. Query the task for details."
}

Как подтвержденные провайдером ошибки, так и таймауты задач шлюза могут генерировать события об ошибках. Запрос на создание, отклоненный до принятия задачи, не генерирует событие задачи. Сбой доставки уведомления не меняет статус генерации и не запускает генерацию заново. События не подтверждают завершение биллингового согласования.

Для изображений kind — это image, а outputs содержит все доступные выходные изображения. События дочерних задач Midjourney включают batch_id; вы можете дополнительно подписаться на batch.completed, чтобы получить одну сводку пакета после завершения всех дочерних задач. Ее статус — completed, partial_failure или failed, с количеством в data.summary. Завершение пакета не всегда означает, что каждая дочерняя задача завершилась успешно.

Загружайте выходные URL с помощью API-ключа, принадлежащего аккаунту задачи. Сохраняйте сгенерированные медиафайлы оперативно. expires_at: null означает, что гарантированное время истечения срока действия не предоставляется, а не постоянное хранение; последующая загрузка может вернуть HTTP 410. Повторное воспроизведение события не продлевает доступность медиафайлов.

Аутентификация обратных вызовов и своевременное подтверждение

Каждый POST-запрос содержит:

X-APIMaster-Event-ID: evt_example
X-APIMaster-Delivery-ID: dlv_example
X-APIMaster-Timestamp: 1791014400
X-APIMaster-Signature: v1=<hex-hmac>,kid=<key-id>

Проверяйте HMAC-SHA256 по временной метке, буквальной точке и сырым байтам тела запроса, используя секрет подписи конечной точки. Используйте сравнение с постоянным временем, допускайте отклонение часов не более пяти минут и проверяйте, что заголовок Event-ID соответствует ID в теле. Повторные попытки сохраняют тот же ID события и тело, но получают новый ID доставки, временную метку и подпись.

Следующий приемник на Python использует Flask и SQLite. Он атомарно сохраняет событие перед его подтверждением. Ваш рабочий процесс приложения должен потреблять сохраненные строки, загружать файлы и выполнять бизнес-логику отдельно.

import hashlib, hmac, json, os, sqlite3, time
from flask import Flask, request, jsonify, abort

app = Flask(__name__)
# During key rotation, configure both active and previous kid/secret pairs.
SECRETS = json.loads(os.environ["APIMASTER_WEBHOOK_SECRETS_JSON"])
DB_PATH = os.environ.get("WEBHOOK_DB_PATH", "webhook-events.sqlite3")
with sqlite3.connect(DB_PATH) as db:
    db.execute("CREATE TABLE IF NOT EXISTS events (id TEXT PRIMARY KEY, body BLOB NOT NULL)")

@app.post("/webhooks/apimaster")
def receive():
    raw = request.get_data()
    try:
        timestamp = request.headers["X-APIMaster-Timestamp"]
        if abs(time.time() - int(timestamp)) > 300:
            abort(401)
        fields = dict(part.split("=", 1) for part in
                      request.headers["X-APIMaster-Signature"].split(","))
        secret = SECRETS[fields["kid"]]
        expected = hmac.new(secret.encode(), timestamp.encode() + b"." + raw,
                            hashlib.sha256).hexdigest()
        if not hmac.compare_digest(expected, fields["v1"]):
            abort(401)
        event = json.loads(raw)
        if event["id"] != request.headers["X-APIMaster-Event-ID"]:
            abort(401)
    except (KeyError, ValueError, TypeError):
        abort(401)
    if event["type"] == "webhook.endpoint_verification":
        return jsonify(challenge=event["data"]["challenge"])
    with sqlite3.connect(DB_PATH) as db:
        db.execute("INSERT OR IGNORE INTO events(id, body) VALUES (?, ?)",
                   (event["id"], raw))
    return "", 204

Возвращайте любой статус 2xx в течение 10 секунд для событий генерации. Подтверждайте после сохранения в устойчивое хранилище, не дожидаясь загрузки медиафайлов. Доставка происходит как минимум один раз: возможны дублирующиеся события, особенно если подтверждение потеряно, поэтому устраняйте дублирование по id. Гарантии порядка выполнения задач нет.

Повторные попытки, история доставки и повторное воспроизведение

APIMaster повторяет попытки при сбоях сети, тайм-аутах подтверждения и ответах не 2xx в течение 72 часов с момента создания события. Начальные задержки составляют 1, 2, 5, 15 и 30 минут, затем 1, 2, 4 и 8 часов, далее с интервалами в 12 часов, с возможным разбросом до 20%. Действительный Retry-After на 429/503 учитывается в течение окна повторных попыток. Перенаправления не отслеживаются. HTTP 410 приостанавливает конечную точку; другие ответы 4xx повторяются, чтобы позволить исправить конфигурацию.

curl --fail-with-body "https://apimaster.ai/v1/webhook-events?task_id=task_example" \
  -H "Authorization: Bearer YOUR_API_KEY"

curl --fail-with-body "https://apimaster.ai/v1/webhook-events/evt_example/deliveries" \
  -H "Authorization: Bearer YOUR_API_KEY"

curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-events/evt_example/redeliver" \
  -H "Authorization: Bearer YOUR_API_KEY"

Статусы включают pending, in_flight, retrying, delivered, paused и exhausted. Записи о событиях и попытках хранятся 30 дней. Повторное воспроизведение сохраняет исходный ID события и полезную нагрузку и открывает новое 72-часовое окно доставки; оно не перегенерирует медиафайлы и не списывает средства повторно. Допускается до пяти ручных повторных воспроизведений на событие за календарный день по UTC. Событие, в настоящее время заблокированное для доставки, не может быть воспроизведено повторно, пока эта попытка не завершится или ее блокировка не истечет.

Приостановите или возобновите конечную точку с помощью PATCH /v1/webhook-endpoints/{id} и {"enabled":false} или {"enabled":true}. Возобновление продолжает приостановленные события, исходный срок которых еще не истек. Смените секреты с помощью POST /v1/webhook-endpoints/{id}/rotate-secret; сохраните новый секрет и kid и сохраните предыдущую пару на возвращаемый 24-часовой переходный период.

Резервный опрос

Для задач, по которым не получено конечное событие, запрашивайте /v1/videos/{task_id} или документированный запрос задачи с изображением модели каждые 60–120 секунд. Используйте API задач как источник истины и проверяйте историю доставки, если генерация завершена, но уведомление отсутствует. Отсутствие вебхука не является причиной для повторной отправки платного запроса на генерацию. Длительный простой конечной точки может исчерпать автоматические повторные попытки; восстановите приемник и воспроизведите сохраненные события.