HiAPI
Блог

Руководство

Не приходят callback-запросы HiAPI? Диагностика и исправление проблем доставки Webhook

Oct 14, 2026
Не приходят callback-запросы HiAPI? Диагностика и исправление проблем доставки Webhook

Вы передали callback.url при отправке задачи через POST https://api.hiapi.ai/v1/tasks, чтобы HiAPI после завершения задачи сам отправил вам POST-уведомление. Но хотя в GET /v1/tasks/{taskId} задача уже имеет статус success, ваш callback-эндпоинт не получил ни одного запроса. В 80% случаев проблема не на стороне HiAPI, а в том, доступен ли адрес callback, возвращает ли принимающая сторона 2xx по договорённости, и не опережает ли опрос (polling) callback. Ниже разберём всё по пунктам согласно реальному контракту callback и дадим готовые к применению шаги исправления.

Если ваша задача долго не достигает терминального состояния (data.status долго остаётся в queued/handling/archiving), это другая проблема — смотрите руководство по диагностике и повторным попыткам при зависании или таймауте задач HiAPI. В этой статье рассматривается только сценарий, когда задача уже завершена, но уведомление callback не приходит.

Симптомы проблемы

Типичная картина: на стороне задачи всё в порядке, GET /v1/tasks/{taskId} возвращает data.status равный success (или fail), но в логах вашего callback-эндпоинта, развёрнутого в публичной сети, нет ни одной записи POST от HiAPI; или запросы приходят изредка и часто теряются; или один и тот же taskId доставляется дважды, и ваша логика дедупликации считает это аномалией.

Сначала установим факт: callback — это лишь один из способов получить результат, а не единственный канал. Асинхронные задачи HiAPI всегда можно получить в терминальном состоянии через активный опрос GET /v1/tasks/{taskId}, а callback (Webhook) лишь избавляет вас от опроса. Поэтому «callback не приходит» не означает «результат недоступен»: сначала убедитесь опросом, что сама задача в порядке, а затем локализуйте проблему доставки.

Реальный контракт callback (сначала свериться, потом искать ошибку)

При регистрации callback callback — это поле верхнего уровня POST /v1/tasks, на одном уровне с model и input, его нельзя помещать внутрь input:

{
  "model": "gpt-image-2",
  "input": { "prompt": "a calm blue data center" },
  "callback": {
    "url": "https://your-domain.com/hiapi/callback",
    "when": "final"
  }
}

Несколько моментов, которые нужно запомнить:

  • callback.url должен быть доступным из публичной сети http(s)-URL, HiAPI отправляет на него POST из публичной сети.
  • callback.when в настоящее время принимает только final: доставка один раз при достижении задачей терминального состояния, срабатывает и при success, и при fail. Callback по прогрессу или по этапам нет.
  • Способ доставки — POST + Content-Type: application/json, тело запроса полностью совпадает с полем data из GET /v1/tasks/{taskId}, то есть это объект деталей задачи, содержащий status, output, error, taskId, created, completed и т. д.
  • При неудачной доставке (не 2xx / таймаут / сетевая ошибка) повторная отправка выполняется по схеме сразу → +1 минута → +5 минут → +20 минут, максимум 4 раза; после 4 неудач повторы прекращаются, и это не влияет на состояние самой задачи.
  • Callback о терминальном состоянии имеет семантику **минимум одного раза (at least once)**, а не ровно одного раза. Один и тот же taskId может доставляться несколько раз, принимающая сторона должна выполнять идемпотентную дедупликацию по taskId.

Детали контракта — в официальной документации: создание задачи и поле callback, обзор асинхронного API (повторы callback и идемпотентность).

Частые причины (по убыванию вероятности)

1. Адрес callback недоступен из публичной сети (самое частое)

Указан http://localhost:3000/..., внутренний IP или домен, который разрешается только через внутренний DNS. HiAPI из публичной сети не может достучаться до вашей локальной машины, поэтому запрос естественно не доставляется. При локальной разработке это самая частая ошибка.

2. Принимающая сторона не возвращает 2xx

Обработчик выбрасывает исключение, возвращает редирект 3xx, блокируется middleware аутентификации как 401/403 или возвращает 5xx. HiAPI считает успешной доставкой только HTTP 2xx, всё остальное переходит в повторы, а после исчерпания окна повторов проявляется как «не получаем».

3. Таймаут обработки

Обработчик сначала выполняет тяжёлые операции (скачивание артефактов, сохранение в объектное хранилище, запись в БД, отправка сообщений), а затем возвращает 200; слишком долго — фиксируется таймаут и запускаются повторы, при накоплении которых кажется, что запросы теряются.

4. callback помещён внутрь input

Это поле верхнего уровня; помещённое в input, оно не будет распознано как регистрация callback. Кроме того, input каждого модели — строгая схема, лишний неизвестный ключ обычно вызывает синхронную ошибку при отправке invalid input: <root>: additional properties 'callback' not allowed, и задача вообще не будет успешно отправлена.

5. В when указано значение, отличное от final

В настоящее время поддерживается только final, другие значения будут отклонены.

6. Опрос и callback опережают друг друга

