Пример, как обработать поступление на QIWI кошелек через QIWI вебхук.

QIWI кошелек позволяет настроить уведомление на вебхук, попробуем это сделать.

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

Сама процедура настройки QIWI-webHook несложная, но есть определенная последовательность действий. 

Первое, что необходимо сделать,- это выпустить токен для работы с QIWI API:

  1. Откройте в браузере страницу https://qiwi.com/api. Для этого потребуется авторизоваться или зарегистрироваться в сервисе QIWI Кошелек. После этого нажмите Выпустить новый токен.
  2. Во всплывающем окне выберите разрешения на операции с токеном и нажмите Продолжить. Мне было достаточно выбрать пункт Просмотр истории платежей, так как других действий я не планировал выполнять.
  3. Подтвердите согласие на выпуск токена и нажмите Продолжить.
  4. Укажите проверочный код из SMS-сообщения, отправленного на номер вашего кошелька.
  5. Скопируйте строку токена и сохраните в безопасном месте.
Помните!
Токен действует в течение 180 дней с момента выпуска.

После получения токена можно настроить QIWI webhook. Сделать это можно через отправку запросов сначала для регистрации WebHook, затем для получения ключа проверки.

Это можно совместить одним действием:

<?php
// Ваш токен
$token = "YOUR_TOKEN";
// адрес файла обработчика запроса https://
$url = "https://URL_WEBHOOK";

/** Запрос на QIWI
 * @param $param_url
 * @param $type
 * @return mixed
 */
$query = function($param_url, $type) use ($token) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $param_url);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $token
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $r = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return $r;
};

/** Запрос на установку WebHook
 * @return mixed
 */
$setWebHook = function () use ($query, $url) {
    return $query("https://edge.qiwi.com/payment-notifier/v1/hooks?hookType=1&param=" . urlencode($url) . "&txnType=2", "PUT");
};

/** Запрос на получение ключа проверки
 * @param $hookId
 * @return mixed
 */
$secretKey = function ($hookId) use ($query) {
    return $query("https://edge.qiwi.com/payment-notifier/v1/hooks/" . $hookId . "/key", "GET");
};

// Установим WebHook
$webHookData = $setWebHook();

// Получим ключ проверки
$keyData = $secretKey($webHookData['hookId']);

// выведем тег форматирования
echo "<pre>";

// выведем информацию о webHook
print_r($webHookData);

// выведем информацию о ключе проверки
print_r($keyData);

После вызова этого скрипта через браузер, вы должны получить примерно вот такое содержимое:

Array 
(
    [hookId] => "779354rr4-5d47-44c4-ac79-3afdfg54a0cff"
    [hookParameters] => Array
        (
            [url] => "https://URL_WEBHOOK"
        )
    [hookType] => "WEB"
    [txnType] => "BOTH"
)
Array
(
    [key] => "1RuadasdfiYJZbYDu43563456435634534js81/jq2D0k0="
)

У нас теперь есть все необходимые данные, чтобы настроить обработку уведомления от QIWI о поступлении нового платежа.

Для того чтобы хоть как-то программно определить, что делать с платежом, нам нужен какой-то маркер, например, id заказа или id пользователя в телеграм. 

Маркер можно направить в комментарии к платежу, то есть попросить пользователя вместе с платежом указать нужный нам параметр для обработки платежа.

Давайте представим, что у вас есть бот, в боте есть баланс у каждого пользователя, ну, например, это какая-то игра в Телеграме. Вам необходимо, чтобы пользователь пополнил свой баланс через QIWI кошелек, вы предлагаете ему направить QIWI платеж с комментарием содержащим его telegram_id.

В обработке уведомления вы получаете комментарий платежа, в котором содержится нужный вам параметр - telegram_id пользователя, и производите начисление платежа на баланс соответствующую сумму.

Самое важно - это проверить подлинность уведомления от QIWI. Вот здесь-то нам и понадобится ключ проверки.

Вот пример обработчика уведомления:

<?php
// отсекаем лишние запросы
if ($_SERVER["REQUEST_METHOD"] != "POST") {
    echo "Hello world!";
    exit();
}

/**
 * Вызываем обработку
 */
new Qiwi();

/**
 * Class Qiwi
 */
class Qiwi
{
    // ключ для проверки подлинности
    private $key = "YOUR_KEY";

    // свойство для хранения данных
    private $data; 
  
    /** 
     * Qiwi constructor.
     */
    public function __construct()
    {
        // заполним данные
        $this->data = json_decode(file_get_contents('php://input'), true);
        // запустим роутер
        $this->router();
    }

    /**
     * Роутер проверки
     */
    private function router()
    {
        // проверяем на подлинность
        if ($this->checkData()) {
            // если это успешно
            if ($this->getStatus() == "success") {
                // проверяем тип платежа и направляем в нужный метод
                if ($this->getType() == "in") {
                    // обрабатываем уведомление
                    $this->getPay();
                }
            }
        }
    }

    /**
     *  Принимаем оплату
     */
    private function getPay()
    { 
         // Получим комментарий
         $comment = $this->getComment();  

         /**
          *
          * Здесь можно обработать платеж
          *
          */
    }

    /** Получим комментарий к платежу
     * @return mixed
     */
    public function getComment()
    {
        return $this->data['payment']['comment'];
    }

    /** Тип уведомления in | out
     * @return string
     */
    public function getType()
    {
        return strtolower($this->data['payment']['type']);
    }

    /** Статус уведомления 
     * @return string
     */
    public function getStatus()
    {
        return strtolower($this->data['payment']['status']);
    }

    /** Сумма платежа
     * @return float
     */
    public function getSum()
    {
        return $this->data['payment']['sum']['amount'];
    }

    /** Проверяем подлинность
     * @return bool
     */
    private function checkData()
    {
        $signFields = explode(",", $this->data['payment']['signFields']);
        $keysValues = [];
        foreach ($signFields as $field) {
            $keys = explode(".", $field);
            $keysValues[] = $this->getText($this->data['payment'], $keys, 0);
        }
        return hash_equals(hash_hmac("sha256", implode("|", $keysValues), base64_decode($this->key)), $this->data['hash']);
    }

    /** Получаем в рекурсии значение полей
     * @param $data array
     * @param $val
     * @param $key
     * @return mixed
     */
    private function getText($data, $val, $key)
    {
        return is_array($data[$val[$key]])
            ? $this->getText($data[$val[$key]], $val, $key + 1)
            : $data[$val[$key]];
    }
}
1 комментарий
Авторизуйтесь через Telegram, чтобы оставить комментарий.
Откройте бот @iMakeBot, нажмите кнопку Старт/Start. Следуйте инструкциям бота.

  • Дмитрий Бугаев [2 месяца назад]

    Как всегда максимально полезная статья! Благодарю!)