Ошибки и ответы
Какие коды возвращает API, как выглядит тело ошибки в разных разделах и что передавать в заголовках.
Коды ответов
| HTTP | Когда |
|---|---|
200 | Успех: чтение, изменение, удаление |
201 | Создана запись: ассистент, агент, версия, welcome-экран, файл знаний |
204 | Ответ на предварительный CORS-запрос OPTIONS |
400 | Тело с Content-Type: application/json не разбирается как JSON (invalid_json); запрос понятен, но действие невозможно, например выдать доступ владельцу |
401 | Нет ключа, ключ не того формата или не найден — Авторизация. Ключ отключённого аккаунта — не 401, а 403 {"success": false, "error": "Account disabled"} |
403 | Ключ отключённого аккаунта (Account disabled) или доступ к ассистенту есть, но действие запрещено: расшаренный пользователь пытается выдать доступ или убрать другого (Only the project owner can manage access) |
404 | Ассистент чужой или не существует; не найдена вложенная запись; нет такого адреса, в том числе нечисловой id ассистента в пути (/assistants/abc) в любом методе |
405 | Метод не поддерживается маршрутом, например GET на upload/image |
422 | Ошибка валидации, незнакомые поля в режиме strict, массив в строке запроса (invalid_query) |
500 | Внутренняя ошибка сервера |
502 | Платёжный шлюз не выполнил действие: отмена подписки, см. Подписчики, кредиты, платежи |
Заголовки запроса
| Заголовок | Когда нужен |
|---|---|
Authorization: Bearer user_… | Всегда, см. Авторизация |
Content-Type: application/json | Для тела в JSON (POST, PUT, PATCH) |
Content-Type: multipart/form-data | Для загрузки файлов, curl ставит его сам при -F |
Тело в JSON — в UTF-8. Ответы тоже в UTF-8, но не-ASCII символы в большинстве методов экранируются: "\u0414\u0443\u043c\u0430\u044e..." вместо "Думаю...". Любой JSON-парсер вернёт исходный текст.
Даты служебных полей (created_at, updated_at) — ISO 8601 в UTC: 2026-09-25T19:47:33.000000Z. Даты, которые задаёте вы (например version_date у версии), возвращаются так, как записаны: 2026-09-25 00:00:00.
Ответ всегда в JSON, заголовок Accept не нужен: ошибки валидации, неизвестный адрес, неверный метод и внутренняя ошибка тоже приходят JSON-объектом.
Битый JSON
Тело с Content-Type: application/json, которое не разбирается как JSON, отбивается до метода кодом 400, ничего не записывается:
curl -s -X PUT "$BASE/assistants/$ASSISTANT/bot" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"thinking_text":'
{ "success": false, "error": "invalid_json", "message": "Request body is not valid JSON: Syntax error" }
Пустое тело ошибкой не считается: это запрос без полей.
Формы тела ошибки
Любой ответ 4xx и 5xx под /api/v1 — JSON с "success": false. Общая форма ошибки — {"success": false, "error": "…"}, у ошибки валидации — {"success": false, "errors": {"поле": ["…"]}}, иногда ещё с message. Если метод сам не написал error и errors, error заполняется текстом из message, а без него — названием HTTP-статуса. Остальные поля тела сохраняются, поэтому у некоторых разделов в ошибке есть дополнительные ключи (messages, ignored, subscription).
До 26.09.2026 часть методов (доступ к ассистенту, вложенные записи, проверка ключа) отвечала без success. Теперь признак ошибки один для всех — success: false, но проверять HTTP-код по-прежнему надёжнее всего.
Неверный ключ
Личный ключ user_… и ключ ассистента site_… отбиваются в той же форме:
| Тело | Когда |
|---|---|
{"success": false, "error": "Invalid API token"} | Личный ключ не найден |
{"success": false, "error": "API token is required", "message": "…"} | Личного ключа нет в запросе |
{"success": false, "error": "Invalid API key", "message": "The provided API key is not valid"} | Ключ site_… не найден, чаты по ключу ассистента |
{"success": false, "error": "API key is required", "message": "…"} | Ключа site_… нет в запросе |
Нет доступа к ассистенту
Большинство методов ассистента: чужой и несуществующий ассистент неразличимы.
curl -s "$BASE/assistants/1" \
-H "Authorization: Bearer $KEY"
{ "success": false, "error": "Project not found or access denied" }
Так отвечают все методы ассистента, включая агентов и версии: правило доступа одно для всего API. Ключ администратора площадки не открывает чужих ассистентов ни в одном разделе.
Не найдена вложенная запись
Внутри доступного ассистента — свой текст на каждый тип записи, например:
| Тело | Где |
|---|---|
{"success": false, "error": "Agent not found"} | Изменение и удаление агента другого ассистента |
{"success": false, "error": "Agent not found or access denied"} | Коннекторы, секреты, база знаний агента |
{"success": false, "error": "Welcome screen not found"} | Первые экраны |
{"success": false, "error": "Ticket not found"} | Обращения |
{"success": false, "error": "User not found"} | Кредиты |
{"success": false, "error": "domain_not_found"} | Домены |
{"success": false, "error": "locale_not_found"} | Языки |
Ошибка валидации: поля и сообщения
Основная форма — объект errors, где ключ — поле, значение — список сообщений:
curl -s -X POST "$BASE/assistants/$ASSISTANT/versions" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"date": "не дата", "number": 123, "description": ["x"]}'
{
"success": false,
"errors": {
"number": ["The number field must be a string."],
"date": ["The date field must be a valid date."],
"description": ["The description field must be a string."]
}
}
Так же отвечают создание ассистента, агенты, большинство PUT настроек. У вложенных полей ключ — полный путь: config.tags, bot_locales.en.bot_gender, sidebar.agents_tag:
{
"success": false,
"errors": {
"label": ["The label field must be a string."],
"action": ["The selected action is invalid."]
}
}
Ошибка валидации: одна строка
Методы загрузки файлов отдают только первое сообщение строкой:
{ "success": false, "error": "The image field must be a file of type: jpeg, jpg, png, gif, webp, svg, mp4, webm." }
Ошибка валидации с общим сообщением
Несколько методов (языки ассистента, язык по умолчанию, начисление кредитов, переводы интерфейса, чаты по ключу ассистента) кроме errors отдают message с первым сообщением:
curl -s -X PATCH "$BASE/assistants/$ASSISTANT/default-locale" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{}'
{
"success": false,
"message": "The locale field is required.",
"errors": { "locale": ["The locale field is required."] }
}
Массив в строке запроса
Параметры строки запроса — только строки. ?locale[]=en отбивается до метода:
curl -s -g "$BASE/assistants/$ASSISTANT/templates?locale[]=en" \
-H "Authorization: Bearer $KEY"
{
"success": false,
"error": "invalid_query",
"message": "Query parameters must be strings: locale",
"errors": { "locale": ["The locale query parameter must be a string, not an array."] }
}
Незнакомые поля в режиме strict
Методы сохранения настроек (PUT на /bot, /onboarding, /features, /delay, /models, /paywall) принимают strict=true в теле или строке запроса. С ним незнакомое поле — ошибка, и ничего не записывается:
curl -s -X PUT "$BASE/assistants/$ASSISTANT/features?strict=true" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"capability_bogus": true}'
{
"success": false,
"error": "unknown_fields",
"message": "Unknown fields: capability_bogus",
"ignored": ["capability_bogus"]
}
Без strict тот же запрос вернёт 200 с "ignored": ["capability_bogus"] и полем warning.
Партнёрская программа
Методы партнёрской программы отдают сообщения валидации в поле messages:
{ "success": false, "error": "Validation failed", "messages": { "partner_percent": ["The partner percent field must not be greater than 100."] } }
Действие невозможно
{ "success": false, "error": "User is the project owner" }
Код 400: например, попытка выдать доступ к ассистенту его же владельцу.
Неизвестный адрес, неверный метод, внутренняя ошибка
Текст ошибки приходит и в error, и в message:
curl -s "$BASE/assistants/abc/bot" \
-H "Authorization: Bearer $KEY"
{
"success": false,
"error": "The route api/v1/assistants/abc/bot could not be found.",
"message": "The route api/v1/assistants/abc/bot could not be found."
}
Id ассистента, агента, подписчика и домена в пути — только число: /assistants/abc и /assistants/abc/agents — 404, как несуществующий адрес. Неверный метод — 405:
{
"success": false,
"error": "The GET method is not supported for route api/v1/assistants/53/upload/image. Supported methods: POST.",
"message": "The GET method is not supported for route api/v1/assistants/53/upload/image. Supported methods: POST."
}
Запись, которой нет вовсе (например, версия с несуществующим id), — 404 с тем же видом тела: "error": "No query results for model [App\\Models\\Version] 99999999". Так же отвечают методы агентов на несуществующий id ассистента: /assistants/999999/agents — No query results for model [App\\Models\\Project] 999999. Внутренняя ошибка — 500 с "error": "Server Error".
Частичные обновления
PUT в этом API работает как частичное обновление: меняются только переданные поля, остальные остаются как были. Передавать объект целиком не нужно.
| Что передали | Результат |
|---|---|
| Поле со значением | Записано |
| Поле не передано | Не тронуто |
Поле с null или "" | Для большинства полей — очищено. Поля с обязательным значением (ai_model, currency, billing_mode и т.п.) null пропускают, а у задержки и search_max_results null возвращает значение по умолчанию — это указано в описании поля |
Ключ вложенного объекта с null | В объектах, которые сливаются по ключам (config агента, *_locales, paid_features, тексты /templates), — ключ удалён |
| Незнакомое поле | Пропущено, попадает в ignored; с strict=true — ошибка 422 |
Повторный одинаковый PUT безопасен: результат тот же, что после первого. POST на создание не идемпотентен — повтор создаст вторую запись. Если скрипт может повторить запрос после сбоя сети, сначала проверьте списком, что запись ещё не создана.
CORS
API отвечает на запросы с любого домена: access-control-allow-origin: *, предварительный OPTIONS разрешает запрошенные метод и заголовки. Куки не используются, авторизация только по ключу.
Технически API можно вызывать из браузера, но личный ключ при этом окажется у посетителя. Из браузера работайте только с тем, что не требует ключа, а управление держите на своём сервере.