Коды ошибок
Единый envelope для всех ошибок BCS API. Машинно-читаемый code + человеко-читаемый message + опциональные details.
Envelope
{
"error": {
"code": "validation_error",
"message": "bank_account_id обязателен (UUID)",
"details": {
"field": "bank_account_id"
}
}
}| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
error.code | string | ✓ | Стабильный машинный код. Не меняется без bump'а major-версии API. Клиент должен matching'овать по code, не по message. |
error.message | string | ✓ | Человеко-читаемое описание (RU). Показывайте оператору, не парсите. |
error.details | object | Структурированный контекст (например, {"field": "..."}, {"retry_after_seconds": 30}). Опционален. |
Полный справочник кодов
| HTTP | code | Когда возникает |
|---|---|---|
| 400 | validation_error | Невалидный формат запроса: missing field, плохой UUID, плохая дата, период вне допустимого, и т.п. Универсальный код валидации. |
| 400 | invalid request body | Невалидный JSON в body или malformed UUID в URL-path. Срабатывает до ручного валидатора. |
| 401 | invalid_token_format | Нет header Authorization, либо токен не начинается с bcs_live_ / bcs_test_. |
| 401 | invalid_token | Формат корректный, но токен не найден / отозван / истёк. |
| 403 | forbidden_ip | Запрос с IP вне allowed_ips токена. |
| 403 | forbidden_purpose | Назначение токена не подходит endpoint'у (например, MCP-токен на REST integration-endpoint'е или integration-токен на /api/v1/mcp). |
| 403 | forbidden_scope | У токена нет нужного scope (read_statements / send_payments). |
| 403 | forbidden_account | scope есть, но у токена нет per-account allow на конкретный bank_account_id. |
| 403 | forbidden_company | Запрошенный bank_account_id принадлежит другой компании. Cross-tenant попытка. |
| 403 | forbidden_origin | Только MCP HTTP transport. Origin вне MCP_ALLOWED_ORIGINS. |
| 404 | not_found | Resource (batch / payment / statement) либо отсутствует, либо принадлежит другому токену. Намеренно не различаем — не светим существование. |
| 405 | method_not_allowed | HTTP-метод не поддержан на endpoint'е. На /api/v1/mcp — GET → 405 (SSE upgrade не реализован). |
| 409 | conflict | Тот же external_id у этого токена для другого payload / периода / РС. Для платежей: single-item submit. Для выписок: POST /statements. |
| 409 | not_ready | Запрос export на выписку до того, как её статус стал ready. |
| 413 | payload_too_large | Body превышает лимит. Для платежного файла — 10 MB; для MCP HTTP — 16 KB. |
| 422 | account_mismatch | В 1С-файле указан РС-плательщик, не совпадающий с bank_account_id запроса. Batch не создаётся. |
| 429 | rate_limited | Превышен per-token лимит. error.details.retry_after_seconds + HTTP header Retry-After подсказывают, через сколько ретраить. |
| 500 | internal_error | Неожиданная ошибка backend'а. Запишите request_id из X-Request-Id header и эскалируйте админу. |
| 500 | bank_error | Банк-адаптер вернул ошибку. error.details может содержать bank-specific код. |
| 501 | bank_not_supported | Банк-адаптер целевого РС не реализует данную операцию (например, выписки на адаптере без SupportsStatements). |
| 503 | service_unavailable | Только MCP HTTP transport. Redis session store недоступен — fail-closed контракт. |
MCP JSON-RPC error codes
MCP HTTP transport использует JSON-RPC 2.0 envelope. Ошибки протокольного уровня — внутри JSON-RPC error object с одним из стандартных кодов:
| code | name | Когда возникает |
|---|---|---|
| -32700 | Parse error | Невалидный JSON в body. |
| -32600 | Invalid Request | Нет/неверный jsonrpc; нет Mcp-Session-Id на non-initialize методе; сессия истекла; сессия другого токена. |
| -32601 | Method not found | Unknown JSON-RPC method или unknown tool name. Все write-tools (send_payment, approve и т.п.) фактически попадают в эту категорию — их нет в registry. |
| -32602 | Invalid params | Bad params в tools/call. |
| -32603 | Internal error | Внутренняя ошибка backend. |
:::info
Tool-level ошибки (валидация аргументов tool, ACL, not_found для конкретной выписки) приходят как {"jsonrpc":"2.0","id":N,"result":{"isError":true,"content":[…],"_meta":{"notice":…}}} — HTTP 200, JSON-RPC success, но внутри tool result isError=true. Это спецификация MCP, не пропуск backend'а.
:::
Политика retry
| Категория | Поведение |
|---|---|
| 401, 403 | НЕ ретраить. Решается ротацией токена / правкой ACL. |
| 404 | НЕ ретраить. |
| 409 conflict | НЕ ретраить с тем же external_id. Нужно поменять идентификатор (новый Номер 1С). |
| 409 not_ready | Ретраить с backoff (1s → 2s → 4s, до status=ready). |
| 413, 422 | НЕ ретраить. Исправить запрос на клиенте. |
| 429 | Ждать Retry-After секунд, потом повторить. Реализуйте exponential backoff на случай шквала 429'ов. |
| 500 internal_error | Эскалировать с request_id. Ретрай только после устранения root cause. |
| 500 bank_error | Зависит от bank-specific кода. Часть — transient (network к банку), часть — permanent (отказ банка). На бизнес-уровне всегда показывать оператору. |
| 503 service_unavailable | Ретраить с backoff. Обычно временное. |
X-Request-Id
Каждый HTTP-ответ BCS содержит X-Request-Id header — уникальный идентификатор запроса. Если клиент шлёт свой X-Request-Id, backend его пропускает; иначе генерит свой. При репортинге об ошибке в support — обязательно включайте этот id, по нему легко найти полный контекст в audit log.