Webhooks

Speend отправляет POST на url_callback при изменении статуса. Правила того, при каких именно сменах статуса шлётся webhook, различаются для платежей и выплат — см. ниже.

Откуда берётся адрес доставки

Приоритет между адресом из личного кабинета и адресом из тела запроса различается по методам:

Метод Приоритет
Статический кошелёк (createStaticWallet) Адрес из личного кабинета — значение url_callback из запроса игнорируется
Инвойс (createPayment) Адрес из запроса имеет больший приоритета по сравнению с адресом из личного кабинета
Выплата (payout/create) Адрес из личного кабинета — аналогично статическому кошельку

Webhook — инвойс и статический кошелёк

Отправляется на многих значимых переходах, включая промежуточные статусы (не только финальные) — например, при переходе в check, при частичной недоплате, при разблокировке AML и т.д.

{
  "type": 2,
  "uuid": "019f69ef-f130-7064-b822-09b39a40b99c",
  "amount": "2",
  "paid_amount": "6.170554",
  "paid_amount_usd": "2.00210147",
  "merchant_amount": "6.07799569",
  "commission_percent": "1.5",
  "commission_fixed": "0",
  "commission": "0.09255431",
  "is_final": true,
  "status": "paid",
  "network": "TRON",
  "currency": "TRX",
  "txid": "36540b5842d27b23da70415439281e2...",
  "from": "TQn9Y2*****LVLTiPKX",
  "to": "TCEUYh*****bNhPMK6W",
  "order_id": "1002",
  "additional_data": null,
  "sign": "91be60615455288c41ee177ab8b02b19"
}

Для статического кошелька дополнительно присутствуют поля wallet_address_uuid и wallet_id. Если у мерчанта включена автоконвертация — присутствует объект convert (структура как в payment/info, см. раздел «Информация о платеже»).

type — что породило уведомление (платежи и статический кошелёк)

type Источник
1 Статический кошелёк
2 Invoice (createPayment)

Webhook — выплаты (Payout)

В отличие от платежей, вебхук по выплате отправляется не при каждой смене статуса, а только для ограниченного набора статусов — см. таблицу ниже. Промежуточные технические статусы наружу не идут.

{
  "uuid": "019f89aa-bfe9-7308-8e40-fb5b1345a5a4",
  "type": 1,
  "status": "success",
  "is_final": true,
  "amount": "7",
  "commission": "0",
  "network": "SOL",
  "currency": "USDT",
  "address": "8Q3zsm*****tVUzasKQ",
  "txid": "DgR9Tg*****AFe5nA9j6zJ6",
  "order_id": "13",
  "description": null,
  "comment": null,
  "created_at": "2026-07-22T11:51:36+00:00",
  "updated_at": "2026-07-22T11:52:04+00:00",
  "sign": "c8980a53111b04abea70c2371ff2fca7"
}

type — способ создания выплаты (только Payout)

type Способ создания выплаты
1 Через публичное API (payout/create)
2 Вручную в личном кабинете мерчанта
3 Администратором Speend

Статусы, по которым шлётся webhook (Payout)

Статус в API (getStatus) Статус в вебхуке
ON_QUEUE process
SUCCESS success
CANCELED cancel
FAILED fail
AML_FAILED aml_fail

Вебхук приходит только по этим 5 статусам, вне зависимости от того, как создана выплата. Статусы REQUESTED, AWAITING_CONFIRMATION и внутренние стадии (ON_QUEUE_CONVERSION, ON_NETWORK_QUEUE) наружу не отправляются.

Подпись sign

Каждый webhook содержит поле sign.

Подпись позволяет убедиться, что webhook действительно отправлен Speend, а не подделан третьей стороной. Проверка обязательна перед тем, как доверять статусу из webhook.

type — что породило уведомление (платежи и статический кошелёк)

// webhook_password опционален
signKey = api_key + webhook_password

// тело — без поля sign, порядок ключей как в исходном JSON
sign = MD5(
  base64( json_encode(тело, JSON_UNESCAPED_UNICODE) ) . signKey
)

Какой ключ использовать

Ключ для формулы зависит от события, а не напрямую от поля type. У Payout и Статического кошелька значение type одинаковое (1), но ключи разные:

Событие Ключ (api_key в формуле)
Payout (вывод средств) Ключ выводов (api_key_withdraw)
Статический кошелёк (пополнение) Основной ключ (api_key_main)
Invoice (createPayment) Основной ключ (api_key_main)
speend