API Reference

REST API

REST поверх HTTPS, JSON в обе стороны. База - https://zergpay.com. Bearer-ключ из ЛК, опционально с HMAC-подписью; Idempotency-Key на create-операциях.

Платежи

Магазин определяется по API-ключу - один ключ соответствует одному магазину. Для нескольких магазинов выпустите отдельные ключи в личном кабинете.

Создание платежа

POST/v1/public/payments
Создаёт платёжную сессию. В ответе - объект платежа и payment_url, на который нужно перенаправить покупателя.
Тело запроса
amountСумма в минорных единицах. Для RUB - копейки. Обязательно.
currencyКод валюты ISO-4217. По умолчанию RUB.
methodСпособ оплаты: sbp, cards, tpay, sberpay, recurrent или any. По умолчанию any - покупатель выбирает на нашей странице.
order_idВаш идентификатор заказа. Если не передан, сгенерируется ord_<timestamp>.
customer_idВаш идентификатор клиента. Сохраняется в metadata и используется для группировки операций.
return_urlURL, на который вернётся покупатель после оплаты. Требуется схема https://.
descriptionВаше описание платежа. Сохраняется и возвращается в API; в банк не передаётся - назначение платежа единое: «Оплата заказа P-номер».
webhook_urlАдрес webhook-получателя только для этого платежа. Переопределяет настройки магазина.
ttl_minutesСрок жизни платёжной ссылки в минутах. Не передан - по умолчанию 60 (1 час). По истечении - статус expired. Максимум 7 дней.
metadataПроизвольные пары ключ-значение. До 20 пар, значения - строки до 500 символов.
Запрос
curl -X POST https://zergpay.com/v1/public/payments \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7f2a-pay-1042' \
  -d '{
    "amount":      150000,
    "currency":    "RUB",
    "method":      "sbp",
    "order_id":    "ORDER-1042",
    "customer_id": "user-7821",
    "return_url":  "https://example.com/order/1042/done"
  }'
Ответ
{
  "payment": {
    "id":          "5a331a39-32bf-4940-afb1-855e2fc6757f",
    "public_id":   "P-11000010",
    "merchant_id": "22222222-2222-2222-2222-222222222222",
    "shop_id": "33333333-3333-3333-3333-333333333333",
    "order_id":    "ORDER-1042",
    "amount":      150000,
    "currency":    "RUB",
    "method":      "sbp",
    "status":      "pending",
    "expires_at":  "2026-05-05T13:42:00Z",
    "created_at":  "2026-05-05T12:42:00Z"
  },
  "payment_url": "https://zergpay.com/pay/5a331a39-...",
  "mode":        "live",
  "bank":        "Сбер",            // имя банка-эквайера, если он ответил sync
  "bank_ref":    "262512345678"     // ID операции в банке (только для h2h)
}

Поля idempotent: true, failure_code и failure_message возвращаются при повторе запроса по Idempotency-Key или при синхронном отказе банка. В тестовом режиме добавляются служебные поля симулятора - описаны на странице Тестовая среда.

Проверка статуса платежа

GET/v1/public/payments/{id}
Возвращает полный объект платежа с актуальным status, finalized_at и списком возвратов refunds[]. Используется для синхронной проверки статуса и после получения webhook-уведомления.
Запрос
curl -X GET https://zergpay.com/v1/public/payments/5a331a39-32bf-4940-afb1-855e2fc6757f \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "id":              "5a331a39-32bf-4940-afb1-855e2fc6757f",
  "public_id":       "P-11000010",
  "merchant_id":     "22222222-2222-2222-2222-222222222222",
  "shop_id":     "33333333-3333-3333-3333-333333333333",
  "shop_name":   "Web checkout",
  "order_id":        "ORDER-1042",
  "status":          "succeeded",
  "amount":          150000,
  "amount_refunded": 0,
  "currency":        "RUB",
  "method":          "sbp",
  "rrn":             "262512345678",
  "bank_name":       "Сбер",
  "return_url":      "https://example.com/order/1042/done",
  "created_at":      "2026-05-05T12:42:00Z",
  "captured_at":     "2026-05-05T12:43:11Z",
  "finalized_at":    "2026-05-05T12:43:11Z",
  "expires_at":      "2026-05-05T13:42:00Z",
  "processing_until":"2026-05-05T13:02:00Z",
  "metadata":        { "customer_id": "user-7821" },

  "customer_card_brand":  "visa",
  "customer_card_mask":   "411111******1111",
  "customer_card_holder": "IVAN IVANOV",
  "customer_phone_mask":  "+7•••••••12-34",
  "customer_payer_bank":  "Сбер",

  "refunds": [
    {
      "id":           "9b2c1f8a-1111-2222-3333-444444444444",
      "payment_id":   "5a331a39-32bf-4940-afb1-855e2fc6757f",
      "amount":       50000,
      "reason":       "частичный по запросу",
      "status":       "succeeded",
      "created_at":   "2026-05-05T15:10:00Z",
      "completed_at": "2026-05-05T15:10:08Z"
    }
  ]
}

