# Вебхуки

<figure><img src="https://316941418-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fu7Tp9nYI5WDjQbI6k69e%2Fuploads%2FMYAebMKj4b6S5b6G6Rga%2Fimage.png?alt=media&#x26;token=67d82439-1441-4644-a5d6-9278cd54cab4" alt=""><figcaption></figcaption></figure>

## 1. Что такое вебхуки?

Вы создаете заявку на оплату и далее хотите понимать когда статус по заявке изменится. Сделать это можно несколькими способами

### 1.1. Примитивный способ

Самый примитивный способ узнать об изменении статуса заявки это делать регулярный опрос FireKassa по деталям транзакции и как только вы увидите что статус поменялся - вы достигли своей цели.

К очевидным плюсам такого подхода относится простота концепции. Т.е. просто опрашиваем детали транзакции до тех пор пока не увидим что статус поменялся. Однако минусов значительно больше

**Первый минус** заключается в том что как правило опрос выполняется раз в минуту и если оплата произошла в 13:05:03, то вы об этом узнаете только в 13:06:00 и в это время ваши клиенты будут разрывать чаты на тему "почему я оплатил, а заявка еще не оплачена". Этого минуса более чем хватает для того чтобы не пользоваться этим методом

**Второй минус** заключается в избыточной нагрузке на вашей стороне. Если у вас не одна заявка. а не несколько сотен, то получается вам нужно по циклу опрашивать состояние всех ваших транзакций, к примеру, раз в минуту. Скорее всего вы не успеете их опросить за одну минуту, уже пойдет следующая, в итоге процедура опроса будет накладываться одна на другую или блокировать одна другую. Не удобно и громоздко.

**Третий минус** заключается в избыточной нагрузке на нашей стороне. Если какой-то клиент упорно не желает эволюционировать и заваливает наш сервис бесполезными сотнями запросами, то мы будем ограничивать таких клиентов посредством **rate limit**.&#x20;

### 1.2. Правильный способ или вебхуки

Мы уже понимаем что **правильно** означает в первую очередь максимально оперативно, а кроме того с минимальной нагрузкой для вашей и нашей системы. Как же это обеспечить?

На самом деле FireKassa заботливо отправляет уведомление по факту каждого изменения статуса транзакции. Причем делает это весьма настойчиво, делая до 5 повторов на тот случай, если первый раз вы по какой-то причине не смогли обработать уведомление.

Т.е. все что вам нужно, это обеспечит прием и обработку этих сообщений от нашей системы

## 2. Формат вебхука <a href="#id-8.1.-format-vebkhuka" id="id-8.1.-format-vebkhuka"></a>

Мы присылаем следующие данные в вебхуке:

* **id** - номер транзакции в нашей системе
* **order\_id** - номер заявки в вашей системе
* **type** - тип транзакции, deposit или withdrawal
* **site\_id** - номер сайта, по которому была создана заявка
* **amount** - оплаченная сумма по транзакции, может быть больше или меньше оригинальной
* **currency** - валюта транзакции
* **commission** - комиссия по транзакции
* **account** - контрагент, чаще всего пустое, но иногда тут может быть номер счета, с которого или на который была выполнена оплата
* **status** - статус платежа, подробно ниже
* **error\_code** - код ошибки, если платеж завершился с ошибкой
* **error** - сообщение об ошибке, если платеж завершился с ошибкой

По статусам платежей могут быть следующие варианты

**Для ввода** ( `type=deposit` )

* **paid**, конечный статус, заявка оплачена 1 в 1 с заказанной суммой
* **partially-paid**, конечный статус, клиент недоплатил. Бывает так что заявка на 100.12, а клиент оплачивает ровно 100.00. Кроме статуса мы также указываем в качестве amount именно 100.00, а не 100.12, как это было указано в заявке. Решение о том что делать с этим клиентом на вас.
* **overpaid**, конечный статус, клиент переплатил. Бывает так что заявка на 99.94, а клиент оплатил 100.00. Кроме статуса мы также указываем в качестве amount именно 100.00, а не 99.94, как это было указано в заявке. Решение о том что делать с этим клиентом на вас.
* **expired**, *частично* конечный статус. У каждой заявки есть свой срок действия и если оплата не произошла в течение указанного срока, то заявка будет закрыта как просроченная (expired). Обычно если заявка перешла в статус expired, то она в таком статусе уже и остается, однако бывает так что клиент оплатил познее истечения срока действия или зачисление пришло позднее истечения срока действия, то заявка может перейти в один из конечных статусов: paid или overpaid или partially-paid.
* **cancel**, частично конечный статус. Заявка переход в статус `cancel` в случае если вы ее отменили ( в этом случае вебхук не будет отправлен ) или ее отменил наш оператор ( в этом случае вебхук будет отправлен ). Однако если ее отменили вы, а клиент все таки решил оплатить, то заявка может перейти в один из конечных статусов: `paid` или `overpaid` или `partially-paid`.
* **error**, конечный статус. Обычно если при создании заявки на ввод произошла ошибка, то заявка переходит в такой статус и вы получаете сообщение о проблеме сразу в ответе по апи. Потому на текущий момент вебхука с таким статусом не предусмотрено.

