Прием платежей в крипто валютах в Telegram боте через WalletPay и Python/Flask

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Криптовалюты в Telegram

Приветствую сообщество.

Бот Telegram @wallet недавно предоставил API для приема платежей в сторонних Telegram ботах. Из крипто валют поддерживаются BTC, TON, USDT.

Необходимо зарегистрироваться на сайте, предоставить сведения о подключаемом к API боте, пройти процедуру идентификации (биометрия для физических лиц), дождаться одобрения заявки и назначения размера комиссии для ваших платежей. У меня процедура заняла чуть более суток.

После одобрения заявки получаете доступ в личный кабинет, где нужно сгенерировать ключ для доступа к API WalletPay.

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

import requests

def get_pay_link():
    headers = {
     'Wpay-Store-Api-Key': 'YOUR-API-KEY',
     'Content-Type': 'application/json',
     'Accept': 'application/json',
    }

    payload = {
      'amount': {
        'currencyCode': 'USD',  # выставляем счет в долларах США
        'amount': '1.00',
      },
      'description': 'Goods and service.',
      'externalId': 'XXX-YYY-ZZZ',  # ID счета на оплату в вашем боте
      'timeoutSeconds': 60 * 60 * 24,  # время действия счета в секундах
      'customerTelegramUserId': '999666999',  # ID аккаунта Telegram покупателя
      'returnUrl': 'https://t.me/mybot',  # после успешной оплаты направить покупателя в наш бот
      'failReturnUrl': 'https://t.me/wallet',  # при отсутствии оплаты оставить покупателя в @wallet
    }

    response = requests.post(
      "https://pay.wallet.tg/wpay/store-api/v1/order",
      json=payload, headers=headers, timeout=10
    )
    data = response.json()

    if (response.status_code != 200) or (data['status'] not in ["SUCCESS", "ALREADY"]):
        logging.warning("# code: %s json: %s", response.status_code, data)
        return ''

    return data['data']['payLink']

Счет можно выставлять в долларах США, евро или рублях. Пересчет в BTC, TON, USDT будет выполнен по курсу WalletPay.

Для подтверждения факта оплаты счета, WalletPay предоставляет две опции:

  • периодический опрос состояния счета с вашей стороны

  • POST-запрос на указанный вами в личном кабинете https адрес (webhook в терминах WalletPay)

Я использовал второй вариант. Код обработчика вебхука может быть таким.

from flask import Flask, request

app = Flask(__name__)

@app.route('/tgwallet/ipn', methods=['POST'])
def ipn_tgwallet():
    for event in request.get_json():
        if event["type"] == "ORDER_PAID":
            data = event["payload"]
            print("Оплачен счет N {} на сумму {} {}. Оплата {} {}.".format(
              data["externalId"],  # ID счета в вашем боте, который мы указывали при создании ссылки для оплаты
              data["orderAmount"]["amount"],  # Сумма счета, указанная при создании ссылки для оплаты
              data["orderAmount"]["currencyCode"],  # Валюта счета
              data["selectedPaymentOption"]["amount"]["amount"],  # Сколько оплатил покупатель
              data["selectedPaymentOption"]["amount"]["currencyCode"]  # В какой криптовалюте
            ))

    # нужно всегда возвращать код 200, чтобы WalletPay не делал повторных вызовов вебхука
    return 'OK'

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

Для этого WalletPay предлагает две опции:

  • проверка принадлежности IP вызова к пулу IP адресов WalletPay

  • проверка хеша, вычисленного на основе данных вызова вебхука и вашего ключа API

Список IP адресов WalletPay можно найти в документации, а для проверки хеша можно использовать следующий код.

import base64, hashlib, hmac

ENCODING = 'utf-8'

def is_valid(flask_request):
    text = '.'.join([
      flask_request.method,  # 'POST'
      flask_request.path,  # нужно использовать часть адреса без имени домена, '/tgwallet/ipn' в нашем случае
      flask_request.headers.get('WalletPay-Timestamp'),
      base64.b64encode(flask_request.get_data()).decode(ENCODING),
    ])
    signature = base64.b64encode(hmac.new(
      bytes('YOUR-API-KEY', ENCODING),
      msg=bytes(text, ENCODING),
      digestmod=hashlib.sha256
    ).digest())

    return flask_request.headers.get('Walletpay-Signature') == signature.decode(ENCODING)

Затем использовать функцию is_valid для проверки в обработчике вебхука.

Спасибо за внимание.

Источник: https://habr.com/ru/articles/751848/


Интересные статьи

Интересные статьи

Я не смог найти хоть какой-то нормальной информации про тестовые сервера Telegram кроме одной статьи про то как зайти с андроида на тестовый сервер и получить там премиум и канал с галочкой. И маленьк...
Всем привет! Да-да тема не очень актуальна и на просторах habr-a есть очень много статей про то, как написать простейшего telegram bota, но я все-таки рискну написать еще одну. Может кому-то она будет...
Если в сферу ваших интересов входит разработка приложений под Android или мультиплатформенная разработка на Kotlin, то есть все шансы, что вы уже сталкивались с коллекциями в Kotlin.Kotlin располагает...
Мне очень досадно наблюдать, как суровые инженеры, которые программируют микроконтроллеры для самонаводящихся ракет, не могут настроить систему контроля версий, чтобы работать комфортно, эффективно и ...
Голыми руками захватывать криптоключи и копировать брелоки Mifare для домофонов конечно невозможно, а вот собрать прибор, который будет это делать вполне реально. Не буду здесь рассказывать о том...