Webhook уведомления
Работа с Webhook-уведомлениями — это ключевой этап интеграции, который позволяет вашей системе оперативно реагировать на изменения статуса платежа в реальном времени.
При регистрации в системе необходимо указать URL, на который будут поступать уведомления о статусе транзакций (успешных и неуспешных). В личном кабинете можно указать отдельный вебхук для каждого терминала, и, при необходимости, выбрать какие типы вебхуков вы хотите получать.
Общая логика работы
Webhook используется для оперативной синхронизации статусов между WATA и системой мерчанта.
Типовой сценарий:
- В WATA меняется статус платёжной транзакции или возврата
- WATA отправляет HTTP-запрос на webhook URL мерчанта
- Система мерчанта обрабатывает уведомление
- В ответ необходимо вернуть HTTP
200 OK
Если webhook не был успешно доставлен, дальнейшее поведение зависит от типа уведомления.
Типы уведомлений
Webhook-уведомления бывают трех типов:
| Тип webhook | Когда приходит | Для чего используется |
|---|---|---|
| Предоплатный | Сразу после того, как клиент нажал «Оплатить», но до запроса в банк | Проверка наличия товара, актуальности цены, фрод-мониторинг или другая проверка заказа на стороне мерчанта |
| Постоплатный | После успешного подтверждения транзакции банком или после ошибки оплаты | Реализация бизнес-сценария: открытие доступа, смена статуса заказа в БД, отправка чека и т.д. В личном кабинете, в настройках терминала, можно отключить получение вебхука со статусом Ошибка (Declined), при необходимости |
| Возврат | После успешного возврата либо после ошибки возврата | Корректировка баланса, отмена заказа или деактивация услуги |
Правила обработки и тайм-ауты
Ваш сервер должен возвращать HTTP 200 OK на каждое webhook-уведомление.
Если ответ не получен или отличен от 200:
| Тип webhook | Поведение при ошибке ответа | Тайм-аут ожидания ответа |
|---|---|---|
| Предоплатный | Транзакция считается несогласованной и автоматически отклоняется. Запрос в банк не отправляется | 10 секунд |
| Постоплатный | WATA будет повторять отправку с увеличивающимся интервалом в течение следующих 32 часов | 1 минута |
| Возвратный | WATA будет повторять отправку с увеличивающимся интервалом в течение следующих 32 часов | 1 минута |
Параметры webhook-уведомления
| Параметр | Тип | Комментарий |
|---|---|---|
| transactionType | Строка | Тип транзакции: CardCrypto — рублевые и валютные карты, SBP — система быстрых платежей, TPay — метод Т-Банка, SberPay – метод Сбербанка |
| kind | Строка | Тип транзакции: Payment – оплата, Refund - возврат |
| id | UUID | Идентификатор транзакции в системе WATA. (Не является идентификатором платежной ссылки) |
| transactionId | UUID | Идентификатор созданной транзакции возврата в системе WATA |
| originalTransactionId | UUID | Используется при возвратах. Идентификатор исходной транзакции по которой производится частичный или полный возврат |
| terminalPublicId | UUID | Публичный идентификатор терминала мерчанта |
| transactionStatus | Строка | Статус транзакции (Created, Pending, Paid, Declined) См. раздел Статусы транзакций |
| errorCode | Строка | Код ошибки в случае неуспешного запроса (см. справочник кодов ошибок) |
| errorDescription | Строка | Описание ошибки в случае неуспешного запроса |
| terminalName | Строка | Название терминала мерчанта |
| amount | Число | Сумма платежа. Всего после точки может быть 2 цифры для копеек или центов. Пример: 1188.00 |
| currency | Строка | Валюта платежа (RUB, USD, EUR) |
| orderId | Строка | Уникальный идентификатор заказа в системе мерчанта |
| orderDescription | Строка | Описание заказа |
| commission | Число | Комиссия за транзакцию |
| paymentTime | Дата | Дата и время оплаты транзакции в UTC (перехода в статус Paid или Declined) |
| Строка | Email плательщика (если был задан на форме) | |
| paymentLinkId | UUID | Идентификатор платежной ссылки в системе WATA |
| payerData | Объект | Содержит информацию о плательщике |
| └ payerId | Строка | Маскированный номер телефона плательщика по СБП транзакции |
Безопасность и проверка подписи
Чтобы гарантировать, что уведомление отправлено системой WATA, каждое сообщение содержит заголовок X-Signature с цифровой RSA-подписью, она нужна, чтобы проверить, что уведомление действительно отправлено WATA и тело запроса не было изменено
X-Signature: <signature>
Алгоритм проверки
- Получите публичный ключ: Используйте актуальный ключ (формат PKCS1), доступный по адресу: api.wata.pro/api/h2h/public-key.
- Подготовьте данные: В качестве сообщения используйте raw JSON (необработанное тело запроса), полученный в Webhook.
- Верифицируйте: Используйте алгоритм
SHA512withRSAдля проверки соответствия подписи из заголовка X-Signature и тела сообщения.
Важно использовать именно необработанное тело запроса. Если JSON был отформатирован, пересобран или изменен middleware, проверка подписи может не пройти.
Пример проверки подписи на PHP
<?php
class SignatureVerificationService {
public static function verify($rawWebhookJson, $signature, $publicKey) {
$publicSignature = openssl_get_publickey($publicKey);
$signatureBytes = base64_decode($signature);
$result = openssl_verify($rawWebhookJson, $signatureBytes, $publicSignature, OPENSSL_ALGO_SHA512);
openssl_free_key($publicSignature);
return $result === 1;
}
}
Пример проверки подписи на Java
import java.security.PublicKey;
import java.security.Signature;
import java.util.Base64;
import static java.nio.charset.StandardCharsets.UTF_8;
public class SignatureVerificationService {
public static boolean verify(String rawWebhookJson, String signature, PublicKey publicKey) throws Exception {
Signature publicSignature = Signature.getInstance("SHA512withRSA");
publicSignature.initVerify(publicKey);
publicSignature.update(rawWebhookJson.getBytes(UTF_8));
byte[] signatureBytes = Base64.getDecoder().decode(signature);
return publicSignature.verify(signatureBytes);
}
}
Получение публичного ключа
Публичный ключ для проверки подписи можно получить через API:
GET https://api.wata.pro/api/h2h/public-key
Content-Type: application/json
Пример ответа:
{
"value": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
}
Пример webhook-уведомления
Content-Type: application/json
X-Signature: <signature>
{
"transactionType": "CardCrypto",
"kind": "Payment",
"id": "3a1cf611-abc6-8d30-c4cd-521c9f6eeeb0",
"transactionId": "3a16a4f0-27b0-09d1-16da-ba8d5c63eae3",
"transactionStatus": "Paid",
"terminalPublicId": "3b16a2f1-dead-4e5d-abff-90865d1e13b1",
"errorCode": null,
"errorDescription": null,
"terminalName": "string",
"amount": 1188.00,
"currency": "RUB",
"orderId": "string",
"orderDescription": "string",
"paymentTime": "2024-12-04T17:41:44.434598Z",
"commission": 10,
"email": null,
"paymentLinkId": null
}
Рекомендации по обработке
- Возвращайте
200 OKтолько после успешной обработки уведомления. - Обрабатывайте webhook-уведомления идемпотентно: повторная доставка одного и того же события не должна ломать бизнес-логику.
- Сохраняйте transactionId и transactionStatus для последующей сверки.
- Проверяйте подпись X-Signature до выполнения бизнес-операций.
- Не используйте polling как основной способ получения статусов. Для обновлений статусов используйте webhook-уведомления.