Отмена платежа

POST/v1/public/payments/{id}/cancel
Работает только в статусе pending. На остальных статусах возвращается 409 not_pending. После успешной отмены отправляется webhook payment.cancelled.
Запрос
curl -X POST https://zergpay.com/v1/public/payments/5a331a39-32bf-4940-afb1-855e2fc6757f/cancel \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "status": "cancelled"
}

Метод any (мультиформа)

Когда мерчант создаёт платёж с method: "any" (или вообще без поля method), в ответе payment_url ведёт на нашу страницу https://zergpay.com/pay/<id>. Покупатель сам выбирает способ оплаты: карта, СБП, T-Pay, SberPay или recurrent.

Жизненный цикл

  1. Создаётся платёж со статусом pending, methods=any. Banking-сессии ещё нет, processing_until пустой.
  2. Покупатель открывает payment_url, видит кнопки методов.
  3. Жмёт «Оплатить через СБП» (например). Метод фиксируется: статус остаётся pending, поле method меняется с any на sbp. Webhook на этом шаге не отправляется.
  4. Открывается банк-сессия: статус становится processing, processing_until заполняется на длительность TTL метода (для СБП - 20 мин). Webhook'ом этот переход не сопровождается.
  5. Банк присылает финальный статус: succeeded или failed. Прилетает webhook payment.succeeded или payment.failed.
Если за время processing_until банк не вернёт статус, платёж переходит в expired, и мерчант получает webhook payment.expired. Это другая семантика, чем failed: банк не отказал, просто не закрыл сессию.

До выбора метода платёж нельзя ни отменить (cancel разрешён только в pending - и здесь он сработает), ни вернуть (succeeded ещё не наступил). Мерчант может смотреть статус через GET /payments/{id} или ждать webhook.

Поле metadata

metadata - произвольные пары ключ-значение, которые вы передаёте при создании платежа. Мы их не интерпретируем, только храним и отдаём обратно. Удобно прокидывать ID корзины, источник трафика, A/B-метку и т.п.

Лимиты

  • Все значения - строки. Числа и булевы передавайте как "42" / "true", мы не трогаем.
  • Рекомендуем не больше 20 пар на платёж и 500 символов в значении. Жёсткого лимита нет, но сверху всё это лежит в JSONB-колонке БД.
  • Кодировка - UTF-8.

Где их потом увидеть

  • В ответе POST /payments - поле payment.metadata.
  • В ответе GET /payments/{id} - то же поле.
  • В data-объекте webhook'а.

Зарезервированные ключи

Помимо ваших данных в metadata могут оказаться служебные ключи, которые проставляем мы. Ничего страшного, просто не удивляйтесь:

ключкогда появляется
modeвсегда. Значение test или live по используемому ключу.
webhook_urlесли вы передали webhook_url в теле POST /payments.
customer_idесли вы передали customer_id в теле POST /payments.
bank_reflive-режим: ID операции на стороне банка-эквайера.
failure_codeна failed/expired: наш унифицированный код отказа (см. раздел «Коды отказов»).
bank_failure_codeна failed: сырой код от банка. Только для аудита, программно опираться лучше на failure_code.
simulator_outcometest-режим: запланированный исход симулятора (succeeded, failed, requires_action, pending).
simulator_failure_codetest-режим: код, который симулятор подсунет как банковский ответ.

Не используйте эти имена для своих ключей: при пересечении мы перезапишем ваше значение.

