SubscriptionStatusNotification
When the subscription status actually changes, the platform sends an XML notification to the project’s callback URL. The body is signed with the same HMAC-SHA256 formula — the Now and Signature fields are inside the notification. The first delivery is delayed by 15 seconds after the status change.
| Event | When it arrives |
|---|---|
APPROVED | The subscription is confirmed: a correct PIN in ApproveSubscription or a successful card / SBP payment. SubscriptionStatus=Active |
REJECTED | The card payment was declined. SubscriptionStatus=ApprovingFailed |
CANCELLED | After CancelSubscription. SubscriptionStatus=Cancelled |
APPROVED_BILLING | A scheduled charge succeeded: BillingIteration grows, PaidUntil shifts |
REJECTED_BILLING_ATTEMPT | A charge attempt failed, a retry follows. SubscriptionStatus=Redelivering, BillingErrorCode=210 |
REJECTED_BILLING | Attempts exhausted — three in a row. SubscriptionStatus=RenewingFailed, the subscription is closed |
FINISHED | All billing cycles are done. SubscriptionStatus=Closed |
Sandbox
Charge-cycle events arrive only if <TestInfo><BillingPeriodSeconds> was passed at creation — without it the sandbox performs no charges. In production those notifications follow the project schedule and make up the bulk of the traffic.
| Delivery parameter | Value |
|---|---|
| First callback delay | 15 sec after the status change |
| Retries | 173 retries on the same schedule as one-off payments: 2 s × 2, 5 s × 2, 10 s × 2, 1 min × 14, 5 min × 21, 10 min × 132 — a day from the first delivery |
| HTTP timeout | 60 sec |
The merchant acknowledges receipt with a 200 response. Deduplicate notifications by the X-Event-Id header (also sent as RequestID) — it does not change between delivery attempts, the attempt number is separate in X-Event-Attempt. This circuit does not know the Idempotency-Key / Idempotence-Key headers.
<?xml version="1.0" encoding="utf-8"?>
<Request>
<SubscriptionID>12345678</SubscriptionID>
<SubscriptionProjectID>2001</SubscriptionProjectID>
<SubscriberID>1234567</SubscriberID>
<Subscriber_MSISDN>79001234567</Subscriber_MSISDN>
<EventType>APPROVED</EventType>
<SubscriptionStatus>Active</SubscriptionStatus>
<BillingIteration>1</BillingIteration>
<BillingAttempt>1</BillingAttempt>
<Country>ru</Country>
<OperatorID>22</OperatorID>
<CustomerPrice currency="RUB" amount="0.00"/>
<BillingOperationID>b4da05e2-1d77-40c9-85ac-0bb3835de8b5</BillingOperationID>
<BillingErrorCode>0</BillingErrorCode>
<PaidUntil>2026-07-25T12:00:00+03:00</PaidUntil>
<Now>20260625120015</Now>
<Signature>d2f36558ca5455beb28b4ec090ffbea1cf9425106b5dbeb2f93538603956da53</Signature>
</Request>ContentRequest — the service SMS text
Before every successful charge the platform asks the partner for the service SMS text: the Service-Method: ContentRequest header, EventType=Content_request. The expected answer is StatusName=REQUEST_ACCEPTED with a ContentMessage block carrying the parameter values.
<?xml version="1.0" encoding="utf-8"?>
<Request>
<SubscriptionID>10000003</SubscriptionID>
<EventType>Content_request</EventType>
<BillingIteration>1</BillingIteration>
<ContentMessage><Parameter Name="BODY"/></ContentMessage>
</Request>Notification signature verification
curl
# Extract the fields from the body and recompute the signature
NOW=$(xmllint --xpath 'string(//Now)' notification.xml)
PID=$(xmllint --xpath 'string(//SubscriptionProjectID)' notification.xml)
GOT=$(xmllint --xpath 'string(//Signature)' notification.xml)
EXPECTED=$(printf '%s%s' "$PID" "$NOW" \
| openssl dgst -sha256 -hmac "$SECRET" | awk '{print $NF}')
[ "$GOT" = "$EXPECTED" ] && echo OK || echo MISMATCH