**Для вывода** ( `type=withdrawal` )

* **paid**, конечный статус, заявка оплачена 1 в 1 с заказанной суммой
* **partially-paid**, конечный статус, мы не смогли выплатить всю сумму. Такое иногда бывает когда сумма платежа была разбита на несколько и часть операций выплаты прошло, а часть застряло по независящим от нас причинам. Например у получателя был исчерпан месячный лимит платежей. В этом случае мы также указываем в поле amount реальную сумму выплаты
* **waiting,** промежуточный статус. Иногда бывает так что все платежи с нашей стороны ушли, но банк отправил их на дополнительную проверку в службу безопасности, где платежи могут находиться до 2 рабочих дней ( но если выпало на выходные, то дольше ). По истечение срока платеж перейдет в один из конечных статусов
* **expired**, конечный статус. По каким-то причинам мы не смогли выполнить платеж в сроки, указанные в заявке, потому платеж был переведен в просроченные. Если он все еще актуален для вас - создайте платеж заново.
* **error,** конечный статус. По какой-то причине мы не смогли выполнить платеж, код причины и описание будет указано дополнительно в полях `error_code` и `error`.
* **cancel**, конечный статус. Платеж был отменен с вашей стороны или нашим оператором. В случае отмены нашим оператором дополнительная информация будет указана в полях `error_code` и `error`.

Данные от нас приходят в формате `form-data`. Для имитации вебхука, полученного от нас, вы можете выполнить следующий запрос:

```
curl -X POST https://yourhost.com/your-path \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "X-Sign: *signature*" \
  -H "X-Time: 1682528172000" \
  -d "id=12345&order_id=order123&site_id=5&status=paid&amount=255.00&account=&type=deposit&commission=5.25"
```

## 3. Айпи адреса с которых отправляются вебхуки <a href="#id-8.2.-aipi-adresa-s-kotorykh-otpravlyayutsya-vebkhuki" id="id-8.2.-aipi-adresa-s-kotorykh-otpravlyayutsya-vebkhuki"></a>

Для целей безопасности вам следует проверять откуда пришли вебхуки, чтобы не получилось что вы отреагировали на ложное уведомление. Мы отправляем хуки **ТОЛЬКО** со следующих айпи адресов:

* 94.250.252.69
* 178.250.156.196

## 4. Подпись вебхука <a href="#id-8.3.-podpis-vebkhuka" id="id-8.3.-podpis-vebkhuka"></a>

Для целей безопасности мы подписываем все вебхуки апи токеном сайта. Делается это посредством следующего алгоритма:

```php
function sign(array $params, string $xTime, string $siteKey): string
{
    ksort($params);

    $s = '';
    foreach($params as $k => $value) {
        if (in_array(gettype($value), ['array', 'object', 'NULL']) ){
            continue;
        }
        if (is_bool($value)) {
        $s .= $value ? "true" : "false";
            continue;
        }
        $s .= strval($value);
    }
    $s .= $xTime;

    return hash_hmac('sha512', strtolower($s), $siteKey);
}
```

Данные о подписи мы кладем в заголовок `X-Sign`, а время, с которым формировалась подпись в `X-Time`

## 5. Что такое повторная отправка?

Мы понимаем что интернет не самый надежный канал связи, плюс могут быть какие-то временные проблемы с вашей стороны, поэтому, если мы не получим от вас успешный ответ, то мы будем пытаться отправить вебхук еще до 4-х раз.

Под успешным ответом понимается ответ с http статусом `HTTP 200` и с телом сообщения `OK`. Речь идет строго о двух заглавных английских буквах `ОК`, без пробелов, кавычек и любых других символах.

**Внимание!!!** Успешный ответ `ОК` подразумевает что вы получили, обработали информацию и нет никакой нужды в том, чтобы мы отправляли вам ее еще раз. Именно `OK`, не иначе. Если же вы решите детализировать ответ и ответите чем-то типа `uje obrabotano`, то сделаете хуже, поскольку система вас не поймет и будет пытаться отправить вебхук повторно. Это дополнительная нагрузка на вашу и нашу систему.

## 6. Настройка отправки вебхуков

Чтобы вебхуки начали поступать на ссылку для их обработки, вам нужно указать эту ссылку в настройках вашего сайта на вкладке API, параметр URL для уведомлений

<figure><img src="https://316941418-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fu7Tp9nYI5WDjQbI6k69e%2Fuploads%2FVwZjiEe0ezdWIhR32TfJ%2Fimage.png?alt=media&#x26;token=ce84c5d8-0074-45d9-a556-d80efee4990e" alt=""><figcaption></figcaption></figure>

**Кроме того**, если вам по какой-то причине нужно иметь индивидуальный адрес для отправки уведомления для каждой транзакции, то при создании транзакции вы можете прописать этот адрес в параметре notification\_url.