Возврат покупателя в магазин

Если в POST /payments вы указали return_url, после достижения финального статуса мы перенаправим покупателя по этому адресу с двумя query-параметрами:

https://example.com/order/1042/done?payment_id=5a331a39-...&status=succeeded
параметрзначение
payment_idUUID платежа.
statussucceeded | failed | cancelled | refunded | expired.

Существующие query-параметры в вашем return_url сохраняются. Если в URL уже был ?ref=email, он останется, плюс добавятся наши два.

Не доверяйте параметрам как факту оплаты. Покупатель может подменить URL руками. Перед тем как «поздравить с покупкой», подтвердите статус сервер-сайдом - через webhook payment.succeeded или явный GET /payments/{id}.

Когда происходит редирект

  • succeeded: через ~2 секунды после показа экрана «Платёж выполнен».
  • failed / cancelled / refunded / expired: сразу.
  • Если return_url не указан, мы оставляем покупателя на нашей странице с состоянием.

Рекуррентные платежи

Подписка - это регулярные списания по сохранённому способу оплаты. Метод задаётся полем method: cards (карта), sbp (СБП) или tpay (T-Pay). Первая оплата привязывает способ (с согласием клиента; для карты ещё 3DS), банк выдаёт токен, дальше платформа сама списывает по расписанию без участия клиента (MIT). Если нужны просто примитивы «привязать и списывать самому», смотрите Рекуррентные токены.

Как это работает

  1. POST /v1/public/subscriptions - создаёте подписку. В ответе pay_url.
  2. Отправляете клиента на pay_url - он оплачивает первую сумму и соглашается на регулярные списания.
  3. После успешной оплаты приходит webhook, токен сохраняется, подписка становится active и выставляется next_charge_at.
  4. Платформа списывает автоматически по расписанию.
  5. После 3 неудачных списаний подряд подписка автоматически отменяется (cancelled).

Объект Subscription

ПолеТипОписание
idUUIDИдентификатор подписки.
amountint64Сумма периодического списания в минорных единицах.
currencystringВалюта (RUB).
methodenumcards (карта), sbp (СБП), tpay (T-Pay). Первый платёж списывается сразу.
periodenumday | week | month | year.
interval_countintСписывать каждые N period.
trial_daysintПробный период в днях до первого списания (0 - без пробного).
statusenumpending → active → (past_due) → cancelled.
next_charge_attimeКогда запланировано следующее списание.

Создать подписку

POST/v1/public/subscriptions
Создаёт подписку и первичный bind-платёж. Возвращает pay_url - ссылку для оплаты и привязки. Требует scope рекуррента на магазине.
Тело запроса
amountСумма периодического списания в минорных единицах (копейки). Обязательно.
customer_refВаш идентификатор клиента. Обязательно.
methodcards (по умолчанию) | sbp | tpay.
periodday | week | month | year. По умолчанию month.
interval_countКаждые N period. По умолчанию 1.
trial_daysПробный период в днях (method=cards и sbp). Привязка идёт без списания (для карты верификация 1 ₽, для СБП binding на 1 ₽), полная сумма списывается после пробного периода. Для tpay недоступен. По умолчанию 0.
customer_emailОпционально.
plan_nameОпционально, метка плана.
Запрос
curl -X POST https://zergpay.com/v1/public/subscriptions \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json' \
  -d '{
  "amount": 199000,
  "customer_ref": "user_42",
  "method": "cards",
  "period": "month",
  "interval_count": 1
}'
Ответ
{
  "subscription": {
    "id":             "7f0e...",
    "status":         "pending",
    "amount":         199000,
    "currency":       "RUB",
    "method":         "cards",
    "period":         "month",
    "interval_count": 1,
    "next_charge_at": "2026-07-13T10:00:00Z"
  },
  "initial_payment": { "id": "4f0e...", "status": "pending" },
  "pay_url": "https://zergpay.com/pay/4f0e..."
}

До оплаты по pay_url подписка в статусе pending и списаний не делает.

Список подписок

GET/v1/public/subscriptions
Все подписки магазина, к которому привязан API-ключ.
Запрос
curl -X GET https://zergpay.com/v1/public/subscriptions \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'

Получить подписку

