Skip to Content
One-time paymentsMethod reference JSON + XMLCreate invoice

Create invoice

POST /api/v3/projects/{projectId}/invoices

Creates a new invoice for a customer. Supports both mobile phone (DCB) and bank card payment flows; the customer type is selected via customer.type.

Only one active Invoice per (project, customer) is allowed. If an active Invoice already exists, the platform returns 409 Conflict with error.code = INVOICE_ALREADY_EXISTS and error.details.invoice_id referring to the existing record.

v4 signature payload: {order.merchant_order_id}{customerPayload}{order.price.amount}{order.price.currency}{contract.merchant_contract_id}{client_ip}

Sandbox 3-D Secure setting (card_3ds_enabled). For a card invoice authorization.url points at the card-details form; the confirmation page shown after it is a per-project setting (Admin UI, on by default) — in production the challenge is enabled per integration too. With the setting off the payment is settled right after the details are submitted, and the card form stays. The response payload is unaffected — the only difference is the number of screens the payer sees. SBP has no challenge, and reserved card endings 0001–0005 work in both modes: they emulate an acquirer decline.

Request parameters

FieldTypeRequiredDescription
projectIdinteger (int32)yes

Request body

FieldTypeRequiredDescription
client_ipstring—IP address from which the customer makes the request. Required by default (configurable per project).
customerobject—Polymorphic customer block. The actual subset of fields depends on type: - mobile_phone: msisdn, email - bank_card: source, country, merchant_customer_id, email, and — on the PCI DSS contour host only — bank_card with the card details - undefined_bank_card: same fields as bank_card, minus the card details Choosing between the two card types. They are different payment routes, so the type is always stated explicitly — it is never inferred from other fields: - undefined_bank_card — the payer enters the card on the payment page opened by authorization.url. The card is not bound, contracts are not supported. - bank_card — the card is bound to a contract and can be charged again later. Requires approved bank card settings for the project and the payer’s country; on the PCI DSS contour the card details are sent with the request.
customer.typemobile_phone · bank_card · undefined_bank_card—
customer.msisdnstring—Customer’s MSISDN in international E.164 format (no +). Required for mobile_phone.
customer.emailstring (email)—Customer’s email
customer.countrystring—Country code (ISO 3166-1 alpha-2). Required for bank_card.
customer.networkobject—
customer.network.idinteger (int32)—Network ID (see operators reference)
customer.network.namestring—
customer.operatorobject—
customer.operator.idinteger (int32)—Operator ID (see operators reference)
customer.operator.namestring—
customer.sourcestring—Source name in the merchant’s system (unique per partner). Required for bank_card.
customer.merchant_customer_idstring—Unique customer ID in the merchant’s system. Required for bank_card.
customer.bank_cardobject—
orderobject—
order.merchant_order_idstring—Order ID in the merchant’s system. Must be unique.
order.priceobject—Monetary amount with currency. Used for prices, profits and totals.
order.price.amountstring—Fixed-point decimal as string (two digits after the dot). String is used to avoid floating-point rounding.
order.price.currencystring—Payment currency code (ISO 4217).
order.price.vat_includedboolean—Whether the amount includes VAT.
order.descriptionstring—Order description text
order.additional_parametersobject—Arbitrary invoice parameters stored with the invoice, the JSON counterpart of the XML <AdditionalParameters>/<Parameter name= value=/> block. Parameter names are case-insensitive and must be unique. On cancel/refund/authorize the given values are merged into the ones already stored: names that match are overwritten, the rest are kept.
contractobject—Optional contract block used during invoice creation to associate or create a contract along with the invoice.
contract.create_if_not_existsboolean | null—If true and the project supports contract scheme and customer has no contract — a new contract will be created.
contract.merchant_contract_idstring—The ID of the contract in the merchant’s system. Unique within a single customer identity.
applicationobject—
application.namestring—Application name (e.g. game or app where the user makes purchases)
application.is_subscriptionboolean—Marks the payment as a subscription one. It is stored with the invoice and used in reporting; on its own it never creates scheduled charges. In the sandbox the flag is shown on the Admin UI “Invoices” page.
productobject—
product.namestring—Product name — what exactly the user paid for
payment_methodsbp · sberpay_desktop · sberpay_mobile—Sandbox only. Deprecated. The payer picks the payment method through parameters appended to authorization.url (see that field). The body selector comes from the May 2026 revision of the spec and has been dropped by the platform. The field is still accepted for one more minor version; removal is 3.0.0. A value does not change the shape of the response: the sandbox returns the same authorization.url with the parameters already appended — that is, the canonical link to follow: - (omitted) — card form, no parameters - sbp — ?useSbp=true - sberpay_desktop — ?payType=Sber&deviceType=Desktop - sberpay_mobile — ?payType=Sber&deviceType=Mobile The sandbox does not tell SberPay and SBP apart — both boil down to a QR flow, only the screen chosen by deviceType differs. A value outside the list is rejected with 422 INVALID_PAYMENT_METHOD instead of being silently ignored.
test_infoobject—Sandbox only. This block controls mock behaviour and does not exist in production — when switching to production simply drop it entirely, the rest of the body stays the same.
test_info.expected_billing_resultSuccess · Failed · SuccessSequencePayment · FailedSequencePayment—Desired billing outcome. Failed* produces a callback with payment_status: NOT_PAID and result_code: 210 (PAYMENT_CHANNEL_NOT_ENOUGH_MONEY), and GET /invoices/{invoice_id} starts returning status: failed. An unknown value is ignored and Success is used.
test_info.callback_delay_secondsinteger (default 10)—Delay before the first callback delivery attempt. 0 means deliver on the next worker cycle. From that moment GET /invoices/{invoice_id} also reflects the billing outcome. Values outside the range are ignored.
test_info.force_http_status403 · 500 · 503—Ask the sandbox to answer with an infrastructure failure, so that your error handling can be exercised. Only the three statuses that are otherwise impossible to reproduce are offered: 403 needs a project with an IP whitelist, 503 a dead stub server, 500 an unhandled exception. Everything else (400, 401, 404, 409, 422) is reachable through the normal scenario and is not available here. The refusal is returned before anything is created: no invoice appears and the customer is not taken by deduplication. The body has the same shape as a real failure, next_step included. An unknown value is ignored.
test_info.callback_urlstring (uri)—Address that callbacks for this invoice or contract are sent to, instead of the one configured for the project. Not available to everyone: the partner must have the “Allow test_info.callback_url” flag set in the Admin UI, and its login and secret must not be public. For the demo credentials from the “Access” section the field is rejected with TEST_CALLBACK_URL_FORBIDDEN. The address is validated twice — when the request is accepted and again right before delivery: https only, the host is resolved and the resulting IP is checked, private and reserved ranges (10/8, 172.16/12, 192.168/16, 127/8, 169.254/16, ::1, fc00::/7) are rejected, redirects are not followed, delivery timeout is 5 seconds.
Request example — Mobile phone (DCB)
{ "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" } }
Request example — Bank card entered on the payment page
{ "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 } } }
Request example — Bank card with card details (PCI DSS contour host only)
{ "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" } }
Request example — SBP (QR)
{ "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" }
Request example — Bank card
{ "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 } } }
Request example — Invoices_Create / contract_with_undefined_card (HTTP 400)
{ "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" } }
Request example — Invoices_Create / forbidden (HTTP 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": 403 } }
Request example — Invoices_Create / internal_error (HTTP 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" }, "test_info": { "force_http_status": 500 } }
Request example — Invoices_Create / mobile_phone (HTTP 201)
{ "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" } }
Request example — Invoices_Create / unavailable (HTTP 503)
{ "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 } }
Request example — Invoices_Create / unsigned (HTTP 401)
{ "order_id": "x" }
Response example
{ "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" } }

Response codes

CodeDescription
201Invoice created
400Validation or business request error
401Authentication failed (missing/invalid signature or timestamp)
403Project access denied or IP not whitelisted
409Active invoice already exists for the customer
422Business validation error
500Unexpected platform error
503Service temporarily unavailable