Сценарий: регулярные платежи
Контракт — разовое согласие абонента, после которого списания идут без подтверждения PIN на каждый платёж. Абонент подтверждает один раз, дальше вы создаёте инвойсы со ссылкой на контракт.
- Создайте контракт:
POST /contractsсcustomerиmerchant_contract_id. Ответ —201сcontract_id,authorization_typeиexpires_at, поляstatusв нём нет. - Подтвердите его:
POST /contracts/{contract_id}/authorizeс"pin_code": "1234". Ответ —contract_idиstatus: active, следом приходит коллбекcontract..authorized - Списывайте по контракту: обычный
POST /invoices, но с блокомcontract: {"merchant_contract_id": "…"}. PIN на этом шаге не запрашивается. - Проверьте исход: при
SuccessSequencePaymentв песочной ручке инвойс придёт вProcessed/PAID, приFailedSequencePayment— неуспешная транзакция (см. «Песочные ручки»). В коллбекеpayment.исход читается изupdated invoice.,status invoice.иpayment_status transaction.; в прежнем конверте (status payment./completed payment.) заданное значение приходит ещё и полемfailed billing_result. - Закройте контракт, когда подписка кончилась:
POST /contracts/{contract_id}/cancelс пустым телом. Ответ —status: cancelled, следом коллбекcontract..closed
Где merchant_contract_id — зависит от метода. В POST /contracts он лежит на верхнем уровне тела, а в POST /invoices — внутри блока contract. Мок тело не валидирует: положив поле не туда, вы получите 201 и пустое значение в эхо-полях ответа.
Песочница хранит мобильные контракты, как прод: повторный merchant_contract_id получит 409, действия с неизвестным или отменённым контрактом — 404 CONTRACT_NOT_FOUND (см. «Ошибки JSON v3: HTTP-коды»). Блок authorization в ответе приходит даже для списания по контракту — это особенность мока, а не требование подтвердить платёж. Подробности — в «Отличиях Sandbox ↔ Production».
// POST /api/v3/projects/1001/contracts
{
"customer": { "type": "mobile_phone", "msisdn": "79600000000" },
"merchant_contract_id": "CONTRACT-599160" // верхний уровень!
}
// 201 Created
{
"success": true,
"data": {
"contract_id": "85ff8da2-2b75-44f9-b012-49927da62fde",
"authorization_type": "SMS_PIN",
"expires_at": "2026-09-21T12:00:00Z",
"merchant_contract_id": "CONTRACT-599160",
"customer": { "type": "mobile_phone", "msisdn": "79600000000" }
}
}// POST /contracts/{contract_id}/authorize
{ "pin_code": "1234" }
// 200 OK → { "contract_id": "85ff8da2-…", "status": "active" }
// коллбек (фрагмент):
{
"type": "contract.authorized",
"data": {
"customer": { "type": "mobile_phone", "msisdn": "79600000000" },
"contract": {
"contract_id": "85ff8da2-…",
"merchant_contract_id": "CONTRACT-599160"
}
}
}// POST /api/v3/projects/1001/invoices
{
"customer": { "type": "mobile_phone", "msisdn": "79600000000" },
"order": {
"merchant_order_id": "SEQ-a9e56f",
"price": { "amount": "199.00", "currency": "RUB", "vat_included": true }
},
"contract": { "merchant_contract_id": "CONTRACT-599160" }, // внутри contract!
"test_info": { "expected_billing_result": "SuccessSequencePayment" }
}{
"type": "payment.updated",
"data": {
"invoice": {
"invoice_id": "efa72de6-…",
"merchant_order_id": "SEQ-a9e56f",
"status": "Processed",
"payment_status": "PAID"
},
"transaction": { "status": "SUCCESS", "result_code": 0 }
// фрагмент: customer и остальные поля transaction опущены
}
}