Платежи
M2M-платежи: загрузка платежей из 1С-файла, отправка в банк, статус, поиск. Шесть endpoint'ов, общая идемпотентность по external_id+payload_hash.
:::info Требования к токену Все endpoint'ы ниже требуют:
purpose=integration;scope_send_payments=true+ per-accountallow_send_payments=trueна целевом РС.
MCP-токен на любой из endpoint'ов ниже получает 403 forbidden_purpose в auth-middleware до handler'а.
:::
Жизненный цикл платежа
Платёж проходит две стадии: parse (загрузка файла, создание batch + items) и submit (отправка items в банк). Это разделение позволяет клиенту увидеть результат разбора и решить, что делать с невалидными строками, прежде чем тратить лимиты на банк.
POST /imports → batch created, items parsed/duplicate/validation_error/unsupported
GET /imports/{id} → текущее состояние batch + items
POST /imports/{id}/submit → submit всех ready items в банк
POST /imports/{id}/items/{i}/submit → retry одного item
GET /payments/{id} → детализированный статус платежа
GET /payments?external_id=… → поиск по Номеру 1СUpload — POST /payments/imports
POST /api/v1/integration/payments/imports
Загружает 1С-файл (1CClientBankExchange v1.02 / v1.03, до 10 MB). Парсит платежи в batch + items, не отправляя в банк.
Запрос — multipart/form-data
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
bank_account_id | uuid | ✓ | РС-плательщик. Должен присутствовать в ответе GET /integration/bank-accounts и иметь permissions.send_payments=true. |
file | file | ✓ | Файл формата 1CClientBankExchange. Кодировка cp1251 (как 1С его и пишет). Размер до 10 MB. Версия определяется автоматически по ВерсияФормата в шапке. |
curl --silent --show-error \
-H "Authorization: Bearer bcs_live_<TOKEN>" \
-F "bank_account_id=<bank-account-uuid>" \
-F "file=@payments.txt" \
"https://bsc.example.com/api/v1/integration/payments/imports"{
"batch_id": "<batch-uuid>",
"items_total": 3,
"items": [
{ "item_id": "<item-uuid>", "external_id": "100", "status": "parsed" },
{ "item_id": "<item-uuid>", "external_id": "101", "status": "duplicate", "payment_order_id": "<existing>" },
{ "item_id": "<item-uuid>", "external_id": "102", "status": "validation_error",
"error": { "code": "missing_field", "message": "Сумма обязательна" } }
]
}Статусы items на этапе parse
| Статус | Описание |
|---|---|
parsed | Готов к submit. Все поля корректны, нет конфликта по external_id. |
duplicate | Item с тем же external_id + тем же payload_hash уже существует у этого токена. Возвращается existing payment_order_id; submit игнорируется как no-op replay. |
validation_error | Item не прошёл схему: пустой external_id, отрицательная сумма, плохой ИНН и т.п. Submit пропускает. |
unsupported | Item корректный, но содержит тип документа, не поддерживаемый банк-адаптером (например, валютный платёж на rub-only адаптере). |
:::warning account_mismatch — 422
Если в 1С-файле в РасчСчет плательщика указан номер, не совпадающий с bank_account_id запроса, backend возвращает 422 account_mismatch, batch не создаётся. Это защита от случайной отправки платежей не с того счёта. Сценарии 1С см. Интеграция с 1С.
:::
Get batch — GET /payments/imports/{batch_id}
GET /api/v1/integration/payments/imports/{batch_id}
Текущее состояние batch + items. Batch другого токена → 404 (не светим существование).
curl --silent --show-error \
-H "Authorization: Bearer bcs_live_<TOKEN>" \
"https://bsc.example.com/api/v1/integration/payments/imports/<batch_id>"Используется для polling после submit (см. ниже) и для UI, показывающего прогресс отправки.
Submit batch — POST /payments/imports/{batch_id}/submit
POST /api/v1/integration/payments/imports/{batch_id}/submit
Отправляет все ready items batch'а в банк. Идемпотентен: повторный submit ничего не дублирует.
curl --silent --show-error -X POST \
-H "Authorization: Bearer bcs_live_<TOKEN>" \
"https://bsc.example.com/api/v1/integration/payments/imports/<batch_id>/submit"{
"batch_id": "<batch-uuid>",
"results": [
{ "item_id": "<id>", "external_id": "100", "status": "accepted", "payment_order_id": "<new>" },
{ "item_id": "<id>", "external_id": "101", "status": "duplicate", "payment_order_id": "<existing>" },
{ "item_id": "<id>", "external_id": "102", "status": "skipped", "reason": "validation_error" },
{ "item_id": "<id>", "external_id": "103", "status": "rejected",
"error": { "code": "conflict", "message": "payload_hash отличается" } }
]
}Статусы items на этапе submit
| Статус | Описание |
|---|---|
accepted | Платёж принят банком, создан payment_order_id. |
duplicate | Платёж с этим external_id уже существует у токена; банк не вызывается; возвращён existing payment_order_id. |
skipped | Item не был в статусе parsed на момент submit (например, validation_error). В поле reason — текущий DB-статус. |
rejected | Submit прошёл до банк-вызова и был отвергнут: conflict (тот же external_id + другой hash), bank_error (банк вернул ошибку), и т.п. |
Submit single item — POST /payments/imports/{batch_id}/items/{item_id}/submit
POST /api/v1/integration/payments/imports/{batch_id}/items/{item_id}/submit
Retry одного item — после исправления validation_error или после bank_error. Возвращает 409 на conflict.
curl --silent --show-error -X POST \
-H "Authorization: Bearer bcs_live_<TOKEN>" \
"https://bsc.example.com/api/v1/integration/payments/imports/<batch_id>/items/<item_id>/submit"В отличие от batch-submit, single-item submit принимает items в статусах parsed, failed, rejected — то есть всё, что подлежит ретраю. Conflict (тот же external_id, другой hash) → HTTP 409 (а не 200 с rejected внутри). Это упрощает обработку retry'ев на стороне клиента.
Идемпотентность — критичный контракт
:::info Правило Тройка (api_token_id, external_id, payload_hash) — уникальный ключ платежа.
- Тот же
external_id+ тот жеpayload_hash→duplicate, банк не вызывается, возвращается existingpayment_order_id. - Тот же
external_id+ другойpayload_hash→409 conflict. Чтобы переотправить — выпустите 1С-документ с новымНомер. :::
external_id — это trim()-нутое поле Номер из секции СекцияДокумент 1С-файла. Должен быть уникальным в рамках одного API-токена.
payload_hash = sha256 от канонической сериализации полей: bank_account_id, external_id, amount, currency, doc_date, doc_type, payee (account / bik / inn / kpp / name), purpose. Если изменили хоть одно из этих полей — это другой платёж, и BCS требует новый external_id.
Batch-replay (повторная загрузка того же файла)
Повторный submit того же batch'а — безопасный no-op. Items, которые уже ушли в банк (статусы created / submitting / submitted / completed), возвращаются как skipped с reason = текущий DB-статус. Банк повторно не вызывается, новый payment_order не создаётся.
Get payment — GET /payments/{payment_order_id}
GET /api/v1/integration/payments/{payment_order_id}
Детализированный статус платежа. Платёж другого токена → 404.
curl --silent --show-error \
-H "Authorization: Bearer bcs_live_<TOKEN>" \
"https://bsc.example.com/api/v1/integration/payments/<payment_order_id>"{
"payment_order_id": "<uuid>",
"external_id": "100",
"status": "created",
"amount": "1234.56",
"currency": "RUB",
"doc_date": "2026-05-18",
"bank_account_id": "<bank-account-uuid>",
"payee": {
"account_number_masked": "4070…0111",
"bik": "044525225",
"inn": "5566778899",
"kpp": "556601001",
"name": "ООО Контрагент"
},
"purpose": "Оплата по счёту № 17 от 2026-05-15",
"created_at": "2026-05-18T10:00:00Z",
"updated_at": "2026-05-18T10:00:05Z"
}Статусы payment_order
| Статус | Описание |
|---|---|
created | Принят BCS, ждёт отправки в банк. |
submitting | Отправляется в банк прямо сейчас. |
submitted | Банк принял; ждёт подтверждения статуса (зависит от банк-адаптера). |
completed | Банк подтвердил исполнение. |
failed | Submit не удался (банк-ошибка или transport). Можно повторить через single-item submit. |
rejected | Банк отверг платёж (валидация на стороне банка). См. подробности в error поле. |
Search — GET /payments?external_id=…
GET /api/v1/integration/payments?external_id=<value>
Поиск платежа по Номеру 1С. Изолирован по api_token_id — видны только платежи текущего токена.
curl --silent --show-error \
-H "Authorization: Bearer bcs_live_<TOKEN>" \
"https://bsc.example.com/api/v1/integration/payments?external_id=100"Возвращает массив payment_orders (обычно 0 или 1 элемент, но technically возможны несколько, если на разных batch'ах использовали один и тот же external_id; конфликт ловится на submit, не на upload).
Ошибки
| HTTP | code | Когда возникает |
|---|---|---|
| 400 | validation_error | Невалидный формат файла, отсутствующие поля, плохой UUID. |
| 401 | invalid_token | Токен невалиден / истёк / отозван. |
| 403 | forbidden_purpose | Используется MCP-токен на write-endpoint'е. |
| 403 | forbidden_scope | У токена нет scope_send_payments=true. |
| 403 | forbidden_account | У токена нет allow_send_payments=true на целевом РС. |
| 403 | forbidden_company | РС принадлежит другой компании (cross-tenant). |
| 404 | not_found | Batch / payment не существует или принадлежит другому токену. |
| 409 | conflict | Тот же external_id, другой payload_hash. Single-item submit, не batch. |
| 413 | payload_too_large | Файл больше 10 MB. |
| 422 | account_mismatch | РС-плательщик в файле не совпадает с bank_account_id запроса. |
| 429 | rate_limited | Превышен per-token лимит. |
| 500 | bank_error | Внутренняя ошибка банк-адаптера. Подробности в response_body. |