SubscriptionStatusNotification
Когда статус подписки фактически меняется, платформа отправляет XML-нотификацию на callback URL проекта. Тело подписано той же формулой HMAC-SHA256 — поля Now и Signature лежат внутри нотификации. Задержка первой отправки — 15 секунд после смены статуса.
| Событие | Когда приходит |
|---|---|
APPROVED | Подписка подтверждена: верный PIN в ApproveSubscription либо успешная оплата картой / СБП. SubscriptionStatus=Active |
REJECTED | Оплата картой отклонена. SubscriptionStatus=ApprovingFailed |
CANCELLED | После CancelSubscription. SubscriptionStatus=Cancelled |
APPROVED_BILLING | Очередное списание прошло: BillingIteration растёт, PaidUntil сдвигается |
REJECTED_BILLING_ATTEMPT | Попытка списания не прошла, будет повтор. SubscriptionStatus=Redelivering, BillingErrorCode=210 |
REJECTED_BILLING | Попытки исчерпаны — три подряд. SubscriptionStatus=RenewingFailed, подписка закрыта |
FINISHED | Все циклы тарификации пройдены. SubscriptionStatus=Closed |
Sandbox
События цикла списаний приходят, только если при создании подписки передан <TestInfo><BillingPeriodSeconds> — без него песочница списаний не делает. В бою эти уведомления идут по расписанию проекта и составляют основной поток.
| Параметр доставки | Значение |
|---|---|
| Задержка первого коллбека | 15 сек после смены статуса |
| Повторные попытки | 173 повтора по тому же расписанию, что у разовых платежей: 2 с × 2, 5 с × 2, 10 с × 2, 1 мин × 14, 5 мин × 21, 10 мин × 132 — сутки от первой отправки |
| HTTP-таймаут | 60 сек |
Мерчант подтверждает приём ответом 200. Дедуплицируйте нотификации по заголовку X-Event-Id (он же RequestID) — между попытками доставки он не меняется, номер попытки лежит отдельно в X-Event-Attempt. Заголовки Idempotency-Key / Idempotence-Key этот контур не знает.
<?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 — текст сервисного SMS
Перед каждым успешным списанием платформа запрашивает у партнёра текст сервисного SMS: заголовок Service-Method: ContentRequest, EventType=Content_request. Ожидается ответ StatusName=REQUEST_ACCEPTED с блоком ContentMessage со значениями параметров.
<?xml version="1.0" encoding="utf-8"?>
<Request>
<SubscriptionID>10000003</SubscriptionID>
<EventType>Content_request</EventType>
<BillingIteration>1</BillingIteration>
<ContentMessage><Parameter Name="BODY"/></ContentMessage>
</Request>Проверка подписи нотификации
curl
# Извлечь поля из тела и пересчитать подпись
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