GET/v1/public/subscriptions/{id}
Одна подписка по id (только своя).
Запрос
curl -X GET https://zergpay.com/v1/public/subscriptions/7f0e... \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'

График списаний

GET/v1/public/subscriptions/{id}/schedule
История проведённых платежей подписки + проекция ближайших будущих дат списания (для active/past_due).
Запрос
curl -X GET https://zergpay.com/v1/public/subscriptions/7f0e.../schedule \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "subscription_id": "7f0e...",
  "status":          "active",
  "amount":          199000,
  "currency":        "RUB",
  "period":          "month",
  "interval_count":  1,
  "next_charge_at":  "2026-07-13T10:00:00Z",
  "charges": [
    { "payment_id": "4f0e...", "kind": "subscription_init",   "amount": 199000, "status": "succeeded", "created_at": "2026-06-13T10:00:00Z" },
    { "payment_id": "5a1c...", "kind": "subscription_charge", "amount": 199000, "status": "succeeded", "created_at": "2026-07-13T10:00:01Z" }
  ],
  "upcoming": ["2026-08-13T10:00:00Z", "2026-09-13T10:00:00Z"]
}

Отменить подписку

POST/v1/public/subscriptions/{id}/cancel
Останавливает будущие списания. Уже проведённые платежи не трогает.
Запрос
curl -X POST https://zergpay.com/v1/public/subscriptions/7f0e.../cancel \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json' \
  -d '{ "reason": "по запросу клиента" }'
Ответ
{ "status": "cancelled" }

Создание подписок по API доступно, если на магазине включён scope рекуррента. Иначе вернётся 403 scope_required.

Рекуррентные токены

Сохраняете способ оплаты и списываете по нему, когда нужно. Подписочную логику стройте на своей стороне. Метод задаётся полем method: cards, sbp или tpay. Карта привязывается верификацией на 1 ₽ без списания. По СБП и T-Pay привязка проходит вместе с первым списанием: передайте amount, он спишется и сразу выпустит токен. Дальше списываете по токену (MIT) и при необходимости отзываете его. PAN и CVV у вас не хранятся, только наш токен.

Как это работает

  1. Создаёте токен через POST /v1/public/tokens (method=cards|sbp|tpay). В ответе приходит pay_url.
  2. Отправляете клиента на pay_url. Он подтверждает привязку: для карты это 3DS и верификация 1 ₽, для СБП и T-Pay это оплата суммы amount.
  3. После успеха токен переходит в active. Списывайте через POST /v1/public/tokens/{id}/charge с нужной суммой, сколько угодно раз.
  4. Чтобы прекратить списания, вызовите POST /v1/public/tokens/{id}/cancel.

Объект Token

ПолеТипОписание
idUUIDИдентификатор сохранённого токена.
customer_refstringВаш идентификатор клиента.
methodenumМетод привязки и списания: cards, sbp, tpay.
statusenumpending, active, cancelled.
card_brandstringБренд карты (Visa, Mastercard, МИР). Для карт, после привязки.
card_maskstringПоследние 4 цифры. Для карт, после привязки.
last_charged_attimeКогда последний раз списывали.

Привязать способ оплаты

POST/v1/public/tokens
Создаёт токен и bind-платёж. Возвращает pay_url для подтверждения привязки. Требует scope api:recurrent:bind.
Тело запроса
customer_refВаш идентификатор клиента. Обязательно.
methodcards (по умолчанию) | sbp | tpay.
amountСумма первого списания в копейках. Обязательна для sbp/tpay (привязка идёт со списанием). Для карт игнорируется (верификация 1 ₽).
customer_emailОпционально.
return_urlURL, на который вернётся покупатель после привязки. Требуется схема https://.
Запрос
curl -X POST https://zergpay.com/v1/public/tokens \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json' \
  -d '{
  "customer_ref": "user_42",
  "customer_email": "user@example.ru",
  "return_url": "https://example.com/account/subscription"
}'
Ответ
{
  "card": {
    "id":           "9a1c...",
    "customer_ref": "user_42",
    "status":       "pending"
  },
  "pay_url": "https://zergpay.com/pay/4f0e..."
}

До подтверждения по pay_url токен в статусе pending; списания доступны только после active.

Списать по токену

