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

Быстрый старт

При отправке задачи добавьте поле webhook в тело запроса:
curl -X POST https://ваш-домен-доступа/v1/images/generations \
  -H "Authorization: Bearer ВАШ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "a red apple on a table",
    "size": "1024x1024",
    "webhook": "https://your-server.com"
  }'
После завершения задачи мы отправим POST-запрос на ваш URL + /callback.
Другие конечные точки асинхронных задач (видео, аудио и т. д.) работают так же — просто добавьте поле webhook в тело запроса.

Правила URL

Указанный вами webhook — это базовый URL (base), к которому мы автоматически добавляем /callback:
Ваш webhookКуда мы фактически отправляем POST
https://your-server.comhttps://your-server.com/callback
https://your-server.com/apihttps://your-server.com/api/callback
https://your-server.com/api/https://your-server.com/api/callback
Поэтому на вашем сервере нужна конечная точка, принимающая POST .../callback.

Что вы получите

Отправляемое содержимое полностью совпадает с тем, что возвращает конечная точка «Получение статуса задачи» — вы можете обрабатывать его той же логикой разбора.
{
  "id": "task_01KV7FXR8BEYS1BWHJCT3JMCJ5",
  "status": "completed",
  "progress": 100,
  "created": 1781589029,
  "completed": 1781589058,
  "actual_time": 29,
  "cost": 0.006,
  "credits_cost": 0.06,
  "result": {
    "images": [{ "url": ["https://.../result.png"], "expires_at": 1781675458 }]
  }
}
Для видеозадач результат находится в result.videos, а для аудио — в result.audios.
Мы отправляем уведомление только когда задача достигает конечного состояния (completed / failed); во время обработки уведомления не отправляются.

Повторные попытки и дедупликация (важно)

  • Повторные попытки: Если ваш сервер не вернёт 2xx примерно за 10 секунд или вернёт 5xx, мы автоматически повторим попытку, до 3 раз, с интервалами около 10 с, 30 с и 60 с. Если все 3 попытки неудачны, мы прекращаем (примерно за 2 минуты).
  • Без повтора: Если ваша конечная точка вернёт 4xx (считается проблемой URL / запроса), мы сразу прекращаем без повторных попыток.
  • Дедупликация: Обычно задача отправляется только один раз. Но в крайних случаях (например, перезапуск на нашей стороне после отправки, но до подтверждения) вы можете получить повторные отправки. Обязательно выполняйте идемпотентную дедупликацию по id (task_id), чтобы избежать повторной обработки.
Рекомендации для вашей принимающей конечной точки:
1

Возвращайте 2xx как можно быстрее

Сначала примите и поставьте в очередь, затем обрабатывайте асинхронно — не заставляйте нас ждать завершения вашей обработки.
2

Дедуплицируйте по id

Используйте id (task_id) как ключ идемпотентности, чтобы избежать повторной обработки.
3

Настройте и проверяйте подпись

В продакшене проверяйте источник запросов обратного вызова и отклоняйте поддельные.

Требования к URL обратного вызова

В целях безопасности URL обратного вызова должен соответствовать следующему:
ТребованиеОписание
Публично доступенНе может быть внутренним / локальным адресом (например, 127.0.0.1, 10.x, 192.168.x будут отклонены)
Протоколhttp или https (рекомендуется https)
ПортИспользуйте стандартные порты (80 / 443); нестандартные порты могут блокироваться
ДоменНе может указывать на наш собственный сервисный домен
URL, не отвечающие этим требованиям, отбрасываются (без отправки и без повторов).

Частые вопросы

Проверьте по пунктам:
  1. Задача действительно завершена? Проверьте детали задачи — status равен completed / failed (во время обработки уведомления не отправляются)?
  2. Ваш URL публично доступен? Можем ли мы достучаться до вашего /callback?
  3. Порт стандартный (80 / 443)? Нестандартные порты могут блокироваться политиками безопасности.
  4. Ваш /callback вовремя вернул 2xx? При 4xx мы сразу прекращаем.
  5. Используете ли вы https? Действителен ли сертификат?
Некоторые модели создают несколько изображений за раз, поэтому images[].url может быть массивом — просто обрабатывайте его как массив.
Если в result есть expires_at (метка времени Unix), это время истечения срока действия ссылки — вовремя перенесите/сохраните её.
Нет. Мы отправляем уведомление только один раз, когда задача окончательно завершается успехом или ошибкой.

Минимальный пример приёмника

Python
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class H(BaseHTTPRequestHandler):
    def do_POST(self):
        n = int(self.headers.get("Content-Length") or 0)
        body = self.rfile.read(n)
        data = json.loads(body)
        print("Получен обратный вызов задачи:", data["id"], data["status"])
        # TODO: дедуплицировать по id, проверить подпись, затем обработать
        self.send_response(200); self.end_headers()
        self.wfile.write(b'{"ok":true}')

HTTPServer(("0.0.0.0", 443), H).serve_forever()
Возвращайте 200 как можно быстрее, а логику обработки выполняйте асинхронно в фоне.