Creative APIDocs
Общее API

Общее API

Callback и проверка подписи

Если при создании задачи передан callBackUrl, после завершения мы отправим на него POST с результатом. Подпись подтверждает, что запрос пришёл от нас.

Тело callback

{
  "code": 200,
  "msg": "Task completed successfully.",
  "data": {
    "taskId": "3f9c2a7be41d4c0c9a7d5e2b1c8f0a64",
    "model": "seedream/5-pro-text-to-image",
    "state": "success",
    "param": "{\"input\":\"{\\\"prompt\\\":\\\"A red fox sitting in fresh snow, morning light, photorealistic\\\",\\\"aspect_ratio\\\":\\\"1:1\\\",\\\"quality\\\":\\\"basic\\\"}\",\"model\":\"seedream/5-pro-text-to-image\"}",
    "resultJson": "{\"resultUrls\":[\"https://files.cr-api.ru/Qm3xV8rTt1ZbW0kq7Lr2aA.png\"]}",
    "failCode": null,
    "failMsg": null,
    "costTime": 14,
    "completeTime": 1762941614000,
    "createTime": 1762941600000,
    "updateTime": 1762941614000,
    "creditsConsumed": 5.25
  }
}
  • code 200 и msg Task completed successfully. — задача выполнена; code 501 и msg Task failed. — ошибка, причина в data.failCode и data.failMsg.
  • data — тот же объект, что возвращает Статус задачи.

Доставка

  • Ответьте любым кодом 2xx в течение 10 секунд — callback считается доставленным. Тело ответа мы не читаем.
  • Другой код, таймаут или ошибка соединения — повтор: через 10 секунд, 1, 5 и 15 минут, через час и дальше раз в час в течение 24 часов.
  • Доставка «хотя бы один раз»: после сбоя callback может прийти повторно. Отличайте повтор по data.taskId.
  • Адрес должен быть публичным: на внутренние и служебные адреса callback не отправляется.
  • Редиректы не выполняются.
  • Повторно отправить callback можно из кабинета, раздел «Логи».

Подпись

Создайте ключ подписи в кабинете (раздел «Настройки»). С ним каждый callback несёт два заголовка:

ЗаголовокЗначение
X-Webhook-TimestampВремя отправки, секунды Unix
X-Webhook-Signaturebase64(HMAC-SHA256(taskId + "." + timestamp, ключ подписи))

Пока ключа нет, callback уходит без подписи. Проверяйте подпись и время: запрос старше 5 минут отклоняйте.

Проверка

import { createHmac, timingSafeEqual } from "node:crypto";

// Ключ подписи callback из кабинета (раздел «Настройки»).
const WEBHOOK_KEY = "YOUR_WEBHOOK_KEY";

/** body — разобранный JSON запроса, headers — его заголовки (имена в нижнем регистре). */
export function verifyCallback(body, headers) {
  const timestamp = headers["x-webhook-timestamp"];
  const signature = headers["x-webhook-signature"];
  if (!timestamp || !signature) return false;
  // Подпись старше 5 минут — повтор чужого запроса.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected = createHmac("sha256", WEBHOOK_KEY)
    .update(`${body.data.taskId}.${timestamp}`)
    .digest("base64");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

Подписаны taskId и время, а не тело целиком. Надёжнее всего после callback прочитать задачу через Статус задачи и брать результат оттуда.