POST/v1/public/tokens/{id}/charge
MIT-списание по сохранённому токену (тем же методом, что и привязка). Токен должен быть active. Требует scope api:recurrent:charge.
Тело запроса
amountСумма в минорных единицах (копейки). Обязательно.
order_idВаш идентификатор заказа. Опционально.
descriptionВаше описание платежа. Опционально. В банк не передаётся - назначение единое: «Оплата заказа P-номер».
Запрос
curl -X POST https://zergpay.com/v1/public/tokens/9a1c.../charge \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json' \
  -d '{
  "amount": 199000,
  "order_id": "order-7781",
  "description": "Pro plan"
}'
Ответ
{ "id": "p_55a2...", "status": "succeeded", "amount": 199000 }

Список токенов

GET/v1/public/tokens
Сохранённые токены магазина. Фильтр ?customer_ref= по клиенту.
Запрос
curl -X GET https://zergpay.com/v1/public/tokens?customer_ref=user_42 \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'

Отвязать токен

POST/v1/public/tokens/{id}/cancel
Деактивирует токен, новые списания невозможны. Проведённые платежи не трогает.
Запрос
curl -X POST https://zergpay.com/v1/public/tokens/9a1c.../cancel \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{ "status": "cancelled" }

Токенизация по API доступна, если на магазине включён scope рекуррента (api:recurrent:bind / api:recurrent:charge). Иначе вернётся 403 scope_required.

Возвраты

Возврат - самостоятельный объект, привязанный к платежу. На одном платеже допускается несколько частичных возвратов; когда их сумма достигает amount исходного платежа, его статус становится refunded. На каждый успешный возврат отправляется webhook payment.refunded.

Объект Refund

ПолеТипОписание
idUUIDИдентификатор возврата.
payment_idUUIDПлатёж, по которому сделан возврат.
merchant_idUUIDМерчант. Определяется по API-ключу.
amountint64Сумма возврата в минорных единицах.
reasonstringПричина возврата. Попадает в чек и audit-лог.
statusenumpending → succeeded или failed.
created_attimeКогда возврат был создан.
completed_attimeМомент перехода в финальный статус.
{
  "id":           "9b2c1f8a-1111-2222-3333-444444444444",
  "payment_id":   "5a331a39-32bf-4940-afb1-855e2fc6757f",
  "merchant_id":  "22222222-2222-2222-2222-222222222222",
  "amount":       50000,
  "reason":       "частичный возврат по запросу клиента",
  "status":       "succeeded",
  "created_at":   "2026-05-05T15:10:00Z",
  "completed_at": "2026-05-05T15:10:02Z"
}

Возврат средств

POST/v1/public/payments/{id}/refund
Полный или частичный возврат на платёж в статусе succeeded. Суммарный возврат не может превышать amount исходного платежа. На каждый успешный возврат отправляется webhook payment.refunded.
Тело запроса
amountСумма возврата в минорных единицах. Если поле не передано или равно 0 - возвращается весь остаток: amount − amount_refunded.
reasonПричина возврата. Отображается покупателю в чеке и фиксируется в audit-логе.
Запрос
curl -X POST https://zergpay.com/v1/public/payments/5a331a39-32bf-4940-afb1-855e2fc6757f/refund \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json' \
  -d '{
  "amount": 50000,
  "reason": "частичный возврат по запросу клиента"
}'
Ответ
{
  "id":           "9b2c1f8a-1111-2222-3333-444444444444",
  "payment_id":   "5a331a39-32bf-4940-afb1-855e2fc6757f",
  "merchant_id":  "22222222-2222-2222-2222-222222222222",
  "amount":       50000,
  "reason":       "частичный возврат по запросу клиента",
  "status":       "succeeded",
  "created_at":   "2026-05-05T15:10:00Z"
}

Отдельного эндпоинта получения возврата по id в публичном API нет. Возвраты по конкретному платежу всегда возвращаются в массиве refunds[] ответа GET /v1/public/payments/{id}, а полный реестр возвратов мерчанта - GET /v1/public/refunds (см. раздел «Реестры операций»).

Выплаты

