PopNowДокументация API
Справочник
Основное содержимое

Ошибки

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

Если вызов не удался, ответ содержит число (code), которое говорит, что это за проблема, и фразу (msg) для человека. Ветвитесь по числу, а фразу показывайте или пишите в лог.

Обёртка ответа

{ "code": 40201, "msg": "Insufficient balance", "request_id": "req_…" }
  • code — бизнес-код. 200 означает успех, всё остальное перечислено ниже.
  • При ошибке поля data нет — кроме нескольких ошибок библиотеки ассетов, которые добавляют data.reason.
  • HTTP-статус тоже выставляется корректно (40201 приходит с HTTP 402). Ветвитесь по чему-то одному, не смешивая; мы советуем более точный code.
  • request_id дублируется в заголовке X-Request-Id. Указывайте его при обращении в поддержку.

Если ответ вообще не JSON — например, HTML или текстовая страница от промежуточной сети, — обрабатывайте его по HTTP-статусу и пишите в лог начало тела.

Язык сообщений об ошибках

msg и errorMessage упавшей задачи по умолчанию на английском. Отправьте Accept-Language со значением en, ja, ko, de, fr, es, pt-BR, ru, it или pl либо выберите язык ошибок API в консоли — и получите их на этом языке; для остальных языков вернётся английский. В ответах с ошибкой есть заголовок Content-Language. Коды от языка не зависят — ещё одна причина никогда не разбирать msg.

Если модель сообщила конкретную причину сбоя (например, нечитаемое референсное изображение), errorMessage передаёт её на английском, без внутренних подробностей.

Общие коды

codeHTTPЗначениеПовторять?
200200 / 202Успех—
400400Запрос или его input некорректны; msg называет проблемуНет — исправьте
40003400Загруженный файл не совпадает со своим тикетом (размер, тип или содержимое)Нет — новый тикет, новая загрузка
40004400Запрос корректен, но модель сейчас не может выполнить такое сочетание настроекНет — измените настройку, названную в msg
401401Ключа нет, он неизвестен или отозван (подробнее)Нет
403403Нет доступа (см. Права)Нет
404404Не существует или принадлежит другому ключуНет
409409Конфликт с текущим состоянием (когда повторять)Иногда
40901409Расчёт цены устарел или цена измениласьЗапросите расчёт заново
413413Тело запроса слишком большоеНет — загружайте файлы, а не встраивайте их
429429Слишком много запросовДа — после Retry-After
500500Что-то сломалось у насДа — с растущей паузой
503503Вспомогательный сервис ненадолго недоступенДа — после Retry-After

Баланс и лимиты

codeHTTPЗначениеЧто делать
40201402Не хватает кредитов на резерв для этой задачиКупите кредиты и отправьте снова
40202402Достигнут лимит расходов ключаПоднимите лимит в API-консоли или дождитесь сброса

Права

codeHTTPЗначениеЧто делать
40301403Этому ключу нельзя вызывать эту модельДобавьте модель в список разрешённых для ключа
40302403Запрос пришёл с адреса вне белого списка IP ключаДобавьте адрес или снимите ограничение
40303403В этом регионе сервис не предоставляетсяОбойти нельзя
40310403Адрес почты аккаунта ещё не подтверждёнОткройте ссылку из письма о регистрации; ключ заработает сразу после подтверждения

Простой 403 при действующем ключе означает, что аккаунт сейчас не может пользоваться API; напишите в поддержку и приложите request_id.

Доступность моделей

codeHTTPЗначениеПовторять?
50301503Модель сейчас не принимает задачиДа, позже — или выберите другую модель
40004400Модель работает, но не с такими настройкамиНет — измените настройку

Ни один из этих кодов не создаёт задачу и не резервирует кредиты.

Коды сбоя задач

У принятой, но затем упавшей задачи state: "failed", а в errorCode — одно из значений ниже. Список закрыт: любое другое значение обрабатывайте как upstream_failed.

errorCodeЗначениеПовторять?
invalid_requestМодель не приняла параметрыНет — исправьте их
unsupported_combinationТакое сочетание настроек сейчас не поддерживаетсяНет — измените настройку
content_rejectedМодель отклонила этот контентНет — измените промпт или референс
invalid_assetРеференсный файл не удалось прочитать или он больше недоступенЗагрузите заново и создайте новую задачу
rate_limitedСервис генерации был перегруженДа, с растущей паузой
upstream_unavailableГенерация временно недоступнаДа, чуть позже
generation_failedГенерация прошла, но ничего не выдалаВозможно — тот же вход часто падает так же
timeoutУ задачи кончилось времяВозможно — попробуйте короче или в меньшем разрешении
upstream_failedВсё остальноеДа, с растущей паузой

Упавшая задача освобождает резерв, поэтому ничего не стоит (несколько моделей берут плату за отказ по содержанию и пишут об этом на своей странице). errorMessage объясняет причину словами; ветвитесь только по errorCode.

Когда стоит повторять 409

СлучайПовторять?
Два запроса с одним Idempotency-Key пришли одновременноДа, с тем же ключом после короткой паузы
Idempotency-Key уже использован для другого запроса или другим ключомНет
Загрузка или результат ещё обрабатываютсяДа, через несколько секунд
jobs/retry для задачи, которая ещё не завершиласьДа, когда она станет конечной
jobs/retry для успешной задачиНет — создайте новую задачу
Тикет загрузки или загруженный файл истёкНет — загрузите заново

Как писать повтор

Повторяйте только то, что может получиться со второй попытки, ждите Retry-After, если он есть, а иначе увеличивайте паузу экспоненциально:

JavaScript
const RETRYABLE = new Set([429, 500, 503, 50301]);

async function call(path, init, attempts = 4) {
  for (let i = 0; i < attempts; i++) {
    const res = await fetch(`https://api.popnow.ai/api/v1${path}`, init);
    if (!res.headers.get('content-type')?.includes('json')) {
      throw new Error(`HTTP ${res.status}: ${(await res.text()).slice(0, 200)}`);
    }
    const body = await res.json();
    if (body.code === 200) return body.data;
    if (!RETRYABLE.has(body.code)) throw new Error(`${body.code} ${body.msg} (${body.request_id})`);
    const wait = Number(res.headers.get('retry-after')) * 1000 || 2 ** i * 1000 + Math.random() * 500;
    await new Promise((r) => setTimeout(r, wait));
  }
  throw new Error('out of retries');
}
Python
import random, time, requests

RETRYABLE = {429, 500, 503, 50301}

def call(method, path, attempts=4, **kwargs):
    for i in range(attempts):
        res = requests.request(method, f"https://api.popnow.ai/api/v1{path}", timeout=60, **kwargs)
        try:
            body = res.json()
        except ValueError:
            raise RuntimeError(f"HTTP {res.status_code}: {res.text[:200]}")
        if body["code"] == 200:
            return body["data"]
        if body["code"] not in RETRYABLE:
            raise RuntimeError(f'{body["code"]} {body["msg"]} ({body.get("request_id")})')
        retry_after = res.headers.get("retry-after")
        time.sleep(float(retry_after) if retry_after else 2**i + random.random() / 2)
    raise RuntimeError("out of retries")

Повторяя createTask, всегда отправляйте тот же Idempotency-Key, чтобы запрос, который на самом деле прошёл, не выполнился и не списался дважды.

Отладка

  1. Запишите request_id и code.
  2. Найдите задачу в логах API-консоли по ID задачи или request_id.
  3. Не помогло? Напишите в поддержку: request_id, время (UTC) и code. Никогда не отправляйте свой API-ключ.

На этой странице