429 и растянете работу на часы.
Тот же список, отправленный батчем, — это один запрос и одна подпись.
Как это устроено: асинхронность
Батч не обрабатывается синхронно. Шлюз не держит ваше соединение, пока проводит 5000 выплат — это заняло бы минуты и любой таймаут убил бы запрос. Вместо этого:batch_id. Результаты
появляются позже, в /v1/batch/info.
Шаг 1. Отправить батч
Три эндпоинта, по одному на вид операции. Внутри массива лежат ровно те же объекты, что вы отправили бы поштучно:batch_id — без него результаты не забрать.
Элементы батча платежей поддерживают всё то же, что и одиночный POST /v1/payment, — включая цену
в фиате, причём в разных валютах внутри одного батча:
on_error: что делать при ошибке в элементе
Отдельного статуса
skipped нет. Непройденный элемент отличается от настоящей ошибки только
текстом в поле error. Поэтому при on_error: "stop" число failed включает и те элементы, до
которых обработка просто не дошла, — не считайте их все отказами.continue, если элементы независимы (типичный случай: выплаты разным людям). Берите stop,
если пачка осмысленна только целиком и вы хотите разобраться до того, как уйдут остальные деньги.
Как continue выглядит на практике: батч из 3 платежей, один элемент с несуществующей парой
валюта/сеть →
stop на практике — тот же батч из 3 платежей, ошибка во втором:
error.
Шаг 2. Опрашивать статус
pending (принят, ещё не начали) → processing (идёт обработка) → completed
(обработаны все элементы, которые должны были обработаться).
completed не значит «всё удалось». Оно значит «шлюз закончил». Сколько элементов прошло, а
сколько нет — смотрите в succeeded / failed.Шаг 3. Разобрать результаты поэлементно
Ответ/v1/batch/info:
idx— позиция элемента в исходном массиве, который вы отправили. По нему вы сопоставляете результат со своей строкой в БД.result— то, что вернул бы одиночный вызов (полный объект платежа/выплаты/возврата, сuuid).error— строка с причиной, если элемент не прошёл.
items[].status) — не путайте их со статусом батча:
Статуса
skipped нет. Элемент, до которого обработка не дошла (при on_error: "stop"), тоже
получает error — с текстом "skipped: batch stopped after an earlier failure". Отличить его от
настоящего отказа можно только по этому тексту:
Ветвитесь по
status, а не по тексту error. Текст в error — человекочитаемое сообщение,
а не код ошибки: он может измениться. Единственное исключение — проверка на строку выше, если
вам важно отличить «не дошли» от «не прошло».items постраничные — их может быть 5000. Листайте через limit/offset:
Node.js: полный цикл
Шаг 4 (для выплат). done ≠ выплачено
Для батча выплат items[].status: "done" означает лишь, что выплата создана: в result она
приходит со status: "process" (это видно в примере ответа выше). Финальные статусы — paid, fail
или cancel — наступают позже, когда шлюз отправляет транзакцию в сеть, и выплата на этом этапе всё
ещё может упасть.
Дождаться финала можно двумя способами:
- Вебхуки
payout.confirmed(успех) /payout.failed— см. Настройка вебхуков. - Поллинг
POST /v1/payout/infoпо сохранённомуresult.uuid— доis_final: true(статусы и признак финальности — в объекте выплаты).
uuid каждого done-элемента: это ваш ключ для сверки
финального статуса. Для батча платежей аналогично: done = счёт создан, об оплате сообщат
invoice.*‑вебхуки.
Идемпотентность батча
Работает на двух уровнях, и оба стоит использовать:- Заголовок
Idempotency-Keyна самом запросе батча. Защищает от «отправил батч, ответ потерялся, отправил ещё раз» — повтор с тем же ключом вернёт тот жеbatch_id, а не создаст второй батч из тех же 5000 выплат. Это ровно тот сценарий, где ошибка стоит очень дорого. order_idвнутри каждого элемента. Дедуплицирует конкретную операцию (для выплатorder_idобязателен). Даже если батч каким‑то образом продублируется, элементы с теми жеorder_idне уйдут дважды.
Ошибки уровня батча
Отклоняется весь запрос (элементы даже не начинают обрабатываться):
Ошибки отдельных элементов сюда не попадают: они лежат в
items[].error и не роняют весь запрос
(при on_error: "continue").
Что осталось от /v1/payout/mass
POST /v1/payout/mass (до 100 выплат, синхронно) продолжает
работать, но это легаси‑путь. Он оправдан ровно в одном случае: пачка маленькая и вам нужен
результат прямо в ответе, без поллинга. Для всего остального — батч.
→ Массовые выплаты
Практические правила
- Не поллите слишком часто.
/v1/batch/info— тоже запрос и тоже ест лимит частоты. Раз в несколько секунд более чем достаточно; вы только что сэкономили 5000 запросов, не тратьте их на поллинг. - Проверьте баланс до батча выплат. Если денег хватит на половину списка, вторая половина честно
вернёт
insufficient_fundsвitems[].error— но вы об этом узнаете только на разборе. - Храните
batch_idрядом с задачей. Если ваш процесс упал в середине поллинга,batch_id— единственный способ забрать результаты потом. - Уникальный
order_idна каждый элемент. Это ваш якорь для сверки:idxпривязан к позиции в массиве,order_id— к вашей сущности.
Связанные страницы
POST /v1/payment/batch
POST /v1/payout/batch
POST /v1/refund/batch
POST /v1/batch/info
Массовые выплаты (легаси)
/v1/payout/mass и когда он ещё уместен.Ограничение частоты
Почему батч решает проблему
429.