Одна ручка POST /v1/public/payouts, метод выбирается полем method: СБП, на карту или на счёт (РКО). Магазин определяется по API-ключу; режим - по ключу (sk_test_ → симулятор, sk_live_ → реальный банк). Ключу нужен scope соответствующего метода. Финальный статус (succeeded/failed) приходит webhook-ом payout.*. Ниже - три варианта тела запроса.

Выплата по СБП

POST/v1/public/payouts
На номер телефона + member_id банка получателя.
Тело запроса
amountСумма в минорных единицах (копейки). Обязательно.
method"payouts_sbp". Scope: api:payouts:sbp.
phoneТелефон получателя в формате +7XXXXXXXXXX. Обязательно.
bank_idmember_id банка-получателя в реестре НСПК (12 цифр). Например, 100000000111 - Сбербанк. Обязательно. См. «Банки СБП».
full_nameФИО получателя. Банк использует для сверки.
Запрос
curl -X POST https://zergpay.com/v1/public/payouts \
  -H 'Authorization: Bearer sk_live_...' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7f2a-payout-sbp' \
  -d '{
    "amount":    250000,
    "method":    "payouts_sbp",
    "phone":     "+79001234567",
    "bank_id":   "100000000111",
    "full_name": "Иванов Иван Иванович"
  }'
Ответ
{
  "payout": {
    "id":          "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "merchant_id": "22222222-2222-2222-2222-222222222222",
    "shop_id":     "33333333-3333-3333-3333-333333333333",
    "amount":      250000,
    "currency":    "RUB",
    "method":      "payouts_sbp",
    "status":      "pending",
    "recipient": {
      "phone":     "+79001234567",
      "bank_id":   "100000000111",
      "full_name": "Иванов Иван Иванович"
    },
    "created_at":  "2026-05-05T16:01:00Z"
  },
  "mode":     "live",
  "bank":     "Сбер",
  "bank_ref": "PAY2026050601234"
}

Поля failure_reason и idempotent возвращаются при отказе или повторе запроса по Idempotency-Key. В тестовом режиме добавляются служебные поля симулятора - описаны на странице Тестовая среда.

Выплата на карту

POST/v1/public/payouts
На номер карты получателя (OCT).
Тело запроса
amountСумма в минорных единицах (копейки). Обязательно.
method"payouts_card". Scope: api:payouts:card.
card_panНомер карты получателя (16-18 цифр). Обязательно.
full_nameФИО получателя (опционально).
Запрос
curl -X POST https://zergpay.com/v1/public/payouts \
  -H 'Authorization: Bearer sk_live_...' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7f2a-payout-card' \
  -d '{ "amount": 250000, "method": "payouts_card", "card_pan": "2200110033445566" }'
Ответ
{
  "payout": {
    "id":                  "...",
    "amount":              250000,
    "method":              "payouts_card",
    "status":              "pending",
    "recipient_card_mask": "5566",
    "recipient": { }
  },
  "mode":     "live",
  "bank_ref": "PAY2026050609876"
}

В ответе recipient_card_mask - последние 4 цифры карты (для квитанции). Полный номер карты не хранится и не возвращается.

Выплата на счёт (РКО)

POST/v1/public/payouts
На банковский счёт по реквизитам.
Тело запроса
amountСумма в минорных единицах (копейки). Обязательно.
method"payouts_account". Scope: api:payouts:account.
account_numberРасчётный счёт получателя (20 цифр). Обязательно.
bikБИК банка получателя (9 цифр). Обязательно.
innИНН получателя (опционально).
full_nameНаименование получателя. Банк использует для сверки.
Запрос
curl -X POST https://zergpay.com/v1/public/payouts \
  -H 'Authorization: Bearer sk_live_...' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7f2a-payout-acc' \
  -d '{
    "amount":         250000,
    "method":         "payouts_account",
    "account_number": "40817810099910004312",
    "bik":            "044525225",
    "inn":            "771234567890",
    "full_name":      "ООО Ромашка"
  }'

Реестр выплат (пакетно)

