Лимиты и соглашения
Лимиты, размеры запросов, версионирование URL, request-id, retry-политика. Один документ для всех соглашений API.
Rate limits — per-token
Лимит считается per-token и сбрасывается раз в минуту (fixed window). Превышение → 429 rate_limited + HTTP header Retry-After.
| Поле | Тип | Описание |
|---|---|---|
integration | purpose | Default: 60 запросов в минуту. |
mcp | purpose | Default: 300 запросов в минуту (агенты бывают шумными). |
rate_limit_per_minute | override | Per-token override через admin UI. Min 1, max разумных значений (10000) — реально нужно редко. |
:::info Что считается одним запросом
Любой HTTP request, который дошёл до RequireAPIToken middleware. Запросы без Bearer не считаются (они в принципе не имеют token-binding'а). Failed requests (401 / 403 / 422 / 500) — считаются.
:::
429 response
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1747569600
Content-Type: application/json
{
"error": {
"code": "rate_limited",
"message": "Превышен лимит запросов; повторите через 30 секунд",
"details": { "retry_after_seconds": 30 }
}
}Клиент обязан уважать Retry-After (секунды). Реализуйте exponential backoff на случай нескольких подряд 429: retry_after, ×2, ×4, max 5 минут.
Размеры запросов
| Endpoint | Лимит |
|---|---|
POST /integration/payments/imports — multipart file | 10 MB. Превышение → 413 payload_too_large. |
POST /api/v1/mcp — JSON-RPC body | 16 KB. Превышение → 413 payload_too_large. |
| Прочие POST/PUT bodies | 1 MB (хватает с большим запасом на любой типовой payload). |
Версионирование URL
Текущий префикс — /api/v1/. Внутри v1 backend гарантирует:
- Добавление новых полей в response — не breaking. Клиент должен игнорировать неизвестные поля (forward-compat).
- Добавление новых endpoint'ов — не breaking.
- Изменение типа существующего поля — breaking, не делается в v1.
- Удаление поля или endpoint'а — breaking, не делается в v1.
- Smaller изменения семантики error.code — breaking; новые error-коды добавляются, существующие не пере-используются.
Breaking changes выйдут под новым префиксом (/api/v2/). v1 будет жить в параллель минимум 12 месяцев после релиза v2.
HTTP headers — соглашения
| Header | Где | Описание |
|---|---|---|
Authorization | request | Обязателен везде. Bearer bcs_…. |
Content-Type | request | application/json для POST/PUT body. Для POST /payments/imports — multipart/form-data. |
X-Request-Id | request/response | Клиент может слать свой; иначе backend генерирует. Возвращается в response header. Включайте в repro при баг-репортах. |
X-MCP-Session-Id | request | Только REST /api/v1/mcp/* (stdio bcs-mcp). UUIDv4, генерируется клиентом per-process. |
Mcp-Session-Id | request/response | Только Streamable HTTP POST /api/v1/mcp. Server-issued на initialize, клиент-echo'ит на последующих запросах. |
Retry-After | response | На 429 — секунды до следующей попытки. |
X-RateLimit-Limit / -Remaining / -Reset | response | Текущее окно: лимит, остаток, unix-timestamp сброса. Возвращаются на каждом запросе с rate-limited middleware. |
Origin | request | Только MCP HTTP transport — для проверки allowlist (MCP_ALLOWED_ORIGINS). |
Кодировки
| Контекст | Кодировка |
|---|---|
| JSON request/response | UTF-8 без BOM. |
| 1CClientBankExchange (upload payments / export statements format=1c) | cp1251 (как 1С его и пишет). Charset в Content-Type экспорта явно проставлен. |
| CSV export (format=csv) | UTF-8, разделитель , (RFC 4180). |
Идемпотентность по endpoint'ам
| Endpoint | Идемпотентен? |
|---|---|
POST /payments/imports | Нет (каждый upload — новый batch). Идемпотентность встроена в submit, не в upload. |
POST /payments/imports/{id}/submit | Да — по (api_token_id, external_id, payload_hash). |
POST /payments/imports/{id}/items/{id}/submit | Да — то же правило. |
POST /statements | Да — по (api_token_id, external_id, bank_account_id, date_from, date_to). |
| GET endpoints | Естественно — нет side-effects. |
POST /api/v1/mcp method=initialize | Нет — каждый initialize создаёт новую сессию. |
DELETE /api/v1/mcp | Да — удаление несуществующей сессии = success (204). |
Что НЕ возвращается ни в одном ответе
Data-minimization инвариант. Эти поля никогда не появляются в integration / MCP response'ах (только в admin-зоне за логином):
token_hash, raw bcs_… токены;- банковские credentials (
credentials_id,metadata_json,secret_id); signing_secret, rawrefresh_token,access_token,private_key;bank_reference,sign_url(внутренние bank-side handle'ы);- Полный 20-значный номер РС (только
_maskedформа — кроме export'а выписки в JSON, где он машинно-нужен).
Если в response какого-то endpoint'а вы видите одно из этих полей — это баг backend'а, прошу репортить.