Sandbox ↔ Production differences
The sandbox reproduces the production service contract — method addresses, request structure, signing and response format — but not subscription billing itself. Everything that behaves differently is collected below, so that it does not surface in production instead.
| Area | How the sandbox behaves |
|---|---|
| Money and SMS | No charges happen and no SMS is sent — neither the PIN on CreateSubscription nor the repeat on ResendPinCode |
| Subscription state | Stored. The SubscriptionID from CreateSubscription is reused by every other method and the status changes as the scenario progresses. A repeated CreateSubscription for the same number is rejected with SubscriptionAlreadyCreated, as in production |
| Service failures | Reproduced by reserved number endings (0001…0003), a wrong PIN and “failing cards” — see “Failures and limits”. The rate-limit thresholds are the production ones |
GetSubscriptionStatus | Reports the real status: Pending → Active → Cancelled / ApprovingFailed, plus Redelivering, RenewingFailed and Closed once the charge cycle is enabled. OperatorID is always 22, Country is always ru |
| Charges | No money is taken and the outcome is chosen upfront: <TestInfo><ExpectedBillingResult>, with the period compressed to seconds (BillingPeriodSeconds). Without that block there are no charges at all — in production they follow the project schedule. The number of retries after a decline is fixed (3); in production it depends on the tariff |
| PIN confirmation | The PIN is fixed — 1234, three attempts; after the third the subscription stays in ApprovingFailed forever. No random PIN is issued: the mock sends no SMS, and an automated scenario would break on it |
| Card and SBP | CustomerType=Card returns a working AuthorizeUrl — a mock payment page. Card details are neither validated nor forwarded anywhere; a decline is reproduced by the last 4 digits 0001…0005. SBP and SberPay are not distinguished — both open the same QR screen |
| Payment widget | Works: embed. is published and the token comes from AuthorizeUrl. The demo project has SBP, Alfa Pay and SberPay enabled; T-Pay is disabled in the subscription widget, as in production. A future BillingStartTimeUtc defers the first payment — TrialExists=true, the widget offers SBP only. There are no real banks, so the initial step cannot be confirmed from a banking app — a simulation button inside the widget is what drives the flow to success (production has no such button). No money moves: after a successful step APPROVED arrives, with no separate notification about the first charge |
| Callback | Sent on an actual status change: APPROVED after confirmation (PIN or payment), REJECTED when a card is declined, CANCELLED after CancelSubscription, plus the charge-cycle events when the cycle is enabled. The first one is delayed by 15 seconds; cycle notifications are sent at the moment of the charge |
| Storage | Request and callback logs are cleaned up on a schedule |
Signing is verified for real. HMAC-SHA256 and the allowed time drift work exactly as in production: this is the part of the integration the sandbox checks seriously — see “Request signature”. The callback is also delivered for real, with a signature and retries.
Before going live: obtain production SubscriptionProjectID and SecretKey — sandbox credentials do not work in production; test your handler against a full charge cycle (see “Sandbox hooks: charges”) — in production those events follow the project schedule and make up the bulk of the notification traffic.