POST/v1/public/payouts/batch
Массив items (до 500) одним запросом, в рамках магазина ключа. Не атомарно: валидные строки исполняются, невалидные - с ошибкой в results[]. Метод берётся из строки или из общего method. Проверка суммарного баланса на весь реестр - один раз до исполнения. Idempotency-Key делает повторную отправку того же реестра безопасной (строки-дубли помечаются status=duplicate).
Тело запроса
{
  "method": "payouts_sbp",
  "items": [
    { "amount": 150000, "phone": "+79001234567", "bank_id": "100000000111", "full_name": "Иванов И.И." },
    { "amount": 250000, "phone": "+79007654321", "bank_id": "100000000004", "full_name": "Петров П.П." }
  ]
}
Запрос
curl -X POST https://zergpay.com/v1/public/payouts/batch \
  -H 'Authorization: Bearer sk_live_x9k...' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: reg-2026-05-05-001' \
  -d '{"method":"payouts_sbp","items":[{"amount":150000,"phone":"+79001234567","bank_id":"100000000111","full_name":"Иванов И.И."}]}'
Ответ
{
  "mode":    "live",
  "created": 1,
  "failed":  1,
  "total":   2,
  "results": [
    { "index": 0, "status": "created", "payout_id": "7c1f...", "method": "payouts_sbp", "amount": 150000 },
    { "index": 1, "status": "failed",  "method": "payouts_sbp", "amount": 250000, "code": "recipient_not_in_sbp", "error": "получатель не найден в СБП" }
  ]
}

Каждая строка результата: status = created | failed | duplicate, с payout_id или code/error. Финальные статусы приходят webhook-ами payout.* по каждой созданной выплате.

Статус выплаты

GET/v1/public/payouts/{id}
Возвращает текущее состояние выплаты. Статус проходит pending → succeeded или failed. На финальный статус отправляется webhook payout.succeeded или payout.failed.
Запрос
curl -X GET https://zergpay.com/v1/public/payouts/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "id":            "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "merchant_id":   "22222222-2222-2222-2222-222222222222",
  "shop_id":       "33333333-3333-3333-3333-333333333333",
  "amount":        250000,
  "currency":      "RUB",
  "method":        "payouts_sbp",
  "status":        "succeeded",
  "fail_reason":   "",
  "recipient": {
    "phone":     "+79001234567",
    "bank_id":   "100000000111",
    "full_name": "Иванов Иван Иванович"
  },
  "bank_ref":      "PAY2026050601234",
  "created_at":    "2026-05-05T16:01:00Z",
  "completed_at":  "2026-05-05T16:01:09Z"
}

bank_ref - референс выплаты у провайдера. Для выплаты на карту в ответе также recipient_card_mask (последние 4 цифры карты) - для квитанции.

Баланс

Текущий баланс мерчанта: общий, доступный к выплате и разбивка по магазинам. Только чтение, требуется scope api:balance:read. Все суммы - в минорных единицах (копейки).

Получить баланс

GET/v1/public/balance
Общий баланс, доступный баланс (за вычетом сумм, зарезервированных под ожидающие выплаты и возмещения) и остаток по каждому магазину мерчанта.
Ответ
ПолеТипОписание
balanceint64Общий баланс мерчанта в минорных единицах.
availableint64Доступно к выплате: баланс минус резервы под pending-выплаты и возмещения.
currencystringВалюта (ISO 4217), сейчас RUB.
shops[]arrayРазбивка баланса по магазинам.
shops[].shop_idUUIDИдентификатор магазина.
shops[].shop_namestringНазвание магазина.
shops[].balanceint64Баланс магазина в минорных единицах.
Запрос
curl -X GET https://zergpay.com/v1/public/balance \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "balance":   172150,
  "available": 172150,
  "currency":  "RUB",
  "shops": [
    { "shop_id": "1d8243bb-...", "shop_name": "shop-one",  "balance": 122150 },
    { "shop_id": "6a9b6b58-...", "shop_name": "shop-two",  "balance":  50000 }
  ]
}

Выплату нельзя создать на сумму больше available - доступный баланс уже учитывает средства, зарезервированные под ещё не завершённые выплаты.

Реестры операций

Списки платежей, выплат и возвратов. Только чтение, требуется scope api:reports:read. Реестры жёстко изолированы по магазину: ключ видит операции только своего магазина, даже если у мерчанта их несколько.

Пагинация и фильтры

Курсорная пагинация: ответ содержит массив items и next_cursor. Для следующей страницы передайте cursor=<next_cursor>. Когда next_cursor = null - страниц больше нет. Общие query-параметры:

ПараметрТипОписание
limitintРазмер страницы, 1...200. По умолчанию 50.
cursorstringКурсор следующей страницы (next_cursor из предыдущего ответа).
statusstringФильтр по статусу. Можно несколько через запятую.
fromdateНачало периода (YYYY-MM-DD), включительно.
todateКонец периода (YYYY-MM-DD), включительно.

Реестр платежей

GET/v1/public/payments
Список входящих платежей магазина, новые сверху. По умолчанию тестовые платежи скрыты для боевых ключей (include_test=1 - показать).
Query-параметры
include_test1 - включить тестовые платежи в выдачу (для sk_live_ по умолчанию скрыты).
Запрос
curl -X GET https://zergpay.com/v1/public/payments?status=succeeded&limit=20 \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "items": [
    {
      "id":         "5a331a39-32bf-4940-afb1-855e2fc6757f",
      "order_id":   "order-1024",
      "amount":     150000,
      "currency":   "RUB",
      "method":     "sbp",
      "status":     "succeeded",
      "created_at": "2026-05-05T15:00:00Z"
    }
  ],
  "next_cursor": "MTcxNTAw..."
}

Реестр выплат

GET/v1/public/payouts
Список выплат магазина, новые сверху.
Query-параметры
methodФильтр по методу: payouts_sbp | payouts_card | payouts_account.
Запрос
curl -X GET https://zergpay.com/v1/public/payouts?status=succeeded&limit=20 \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "items": [
    {
      "id":         "7c1f...",
      "shop_id":    "1d8243bb-...",
      "amount":     50000,
      "currency":   "RUB",
      "method":     "payouts_sbp",
      "status":     "succeeded",
      "bank_ref":   "10293847",
      "created_at": "2026-05-05T16:00:00Z"
    }
  ],
  "next_cursor": null
}

Реестр возвратов

GET/v1/public/refunds
Список возвратов магазина, новые сверху.
Запрос
curl -X GET https://zergpay.com/v1/public/refunds?limit=20 \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "items": [
    {
      "id":         "9b2c1f8a-...",
      "payment_id": "5a331a39-...",
      "amount":     50000,
      "reason":     "возврат по запросу клиента",
      "status":     "succeeded",
      "created_at": "2026-05-05T15:10:00Z"
    }
  ],
  "next_cursor": null
}

Все суммы - в минорных единицах (копейки). Время - UTC (ISO 8601). Каждый реестр отдаёт операции только того магазина, к которому привязан ключ; для другого магазина используйте его ключ. Общий баланс по всем магазинам - в разделе «Баланс».

Банки СБП

Поле bank_id в POST /payouts - это member_id участника НСПК (12 цифр). Полный реестр ведёт НСПК; мы зеркалим его через интеграцию с Банком 131 и отдаём одним списком.

Справочник банков СБП

GET/v1/public/banks/sbp
Полный реестр участников СБП с member_id и названиями на русском и английском. Синхронизируется с реестром НСПК через bank131. Подходит для рендера выпадающего списка в форме выплаты.
Запрос
curl -X GET https://zergpay.com/v1/public/banks/sbp \
  -H 'Authorization: Bearer sk_test_x9k...' \
  -H 'Content-Type: application/json'
Ответ
{
  "items": [
    { "member_id": "100000000004", "name": "Тинькофф Банк", "name_en": "T-Bank" },
    { "member_id": "100000000005", "name": "ВТБ",            "name_en": "VTB" },
    { "member_id": "100000000007", "name": "Альфа-Банк",     "name_en": "Alfa-Bank" },
    { "member_id": "100000000111", "name": "Сбербанк",       "name_en": "Sberbank" },
    // ... и так весь реестр НСПК (~200 участников), отсортирован по name
  ]
}

Если нужного банка нет в списке

Справочник - список для UI, не allow-list. Принимается любой member_id из официального реестра НСПК; ограничения нет, валидация проходит на стороне банка-получателя.

Валидация на стороне платформы

  • bank_id не из 12 цифр - 400 bad_request возвращается до отправки в банк.
  • member_id формально корректен, но в НСПК отсутствует - банк-эквайер вернёт отказ, операция перейдёт в failed с failure_code do_not_honor или bank_unknown, либо запрос отдаст 502 router_error.