Включены и опрос, и ожидание callback; опрос первым получает терминальное состояние и удаляет локальную запись задачи, а когда приходит callback, соответствующая запись не находится и считается «не полученным».

7. Блокировка сертификатом или WAF

Адрес callback использует самоподписанный / просроченный сертификат, или WAF блокирует анонимный POST без обычного UA и без ваших собственных заголовков аутентификации как подозрительный трафик.

Шаги исправления

  1. Сначала убедитесь, что сама задача в порядке. Проверьте data.status через GET /v1/tasks/{taskId}: если success/fail — задача в терминальном состоянии, и проблема в доставке; если всё ещё не терминальное — это другая проблема (см. диагностику зависания в начале).
  2. Замените адрес callback на публичный https-домен. С внешней машины выполните curl -i -X POST https://your-domain.com/hiapi/callback -d '{}', убедитесь, что соединение устанавливается и возвращается 2xx. Для отладки на localhost используйте публичный туннель для проброса локального порта наружу.
  3. Сначала надёжно зафиксируйте callback, затем быстро верните 2xx. При получении запроса сначала запишите содержимое callback в базу данных или постоянную очередь (этот шаг должен быть быстрым), и только после успешной записи верните 2xx; тяжёлые операции вроде скачивания и сохранения выполняйте асинхронно в фоне. Не возвращайте 200 до сохранения: если после этого процесс упадёт, этот callback потеряется, и HiAPI, получив 2xx, больше не будет повторять отправку. Также исключите этот путь из middleware аутентификации, так как callback от HiAPI не содержит ваших собственных заголовков аутентификации.
  4. Проверьте расположение и значения callback. Убедитесь, что оно на верхнем уровне тела запроса (на одном уровне с model и input), url — публичный http(s), when — final.
  5. Выполняйте идемпотентную дедупликацию по taskId. При получении callback сначала проверьте локально, не обработан ли уже этот taskId, и только если нет — сохраняйте / запускайте дальнейшие действия; при семантике at-least-once повторное поступление нормально, не отбрасывайте дубликаты как аномалию.
  6. Добавьте резервный опрос. Для taskId, по которым callback не пришёл дольше ожидаемого времени, активно запрашивайте терминальное состояние через GET /v1/tasks/{taskId}. Callback — это оптимизация, опрос — базовая гарантия; сведите оба к единой логике идемпотентности.
  7. Сразу сохраняйте артефакты. В теле callback output[].url — временная ссылка (storage равен temp, expireAt — Unix-время, истекает примерно через 7 дней); сразу после получения скачайте или сохраните в собственное хранилище, не сохраняйте горячую ссылку напрямую.

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

Сначала не трогая callback, докажите, что ваш ключ и подключение в порядке, через «отправку + опрос» (используя голый id модели):

# 1. Отправка задачи
curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-image-2","input":{"prompt":"a calm blue data center"}}'
# → {"code":200,"message":"success","data":{"taskId":"tk-hiapi-..."}}

# 2. Опрос терминального состояния по возвращённому taskId
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-xxxx \
  -H "Authorization: Bearer $HIAPI_API_KEY"
# → data.status переходит из queued/handling/archiving в success (с output) или fail (с error)

Если при отправке возвращается HTTP 401 + {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}}, значит API key неверный — сверьте в консоли и повторите. После подтверждения работоспособности подключения добавьте в тело POST поле верхнего уровня callback и проверьте принимающую сторону по пунктам шагов исправления.

FAQ

Callback не приходит, но задача на самом деле успешна — можно ли получить результат? Да. В любой момент можно прочитать data.status и data.output через GET /v1/tasks/{taskId}; потеря callback не мешает вам активно получить результат.

Сколько раз повторяется callback и с каким интервалом? При не 2xx / таймауте / сетевой ошибке повторная отправка выполняется по схеме сразу → +1 минута → +5 минут → +20 минут, максимум 4 раза. После 4 неудач повторы прекращаются, и это не влияет на собственный статус success/fail задачи.

Нормально ли получить два callback по одной задаче? Нормально. Callback о терминальном состоянии имеет семантику «минимум одного раза», достаточно идемпотентной дедупликации по taskId; не считайте повторную доставку ошибкой.

Как принимать callback при локальной разработке? HiAPI не может достучаться до localhost и внутренних адресов. Либо используйте публичный туннель для проброса локального порта в публичную сеть, либо на локальном этапе переключитесь на опрос, а callback подключите после выхода в продакшн.

Какие поля есть в теле запроса callback? Полностью совпадает с data из GET /v1/tasks/{taskId}, содержит taskId, status, output (массив артефактов при успехе), error (code и message при неудаче), created, completed и т. д. Подробнее в документации по деталям задачи.

Будет ли списано больше средств, если callback не приходит? Нет. За неудачную задачу средства не списываются, зарезервированный лимит возвращается; успешность доставки callback также не влияет на результат тарификации задачи — тарификация зависит только от того, успешно ли в итоге сгенерирована задача.

Похожие статьи

Все статьи →

Начните работать с постоянными артефактами ИИ

Получите API-ключ и вызывайте модели изображений, видео и аудио через один API на основе tasks.

Читать документацию API