Skip to main content

2.3 Webhook delivery

Overview

When a payout status changes, the platform can notify your system by sending an HTTP request to a URL you provide. This allows you to keep your records in sync without polling Get payout status.

When webhooks are sent

A webhook is sent when the transaction status changes. One request is sent per status change.

Webhook URL

The platform uses the first available URL in this order:

  1. Per-request callback_url — if you passed callback_url in the Create payout request body, that URL is used for that transaction.
  2. Shop default webhook URL — if the shop has webhook_url configured and webhooks enabled, that URL is used when the transaction has no callback_url.

If neither is set, no webhook is sent for that transaction.

Request format

PropertyValue
MethodPOST
URLYour callback_url or the shop's webhook_url.
HeadersSee below.
BodyJSON object (see payload).

Headers

HeaderDescription
Content-Typeapplication/json
X-TimestampISO-8601 timestamp (UTC) of the request.
X-SignatureHMAC-SHA256 signature (see Verifying the signature).

Payload (body)

The body is a JSON object with the following fields:

FieldTypeDescription
idnumberInternal transaction ID.
external_idstringYour identifier from the create request (idempotency key).
shop_codestringShop code.
statusstringCurrent external payout status. Values are limited to pending, success, failed, canceled, refunded, or expired.
amountstringTransaction amount.
currencystringISO currency code.
paymentDataobjectShop-schema output (same shape as in API responses).
updated_atstringISO-8601 timestamp of the status update.

The webhook body does not include an event field. Delivery type is implied by the endpoint and the merchant flow (payout vs payin), while the platform still tracks the internal event name for delivery logs.

Example payload

{
"id": 12345,
"external_id": "PAY-001",
"shop_code": "shop-001",
"status": "success",
"amount": "1000.00",
"currency": "RUB",
"paymentData": {},
"updated_at": "2025-12-05T10:15:00.000000Z"
}

Verifying the signature

To ensure the request came from the platform and was not altered, verify the X-Signature header.

  1. Take the X-Timestamp header value (as sent).
  2. Take the raw request body (string, as received).
  3. Compute: message = X-Timestamp + body.
  4. Compute: signature = HMAC_SHA256(webhook_secret, message).
  5. Compare signature with the X-Signature header (constant-time comparison).

The webhook_secret is the same secret used for API request signing (merchant/organization level). If no secret is configured, webhooks are not sent.

Your endpoint requirements

  • Your endpoint must respond with HTTP 2xx (e.g. 200) for the delivery to be considered successful.
  • Any other status (4xx, 5xx) or a timeout is treated as a failure; the platform will retry (see below).
  • Respond quickly (e.g. within a few seconds). If you need to do long work, acknowledge with 200 and process asynchronously.

Retries

If the platform does not receive a successful (2xx) response or the request times out, it retries the webhook up to 5 attempts total (initial attempt plus retries) with delays of 1 minute, 5 minutes, 30 minutes, 60 minutes, and 120 minutes. Design your endpoint to be idempotent so that receiving the same status change more than once is safe.