Создать инвойс
JSON API v3
POST /api/v3/projects/{projectId}/invoices
Создаёт новый инвойс для абонента. Поддерживаются оба сценария оплаты — мобильный
телефон (DCB) и банковская карта; тип клиента выбирается через customer..
Для пары (проект, клиент) допускается только один активный инвойс. Если активный
инвойс уже существует, платформа возвращает 409 Conflict с error.code = INVOICE_ALREADY_EXISTS
и error., указывающим на существующую запись.
Payload подписи v4:
{order.merchant_order_id}{customerPayload}{order.price.amount}{order.price.currency}{contract.merchant_contract_id}{client_ip}
Песочная настройка 3-D Secure (card_3ds_enabled). У карточного инвойса
authorization. ведёт на форму ввода реквизитов; страница подтверждения после неё
включается на проекте (Admin UI, по умолчанию включена) — в бою челлендж тоже
включается индивидуально. Со снятой настройкой платёж проводится сразу после отправки
реквизитов, форма карты остаётся. На состав ответа настройка не влияет, разница
только в числе экранов у плательщика. СБП челленджа не имеет, а зарезервированные
окончания карты 0001–0005 работают в обоих режимах — это эмуляция отказа эквайера.
Параметры запроса
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
projectId | integer (int32) | да |
Тело запроса
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
client_ip | string | — | IP-адрес, с которого клиент выполняет запрос. Обязателен по умолчанию (настраивается на уровне проекта). |
customer | object | — | Полиморфный блок клиента. Фактический набор полей зависит от type: - mobile_phone: msisdn, email - bank_card: source, country, merchant_customer_id, email и — только на хосте контура PCI DSS — bank_card с реквизитами карты - undefined_bank_card: те же поля, что у bank_card, без реквизитов Как выбрать между карточными типами. Это разные платёжные маршруты, поэтому тип указывается явно и никогда не выводится из других полей: - undefined_bank_card — плательщик вводит карту на платёжной странице; - bank_card — реквизиты собирает мерчант (контур PCI DSS) либо списание идёт по контракту. |
customer. | mobile_phone · bank_card · undefined_bank_card | — | |
customer. | string | — | MSISDN абонента в международном формате E.164 (без +). Обязателен для mobile_phone. |
customer. | string (email) | — | Email клиента |
customer. | string | — | Код страны (ISO 3166-1 alpha-2). Обязателен для bank_card. |
customer. | object | — | |
customer. | integer (int32) | — | ID сети (см. справочник операторов) |
customer. | string | — | |
customer. | object | — | |
customer. | integer (int32) | — | ID оператора (см. справочник операторов) |
customer. | string | — | |
customer. | string | — | Имя источника в системе продавца (уникально в рамках партнёра). Обязателен для bank_card. |
customer. | string | — | Уникальный ID клиента в системе продавца. Обязателен для bank_card. |
customer. | object | — | |
order | object | — | |
order. | string | — | ID заказа в системе продавца. Должен быть уникальным. |
order. | object | — | Денежная сумма с валютой. Используется для цен, вознаграждений и итогов. |
order. | string | — | Десятичное число с фиксированной точкой в виде строки (два знака после точки). Строка используется, чтобы избежать ошибок округления чисел с плавающей точкой. |
order. | string | — | Код валюты платежа (ISO 4217). |
order. | boolean | — | Включён ли НДС в сумму. |
order. | string | — | Текстовое описание заказа |
order. | object | — | Дополнительные параметры счёта — произвольные пары «имя — значение» (JSON-эквивалент блока <AdditionalParameters> из XML API). Через них передаются служебные флаги обработки, например NeedSendNotification, и собственные метки продавца. Имена нечувствительны к регистру и должны быть уникальны: Flag и flag в одном объекте — ошибка запроса (400 BAD_REQUEST), а не два параметра. Блок принимают создание счёта (внутри order), а также авторизация, отмена и возврат (на верхнем уровне тела): переданные значения дописываются к уже сохранённым у счёта, совпадающие по имени — перезаписываются. |
contract | object | — | Необязательный блок контракта: позволяет привязать счёт к существующему контракту или создать контракт заодно со счётом. |
contract. | boolean | null | — | Если true, проект поддерживает контрактную схему и у клиента нет контракта — будет создан новый контракт. |
contract. | string | — | ID контракта в системе продавца. Уникален в рамках одного клиента. |
application | object | — | |
application. | string | — | Название приложения (например, игра или приложение, где пользователь совершает покупки) |
application. | boolean | — | Пометка «подписной» платёж. Сохраняется у счёта и используется в отчётности; сама по себе списаний по расписанию не создаёт. В песочнице видна на странице «Инвойсы» Admin UI. |
product | object | — | |
product. | string | — | Название продукта — за что именно заплатил пользователь |
payment_method | sbp · sberpay_desktop · sberpay_mobile | — | Только песочница. Deprecated. Способ оплаты выбирает плательщик — параметрами к authorization. (см. описание этого поля). Селектор в теле был в редакции спеки от мая 2026 и платформой снят. Поле принимается ещё одну minor-версию, снятие — в 3.0.0. Переданное значение не меняет ответ по составу: песочница отдаёт тот же authorization., но с уже дописанными параметрами, — то есть каноническую ссылку, на которую и нужно перейти: - (не указан) — форма карты, адрес без параметров - sbp — ?useSbp=true - sberpay_desktop — ?payType=Sber&deviceType=Desktop - sberpay_mobile — ?payType=Sber&deviceType=Mobile SberPay и СБП песочница не различает — оба сводятся к QR-флоу, отличается только экран, выбранный по deviceType. Значение вне перечисленных отвергается 422 INVALID_PAYMENT_METHOD, а не игнорируется молча. |
test_info | object | — | Только песочница. Блок управляет поведением мока и в продакшне отсутствует — при переходе на прод его достаточно удалить целиком, остальное тело менять не нужно. |
test_info. | Success · Failed · SuccessSequencePayment · FailedSequencePayment | — | Желаемый исход тарификации. Failed* даёт коллбек с payment_status: NOT_PAID и result_code: 210 (PAYMENT_CHANNEL_NOT_ENOUGH_MONEY), а GET /invoices/{invoice_id} начинает отдавать status: failed. Неизвестное значение игнорируется, используется Success. |
test_info. | integer (по умолчанию 10) | — | Пауза перед первой попыткой отправки коллбека. 0 — отправить в ближайшем цикле воркера. С этого же момента GET /invoices/{invoice_id} показывает исход тарификации. Значение вне диапазона игнорируется. |
test_info. | 403 · 500 · 503 | — | Попросить песочницу ответить отказом инфраструктуры — чтобы проверить, как ваш код их переживает. Предлагаются только три статуса, которые иначе воспроизвести нечем: 403 требует проекта с whitelist IP, 503 — мёртвого сервера заготовок, 500 — необработанного исключения. Всё остальное (400, 401, 404, 409, 422) достижимо обычным сценарием и через эту ручку не выдаётся. Отказ возвращается до создания чего бы то ни было: счёт не появляется и клиент не занимается дедупликацией. Тело — той же формы, что у настоящего отказа, включая next_step. Неизвестное значение игнорируется. |
test_info. | string (uri) | — | Адрес, на который уйдут коллбеки по этому инвойсу или контракту, вместо настроенного у проекта. Доступно не всем: партнёру должен быть выставлен флаг «Разрешить test_info.callback_url» в Admin UI, а его логин и секрет не должны быть публичными. Для демо-кред из раздела «Доступ» поле отклоняется с TEST_CALLBACK_URL_FORBIDDEN. Адрес проверяется дважды — при приёме запроса и повторно перед отправкой: разрешён только https, хост резолвится и проверяется итоговый IP, приватные и служебные диапазоны (10/8, 172.16/12, 192.168/16, 127/8, 169.254/16, ::1, fc00::/7) запрещены, редиректы не выполняются, таймаут доставки — 5 секунд. |
{
"client_ip": "10.20.30.40",
"customer": {
"type": "mobile_phone",
"msisdn": "79600000000",
"email": "test@test.com"
},
"order": {
"merchant_order_id": "order_123",
"price": {
"amount": "25.00",
"currency": "RUB",
"vat_included": true
},
"description": "Premium subscription"
},
"contract": {
"create_if_not_exists": false,
"merchant_contract_id": "1234567890"
},
"application": {
"name": "Game of Sultans"
},
"product": {
"name": "New Pack_1"
}
}{
"client_ip": "10.20.30.40",
"customer": {
"type": "undefined_bank_card",
"source": "my_app",
"country": "RU",
"merchant_customer_id": "client_12345",
"email": "test@test.com"
},
"order": {
"merchant_order_id": "order_456",
"price": {
"amount": "20.00",
"currency": "RUB",
"vat_included": true
}
}
}{
"client_ip": "10.20.30.40",
"customer": {
"type": "bank_card",
"source": "my_app",
"country": "RU",
"merchant_customer_id": "client_12345",
"email": "test@test.com",
"bank_card": {
"pan": "4111111111111111",
"expiration_month": "12",
"expiration_year": "2030",
"security_code": "123",
"cardholder": "IVAN IVANOV"
}
},
"order": {
"merchant_order_id": "order_456",
"price": {
"amount": "20.00",
"currency": "RUB",
"vat_included": true
}
},
"contract": {
"create_if_not_exists": true,
"merchant_contract_id": "1234567890"
}
}{
"client_ip": "10.20.30.40",
"customer": {
"type": "undefined_bank_card",
"source": "my_app",
"country": "RU",
"merchant_customer_id": "client_12345"
},
"order": {
"merchant_order_id": "order_789",
"price": {
"amount": "100.00",
"currency": "RUB",
"vat_included": true
}
},
"payment_method": "sbp"
}{
"client_ip": "10.20.30.40",
"customer": {
"type": "undefined_bank_card",
"source": "my_app",
"country": "RU",
"merchant_customer_id": "client_12345",
"email": "test@test.com"
},
"order": {
"merchant_order_id": "order_456",
"price": {
"amount": "20.00",
"currency": "RUB",
"vat_included": true
}
}
}{
"client_ip": "127.0.0.1",
"customer": {
"type": "undefined_bank_card",
"source": "app",
"country": "RU",
"merchant_customer_id": "CUSTOMER-000000001"
},
"order": {
"merchant_order_id": "ORDER-000000001",
"price": {
"amount": "100.00",
"currency": "RUB",
"vat_included": true
},
"description": "Remote test order"
},
"application": {
"name": "Test App"
},
"product": {
"name": "Test Pack"
},
"contract": {
"create_if_not_exists": true,
"merchant_contract_id": "CONTRACT-000000001"
}
}{
"client_ip": "127.0.0.1",
"customer": {
"type": "mobile_phone",
"msisdn": "79600000000"
},
"order": {
"merchant_order_id": "ORDER-000000001",
"price": {
"amount": "100.00",
"currency": "RUB",
"vat_included": true
},
"description": "Remote test order"
},
"application": {
"name": "Test App"
},
"product": {
"name": "Test Pack"
},
"test_info": {
"force_http_status": 403
}
}{
"client_ip": "127.0.0.1",
"customer": {
"type": "mobile_phone",
"msisdn": "79600000000"
},
"order": {
"merchant_order_id": "ORDER-000000001",
"price": {
"amount": "100.00",
"currency": "RUB",
"vat_included": true
},
"description": "Remote test order"
},
"application": {
"name": "Test App"
},
"product": {
"name": "Test Pack"
},
"test_info": {
"force_http_status": 500
}
}{
"client_ip": "127.0.0.1",
"customer": {
"type": "mobile_phone",
"msisdn": "79600000000"
},
"order": {
"merchant_order_id": "ORDER-000000001",
"price": {
"amount": "100.00",
"currency": "RUB",
"vat_included": true
},
"description": "Remote test order"
},
"application": {
"name": "Test App"
},
"product": {
"name": "Test Pack"
}
}{
"client_ip": "127.0.0.1",
"customer": {
"type": "mobile_phone",
"msisdn": "79600000000"
},
"order": {
"merchant_order_id": "ORDER-000000001",
"price": {
"amount": "100.00",
"currency": "RUB",
"vat_included": true
},
"description": "Remote test order"
},
"application": {
"name": "Test App"
},
"product": {
"name": "Test Pack"
},
"test_info": {
"force_http_status": 503
}
}{
"order_id": "x"
}{
"success": true,
"data": {
"invoice_id": "0d0f3c58-9b1e-4a77-9a0c-000000000001",
"status": "Created",
"merchant_order_id": "ORDER-000000001",
"price": {
"amount": "100.00",
"currency": "RUB",
"vat_included": true
},
"created_at": "2026-09-21T12:00:00Z",
"payment_status": "NOT_PAID",
"customer": {
"type": "mobile_phone",
"msisdn": "7960***0000"
},
"authorization": {
"type": "SMS_PIN",
"is_authorized": false
},
"billing_channel": "MC",
"expires_at": "2026-09-21T12:00:00Z"
}
}Коды ответов
| Код | Описание |
|---|---|
201 | Инвойс создан |
400 | Ошибка валидации или бизнес-ошибка запроса |
401 | Ошибка аутентификации (отсутствует/неверна подпись или временная метка) |
403 | Доступ к проекту запрещён или IP не в белом списке |
409 | У клиента уже существует активный инвойс |
422 | Ошибка бизнес-валидации |
500 | Непредвиденная ошибка платформы |
503 | Сервис временно недоступен |