Ошибки
Все коды API, их HTTP-статусы, необходимые действия и случаи, когда повтор запроса имеет смысл.
При ошибке вызова ответ сообщает две вещи: число (code), определяющее тип проблемы, и предложение (msg), предназначенное для человека. Эта страница перечисляет все числа, их смысл и возможность повторной попытки. Если нужен быстрый способ устранить конкретный симптом, начните с Устранение неполадок.
Общий формат
JSON-ответы нативного API задач используют этот формат: одинаковые четыре поля вокруг каждого ответа. Совместимые ответы /v1 и SSE разбирайте по правилам их протоколов:
{ "code": 200, "msg": "success", "data": { }, "request_id": "req_…" }code— код API, а не HTTP-статус.200означает успех.- При ошибке
dataотсутствует (не равенnull): вы получаетеcode,msgиrequest_id. Единственное исключение: часть ошибок библиотеки ассетов добавляетdata.reason. msgпредназначен для человека: формулировка и язык могут меняться (см. ниже). Не используйте его для выбора ветви обработки; используйтеcode.request_idтакже возвращается в заголовкеX-Request-Id. Указывайте его при сообщении о проблеме.
HTTP-статус тоже корректен. Можно использовать любой из двух, но только один: конкретные коды различаются (недостаточный баланс — code: 40201 с HTTP 402), а смешение рано или поздно приводит к пропуску случая.
Рекомендуем обрабатывать code. 404 сообщает лишь об отсутствии объекта, а 40201 — о недостаточном доступном балансе.
Не каждый ответ — JSON
Если ответ не разбирается как JSON, например это текст или HTML от нашей пограничной сети, поля code нет. Обрабатывайте HTTP-статус, записывайте начало тела и не повторяйте 403 вслепую: региональную блокировку повторы не устранят.
Язык сообщений об ошибках
Понятный человеку текст ошибки может возвращаться на выбранном вами языке. По умолчанию используется английский. Выбор языка влияет только на три места:
msgв общем формате ответа;errorMessageнеудавшейся задачи вrecordInfoи обратных вызовах вебхуков (с одним исключением ниже);error.messageв объектах ошибок совместимых эндпоинтов OpenAI, Anthropic и Google Gemini (/v1beta).
Поддерживаемые коды языков: en, ja, ko, de, fr, es, pt-BR, ru, it, pl.
Исключение: если сама модель сообщила конкретную причину ошибки, например нечитаемое референсное изображение или ограничение авторских прав для аудио, errorMessage передаёт эту причину на английском. Внутренние сведения — названия сервисов, хосты, URL и ID запросов — удаляются, но вы видите реальную причину. Причины, упоминающие состояние аккаунта или оплаты, никогда не передаются напрямую; вместо них вы получаете наше сообщение. Content-Language по-прежнему описывает msg, а для обработки всегда используется errorCode.
Выбор языка
Применяется первый подходящий вариант:
- Заголовок запроса
Accept-Language— только для этого запроса. Используется стандартный приоритет HTTP: выбирается распознанный язык с наибольшимq. Региональные варианты сводятся к языку:de-DEсчитаетсяde, аpt-PT—pt-BR. Китайский не предлагается, поэтому его теги не совпадают ни с одним языком и проверяется следующий кандидат.*означает отсутствие предпочтения. - Настройка аккаунта в разделе Настройки → Язык ошибок API консоли. Она применяется ко всем запросам с API-ключами аккаунта, у которых нет распознанного
Accept-Language. Большинство серверных SDK и curl по умолчанию не передают этот заголовок, поэтому на настройку опирается большинство интеграций. У обратных вызовов вебхуков нет заголовка исходного запроса, поэтому они всегда следуют настройке аккаунта. - Иначе — английский.
Ответы с ошибками содержат заголовок Content-Language с фактическим языком сообщения.
Меняется только текст для человека
code, errorCode, совместимые с OpenAI type и code, совместимые с Gemini code и status, а также все имена полей одинаковы для любого языка. Обрабатывайте коды, не разбирая формулировку; записывайте code и request_id в логи и уведомления.
Пример
Та же ошибка 40201 (недостаточный баланс) по умолчанию возвращается на английском:
HTTP/1.1 402 Payment Required
Content-Language: en
{ "code": 40201, "msg": "Insufficient balance", "request_id": "req_…" }Добавьте один заголовок Accept-Language: ja; остальное — тот же вызов создания задачи из быстрого старта:
curl -X POST https://api.spicyapi.ai/api/v1/jobs/createTask \
-H "Authorization: Bearer $SPICY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $SPICY_IDEMPOTENCY_KEY" \
-H "Accept-Language: ja" \
--data "$TASK_PAYLOAD"Теперь msg на японском; code по-прежнему 40201:
HTTP/1.1 402 Payment Required
Content-Language: ja
{ "code": 40201, "msg": "残高が不足しています", "request_id": "req_…" }Общие коды
code | HTTP | Значение | Повторять? |
|---|---|---|---|
200 | 200 | Успех | — |
400 | 400 | Неверный формат запроса или параметры | Нет. Исправьте и отправьте снова |
40003 | 400 | Размер, тип или содержимое загруженного файла не совпадает с заявленным при запросе URL загрузки | Нет. Запросите новый URL с правильными contentType и размером, загрузите снова и подтвердите |
40004 | 400 | Запрос корректен, но сейчас модель не может выполнить эту комбинацию настроек | Нет. Измените настройку из msg (например, разрешение или соотношение сторон) либо выберите другую модель. См. ниже |
401 | 401 | Ошибка аутентификации; msg указывает один из трёх вариантов | Нет. Исправьте заголовок или ключ |
403 | 403 | Нет разрешения. При вызове с действительным ключом ограничен аккаунт — см. ниже. Неподтверждённая почта вместо этого возвращает 40310 | Нет |
404 | 404 | Объект не существует или не принадлежит вам | Нет |
409 | 409 | Конфликт с текущим состоянием | Иногда — см. ниже |
40901 | 409 | Расчёт цены просрочен, запрос или цена изменились | Рассчитайте и подтвердите снова; восстанавливайте принятые запросы с исходным ключом идемпотентности |
413 | 413 | Тело запроса превышает допустимый сервером размер | Нет. Уменьшите тело или загрузите медиафайлы через процесс загрузки |
429 | 429 | Слишком много запросов | Обычно да. Выдержите паузу по Retry-After. Один вариант 429 не связан со скоростью — см. Ограничения частоты запросов |
500 | 500 | Сбой на нашей стороне | Да. Выдержите паузу и повторите |
503 | 503 | Вспомогательный сервис (расчёт цены, сохранение изображений из запроса, загрузка медиафайлов) временно недоступен | Да. Дождитесь Retry-After, если есть, и повторите; для createTask — с тем же Idempotency-Key. Если ошибка сохраняется без Retry-After, следуйте msg (например, используйте публичный URL HTTPS вместо изображения в запросе) |
503 и 50301 имеют общий HTTP-статус, но разные коды API: 503 относится к вспомогательному сервису, 50301 — к самой модели.
Как различать три ошибки 401
Три совершенно разные ошибки возвращают 401 при аутентификации и требуют разных исправлений. Во всех случаях code остаётся 401; различие показывает msg.
msg (английский) | Что произошло | Что изменить |
|---|---|---|
Missing credentials: send your API key in the Authorization header as "Bearer sk-spicy-..." (на совместимых /v1 и /v1beta: …as "Authorization: Bearer sk-spicy-...", x-api-key, or x-goog-api-key) | Запрос пришёл вообще без учётных данных | Клиент теряет заголовок. Проверьте перехватчик, прокси и загрузку переменной окружения в выполняющий запрос процесс |
API key format is not recognized: keys begin with sk-spicy- | Учётные данные пришли, но это не наш ключ | Вы вставили значение сессии консоли или ключ другого сервиса. Ключи SpicyAPI начинаются с sk-spicy-; echo "${SPICY_API_KEY:0:9}" должен вывести именно этот префикс |
Credentials are invalid or expired | Ключ имеет наш формат, но не существует, отозван или просрочен | Проверьте на странице API-ключей; если отозван или просрочен, создайте замену. Повторы никогда не превратят ошибку в 200 |
Второй случай определяется без обращения к базе данных. Поэтому он сообщает то, чего третий не сообщает: такая строка изначально не могла работать. Третье сообщение намеренно одинаково для несуществующих, отозванных и просроченных ключей, чтобы ответ не позволял проверять существование конкретных ключей.
Здесь строки показаны на английском; msg следует выбору языка выше, а формулировка не является контрактом. Обрабатывайте code, а сообщение читайте, показывайте или записывайте в лог — не сравнивайте его с фиксированной строкой.
Аккаунт не может вызывать API
В обоих случаях ключ действителен; вызовы пока недоступны самому аккаунту.
40310 означает, что адрес электронной почты не подтверждён. Сообщение: Verify your account email to run models and call the API…:
- Откройте консоль. Баннер вверху сообщает о неподтверждённой почте и позволяет отправить письмо снова.
- Нажмите ссылку в письме подтверждения (проверьте спам).
- Повторите тот же вызов. Новый ключ не нужен.
Пока API заблокирован, консоль продолжает работать, и история остаётся доступной.
Обычный 403 с This account cannot call the API right now означает ограничение аккаунта. Обратитесь в поддержку с request_id.
Баланс и лимиты
code | HTTP | Значение | Что делать |
|---|---|---|---|
40201 | 402 | Баланс не покрывает оценочную стоимость | Пополните в разделе Оплата консоли — см. Настройка аккаунта. Проверьте GET /api/v1/chat/credit |
40202 | 402 | Достигнут лимит расходов | Прочитайте msg, чтобы определить его. Лимит ключа (This key has reached its …): повысьте на странице API-ключей или дождитесь обновления. Лимит команды (Workspace … budget has been reached): попросите владельца, администратора или управляющего бюджетом повысить его на странице команды. Лимит платформы (Platform quota for today is exhausted…): его изменить нельзя; повторите после 00:00 UTC. Дневные лимиты обновляются в 00:00 UTC, месячные — 1-го числа в 00:00 UTC, общий за всё время не сбрасывается |
Повторять оба случая бессмысленно: повторный запрос не меняет баланс или лимиты. См. Лимиты расходов.
Разрешения
code | HTTP | Значение | Что делать |
|---|---|---|---|
40301 | 403 | Ключу не разрешена эта модель | Расширьте список разрешённых моделей ключа в консоли |
40302 | 403 | Адрес источника отсутствует в списке разрешённых IP-адресов ключа | Добавьте его или уберите IP-ограничение ключа |
40303 | 403 | Сервис не предлагается в этом регионе | Обойти ограничение нельзя. См. Где мы работаем |
40310 | 403 | Почта аккаунта ещё не подтверждена, поэтому запуск моделей недоступен | Откройте ссылку из письма регистрации или отправьте новое письмо из консоли. После подтверждения ключ заработает без изменений с вашей стороны |
Ни один из этих случаев не исправляется повтором.
Коды причин библиотеки ассетов
Ошибки на эндпоинтах библиотеки ассетов (/api/v1/assets…) могут добавлять в обычную оболочку одно машиночитаемое поле data.reason:
{ "code": 400, "msg": "…", "data": { "reason": "asset_library_locked" }, "request_id": "req_…" }code, HTTP-статус, msg и errorCode задачи одинаковы с причиной и без неё, поэтому существующая обработка продолжает работать. Причина появляется только на эндпоинтах библиотеки ассетов, но не на других нативных эндпоинтах, а OpenAI-совместимый и другие слои совместимости сохраняют свои форматы ошибок. Список может расти: неизвестное значение обрабатывайте как отсутствие причины.
data.reason | HTTP | Значение | Что делать |
|---|---|---|---|
asset_library_locked | 400 | Библиотека ассетов открывается после первого пополнения | Пополните баланс. Уже сохранённые ассеты остаются доступными |
asset_library_full | 400 | Лимит хранилища (по числу или объёму) исчерпан | Удалите ассеты или перейдите на тариф выше; следующий показывает GET /api/v1/assets/usage |
asset_file_too_large | 400 | Файл превышает лимит тарифа на один файл | Используйте файл меньше или перейдите на тариф выше |
asset_daily_limit | 429 | Достигнут суточный лимит новых ассетов | Подождите до 00:00 UTC и соблюдайте Retry-After |
asset_storage_full | 503 | Хранилище всей платформы заполнено | Повторите запрос позже |
asset_permission_denied | 403 | Ваша роль в команде не допускает это изменение | Обратитесь к владельцу или администратору команды либо используйте ключ, создатель которого имеет подходящую роль |
asset_workspace_forbidden | 403 | Этот ключ не открывает эту библиотеку, например потому, что участник, создавший командный ключ, покинул команду | Создайте новый ключ в нужном рабочем пространстве |
asset_entity_name_taken | 409 | В библиотеке уже есть персонаж с таким именем (без учёта регистра). Персонажей именуют на странице Assets веб-приложения, поэтому API, который пока только читает, этого не возвращает | Выберите другое имя |
Доступность моделей
code | HTTP | Значение | Повторять? |
|---|---|---|---|
50301 | 503 | Модель сейчас недоступна | Да. Повторите позже или выберите другую модель |
50302 | 503 | Текстовый запрос (потоковый или обычный) завершился ошибкой модели до выдачи ответа; резерв возвращён | Да. Отправьте снова с новым Idempotency-Key |
40004 | 400 | Модель работает, но не с этими настройками | Нет. Измените настройку из msg |
50301 означает, что модель не могла принять задачу в момент отправки: она не предлагается, не имеет активной цены или доступных сейчас ресурсов генерации. Временная нехватка ресурсов может разрешиться при ограниченном числе повторов. Недоступность модели или отсутствие цены повторные запросы не исправят. Обновите каталог и получите подтверждение пользователя до смены модели.
40004 и 50301 намеренно различаются. 50301 означает, что модель сейчас вообще не принимает задачи; ожидание может помочь. 40004 означает, что модель работает, но не обслуживает это сочетание настроек. Поле msg называет настройку в скобках, например This model cannot serve this parameter combination right now (…). Ожидание не поможет; изменение значения — поможет. Ни один из случаев не создаёт задачу и не резервирует деньги.
Ошибка генерации после принятия появляется как state: failed
Ошибка генерации после получения ID от createTask появляется в recordInfo как state: "failed" с errorCode / errorMessage. Резерв обычно освобождается полностью, кроме определённых отказов по содержанию, явно указанных как платные на странице модели. Ситуация, соответствующая 40004, но обнаруженная после принятия, появляется как errorCode: "unsupported_combination". Не добавляйте синхронные коды API, которых нет на этой странице.
Коды ошибки задачи
Ошибка после принятия задачи приходит в errorCode на recordInfo. Набор закрытый: внутренняя диагностика сюда не попадает, поэтому любое значение вне списка обрабатывайте как upstream_failed.
errorCode | Значение | Повторять? |
|---|---|---|
invalid_request | Параметры не приняты | Нет. Исправьте и отправьте снова |
unsupported_combination | Сочетание сейчас не поддерживается | Нет. Выберите другие настройки |
content_rejected | Выбранная модель отклонила контент. SpicyAPI сам не проверяет запросы — см. Ответственность за контент и использование | Нет. Измените промпт или выберите другую модель |
rate_limited | Сервис генерации занят | Да. Выдержите паузу и повторите |
upstream_unavailable | Генерация временно недоступна | Да. Повторите вскоре |
invalid_asset | Референсный файл больше недоступен | Не через повтор задачи. retry использует исходные входные данные, поэтому загрузите файл заново и создайте новую задачу с новым URI |
generation_failed | Генерация началась, но ничего не создала | Возможно. Те же входные данные обычно дают ту же ошибку |
timeout | Задача не завершилась до крайнего срока | Возможно. Попробуйте меньшую длительность или разрешение |
upstream_failed | Все прочие случаи | Да. Выдержите паузу и повторите |
Неудавшиеся или просроченные задачи обычно освобождают весь резерв. Некоторые отказы по содержанию оплачиваются по принятому расчёту только если страница модели явно раскрывает это исключение. Проверяйте settled и cost для итогового списания. Поле errorMessage предназначено для человека: оно объясняет причину текстом, может передавать причину самой модели на английском (см. выше), а формулировка меняется. Обрабатывайте только errorCode. «Повтор» здесь означает отправку новой задачи, которая снова оплачивается при успехе.
Какие ошибки стоят денег
Состояние задачи и состояние соединения — разные факты
Явно отклонённое создание, просроченные задачи и исторические отменённые записи не оплачиваются за генерацию. Неудавшиеся задачи обычно не оплачиваются, кроме определённых отказов по содержанию, явно раскрытых как платные на странице модели. Тайм-аут или отключение клиента — не ошибка задачи. Принятые задачи нельзя отменить: восстановите исходную задачу и проверьте её конечное состояние и расчёт. Отключённый текстовый поток может оплачиваться, если корректные данные об использовании уже записаны.
| Ситуация | Оплачивается? |
|---|---|
API явно отклоняет createTask, не создавая задачу (например, 40201, 40202, 40004 или 50301) | Нет. Создание и резерв используют одну транзакцию; ошибка шлюза или отсутствие ответа не доказывают отказ |
| Отправка завершилась тайм-аутом, вкладка закрылась или соединение оборвалось | Пока неизвестно. Восстановите факт принятия исходным ключом идемпотентности; не считайте это бесплатным повтором |
createTask возвращает 202, а позже задача — failed / expired | Обычно не оплачивается. Некоторые результаты failed / content_rejected оплачиваются по принятому расчёту при явном указании на странице модели. Прочитайте settled и cost |
Историческая задача — canceled | Нет. Это состояние совместимости, а не доступное сейчас действие |
createTask возвращает 202, задача — succeeded | Да, по фактическому использованию, не выше принятого резерва. Остаток освобождается; позднее ничего сверх резерва не списывается |
Любая ошибка recordInfo, chat/credit или common/* | Нет. Эти эндпоинты никогда не оплачиваются |
Ограничение частоты (429) или дедупликация ключом идемпотентности | Нет. Первый запрос не был принят; второй возвращает исходную задачу, оплаченную один раз |
Расчёт или освобождение завершаются автоматически, в том числе после прерывания процесса. Обычные ошибки освобождают весь резерв; определённые отказы по содержанию, явно раскрытые на странице модели, оплачиваются по принятому расчёту. Проверьте расчёт задачи и баланс, чтобы подтвердить результат — см. Оплата.
Когда имеет смысл повторять 409
| Случай | Повторять? |
|---|---|
Редкий конфликт одновременных createTask с тем же ключом и неизменным телом | Да. Подождите несколько сотен миллисекунд и повторите с тем же ключом. См. Идемпотентность |
| Ключ уже использован с другим телом или API-ключом | Нет. Остановитесь и исправьте принадлежность ключа; повторы не меняют конфликт |
Изображения из запроса или подтверждение загрузки ещё обрабатываются (может быть Retry-After) | Да. Дождитесь Retry-After или пары секунд и отправьте снова с тем же Idempotency-Key |
| Цены или конфигурация аккаунта изменились во время запроса | Да. Получите новый расчёт, если используете расчёты цены, затем отправьте снова |
| Файл результата ещё копируется | Да. Подождите несколько секунд и снова запросите ссылку скачивания |
jobs/retry для незавершённой задачи или задачи с незавершённым расчётом | Да, позже. Дождитесь конечного состояния исходной задачи и settled, равного true, затем повторите |
jobs/retry для успешной задачи или задачи с уже удалёнными по сроку входными данными | Нет. Создайте новую задачу через createTask |
| URL загрузки или загруженный файл просрочены | Нет. Загрузите файл снова |
Реализация повторов
Не повторяйте вслепую
400, 401, 40004, 40201 и подобные ошибки входных данных или авторизации дают тот же ответ при любом числе попыток. Каждый вариант с пометкой «Нет» выше — бесполезная работа, которая расходует ваш лимит запросов.
Экспоненциальное увеличение паузы со случайной добавкой не даёт пакету неудавшихся запросов одновременно повториться:
// 409 is operation-specific and must be handled at the call site.
const RETRYABLE = new Set([429, 500, 503, 50301]);
async function callWithRetry(path, init, { attempts = 4 } = {}) {
for (let i = 0; i < attempts; i++) {
const res = await fetch(`https://api.spicyapi.ai/api/v1${path}`, init);
// A page from the edge network is not our JSON envelope
if (!res.headers.get('content-type')?.includes('json')) {
const text = await res.text();
throw new Error(`HTTP ${res.status}, not JSON: ${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} (request_id=${body.request_id})`);
}
// When the server says how long to wait, trust it
const retryAfter = Number(res.headers.get('retry-after'));
const backoff = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: 2 ** i * 1000 + Math.random() * 500;
await new Promise((r) => setTimeout(r, backoff));
}
throw new Error('out of retries');
}import random, time, requests
# 409 is operation-specific and must be handled at the call site.
RETRYABLE = {429, 500, 503, 50301}
BASE = "https://api.spicyapi.ai/api/v1"
def call_with_retry(method: str, path: str, attempts: int = 4, **kwargs) -> dict:
for i in range(attempts):
res = requests.request(method, f"{BASE}{path}", **kwargs)
# A page from the edge network is not our JSON envelope
try:
body = res.json()
except ValueError:
raise RuntimeError(f"HTTP {res.status_code}, not JSON: {res.text[:200]}")
if body["code"] == 200:
return body["data"]
if body["code"] not in RETRYABLE:
raise RuntimeError(f'{body["code"]} {body["msg"]} (request_id={body.get("request_id")})')
# When the server says how long to wait, trust it
retry_after = res.headers.get("retry-after")
backoff = float(retry_after) if retry_after else 2**i + random.random() * 0.5
time.sleep(backoff)
raise RuntimeError("out of retries")package main
import (
"encoding/json"
"fmt"
"io"
"math/rand"
"net/http"
"strconv"
"time"
)
// retryable lists the codes worth another attempt. Anything else returns
// the same answer however many times you ask — and each ask eats your own
// rate limit.
// Whether the generation itself failed is read from recordInfo's state.
var retryable = map[int]bool{429: true, 500: true, 503: true, 50301: true}
type envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data json.RawMessage `json:"data"`
RequestID string `json:"request_id"`
}
func callWithRetry(newReq func() (*http.Request, error), attempts int, out any) error {
for i := 0; i < attempts; i++ {
req, err := newReq()
if err != nil {
return err
}
res, err := http.DefaultClient.Do(req)
if err != nil {
// Transport-level failure: the request may well have arrived.
// On createTask, send the same Idempotency-Key or this retry
// turns into a second generation and a second charge.
time.Sleep(backoff(i, ""))
continue
}
var env envelope
decErr := json.NewDecoder(res.Body).Decode(&env)
io.Copy(io.Discard, res.Body)
res.Body.Close()
if decErr != nil {
// Not our JSON envelope, for example a page from the edge network.
return fmt.Errorf("HTTP %d, response is not JSON: %w", res.StatusCode, decErr)
}
if env.Code == 200 {
return json.Unmarshal(env.Data, out)
}
if !retryable[env.Code] {
return fmt.Errorf("%d %s (request_id=%s)", env.Code, env.Msg, env.RequestID)
}
// When the server says how long to wait, trust it
time.Sleep(backoff(i, res.Header.Get("Retry-After")))
}
return fmt.Errorf("out of retries")
}
// backoff trusts Retry-After when present, otherwise backs off
// exponentially with jitter so a batch of failures does not come back
// as one thundering herd.
func backoff(attempt int, retryAfter string) time.Duration {
if s, err := strconv.Atoi(retryAfter); err == nil && s > 0 {
return time.Duration(s) * time.Second
}
base := time.Duration(1<<attempt) * time.Second
return base + time.Duration(rand.Intn(500))*time.Millisecond
}При повторе createTask всегда передавайте тот же Idempotency-Key, иначе успешный запрос с потерянным ответом превратится в двойную генерацию и двойную оплату.
Диагностика
Если ошибка непонятна, проверьте по порядку:
request_id— передайте его нам, чтобы найти точный запрос.code— таблицы выше.- Логи консоли — вставьте ID задачи или
request_idв поиск на странице Логи. Откроется задача: статус, стоимость, задержка, отправивший ключ, код ошибки и причина. Параметры и результаты показаны только пока хранятся, а в команде — только ролям с правом чтения содержимого.
Поле msg для 500 всегда общее: «сервис временно недоступен», без внутренних деталей. В ответах никогда не появляются внутренняя структура, имена компонентов или стеки вызовов. Их можно исследовать только через request_id.
Для связи откройте обращение в разделе Поддержка или напишите на support@spicyapi.ai. Приложите request_id или ID задачи, время (UTC) и code. Никогда не отправляйте API-ключ.
OpenAPI и указатель эндпоинтов
Контракт OpenAPI 3.1, все публичные эндпоинты и руководства, общие заголовки запросов и адрес производственного API.
Ограничения частоты запросов
Как работают отдельные лимиты чтения и записи, какие запросы их расходуют, с какими другими ограничениями можно столкнуться и почему число параллельных задач — отдельный вопрос.

