Skip to Content

Quick start

Five requests from zero to a paid invoice, on demo credentials, with no sign-up. The examples use XML Merchant API v2.9. JSON v3 equivalents are in the method sections below: both protocols are production protocols, the choice is yours.

Flow diagram
Merchant Callisto (sandbox) Subscriber │ │ │ │ 1. CreateInvoice ─────────────►│ │ │◄─── InvoiceID + SMS_PIN ───────│ ~~~ SMS with PIN ~~~~~~~~~►│ │ │ (not sent in sandbox) │ │ 2. AuthorizeInvoice(PIN) ─────►│◄── subscriber tells PIN ───│ │◄─── ResultCode=0 ──────────────│ │ │ │ │ │ 3. GetInvoice ────────────────►│ carrier-side billing │ │◄─── Processed / PAID ──────────│ │ │ │ │ │◄── SendPaymentTransaction ─────│ callback, arrives on its own
  1. Take the credentials. In the sandbox these are the public demo credentials from “Access and test data”; no sign-up is needed, and the credentials are shared by everyone who opens this page.
  2. Compute the signature. Every request needs one, and it lives in <Header><Authentication>. The formula and a walkthrough are in “Request signing”.
  3. Create an invoice with CreateInvoice. The <TestInfo> block is sandbox-only: ExpectedBillingResult=Success forces successful billing and CallbackDelaySeconds=0 removes the callback delay. The response carries an InvoiceID — keep it.
  4. Confirm the invoice with AuthorizeInvoice and <AuthorizeInfo><PinCode>1234</PinCode></AuthorizeInfo>. The sandbox sends no SMS and the PIN is fixed. The response is ResultCode=0 with an empty <AuthorizeInvoiceResponse />.
  5. Check the status with GetInvoice. Right after confirmation you get Active / NOT_PAID — the sandbox simulates billing time. Repeat the request after 6 seconds to get Processed / PAID.
  6. Wait for the callback. SendPaymentTransaction is sent to the project callback URL on its own — you do not need to request it. Details and the retry policy are in “Callbacks”.
  7. Next: paying by bank card and via SBP, sandbox knobs for emulating failures, and the differences from production — see the corresponding sections.

The sandbox stores your invoice: GetInvoice returns the same MerchantOrderID, MSISDN and amount you sent. Only sandbox constants such as OperatorID come from templates — see “Sandbox ↔ Production differences”.

Step 2 — signature (bash)

NOW and SIG go into the <Header> of every request
LOGIN=demo_login SECRET=demo_password NOW=$(date -u +%Y%m%d%H%M%S) INNER=$(printf '%s' "$NOW" | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d' ' -f1) SIG=$(printf '%s' "$LOGIN$INNER" | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d' ' -f1)

Step 3 — CreateInvoice

curl -X POST \ https://pay-sandbox.digitalspb.com/API/XML/InvoiceManagementService.ashx \ -H "Content-Type: text/xml; charset=utf-8" \ --data-binary '<?xml version="1.0" encoding="utf-8"?> <Request> <Header> <Authentication> <Login>'"$LOGIN"'</Login> <NowUtc>'"$NOW"'</NowUtc> <Signature>'"$SIG"'</Signature> </Authentication> </Header> <CreateInvoiceRequest> <ProjectID>1001</ProjectID> <MobilePhoneCustomer><MSISDN>79600000000</MSISDN></MobilePhoneCustomer> <InvoiceInfo> <MerchantOrderID>QS-DEMO-1042</MerchantOrderID> <CustomerPrice amount="99.00" currency="RUB" includingVAT="true"/> </InvoiceInfo> <!-- sandbox knobs, absent in production --> <TestInfo> <ExpectedBillingResult>Success</ExpectedBillingResult> <CallbackDelaySeconds>0</CallbackDelaySeconds> </TestInfo> </CreateInvoiceRequest> </Request>'
Response — keep the InvoiceID
<Response> <CreateInvoiceResponse> <InvoiceInfo> <InvoiceStatus>Created</InvoiceStatus> <PaymentStatus>NOT_PAID</PaymentStatus> <AuthorizationType>SMS_PIN</AuthorizationType> <InvoiceID>8e3b885b-b51a-46d2-835d-7b77b3d5cca7</InvoiceID> <MerchantOrderID>QS-DEMO-1042</MerchantOrderID> </InvoiceInfo> <BillingInfo><BillingChannel>MC</BillingChannel></BillingInfo> </CreateInvoiceResponse> <ResultCode>0</ResultCode> </Response>

Step 4 — AuthorizeInvoice

Recompute the signature: NowUtc is new
<AuthorizeInvoiceRequest> <ProjectID>1001</ProjectID> <InvoiceInfo> <InvoiceID>8e3b885b-b51a-46d2-835d-7b77b3d5cca7</InvoiceID> </InvoiceInfo> <AuthorizeInfo> <PinCode>1234</PinCode> </AuthorizeInfo> </AuthorizeInvoiceRequest> <!-- response --> <Response> <AuthorizeInvoiceResponse /> <ResultCode>0</ResultCode> <ResultDescription>OK</ResultDescription> </Response>

Step 5 — GetInvoice

<GetInvoiceRequest> <ProjectID>1001</ProjectID> <InvoiceInfo> <InvoiceID>8e3b885b-b51a-46d2-835d-7b77b3d5cca7</InvoiceID> </InvoiceInfo> </GetInvoiceRequest> <!-- right after AuthorizeInvoice --> <InvoiceStatus>Active</InvoiceStatus> <PaymentStatus>NOT_PAID</PaymentStatus> <!-- the same request 6 seconds later --> <InvoiceStatus>Processed</InvoiceStatus> <PaymentStatus>PAID</PaymentStatus>

Step 6 — callback, arrives on its own

<Request> <Header><RequestID>bae26b7d-…</RequestID><RequestAttempt>1</RequestAttempt></Header> <SendPaymentTransaction> <InvoiceID>8e3b885b-b51a-46d2-835d-7b77b3d5cca7</InvoiceID> <MerchantOrderID>QS-DEMO-1042</MerchantOrderID> <Status>Success</Status> <BillingResult>Success</BillingResult> <PaymentStatus>SUCCESS</PaymentStatus> <Amount>99.00</Amount><Currency>RUB</Currency> </SendPaymentTransaction> </Request>