Accept crypto payments with Python

Create crypto deposit addresses and verify TrezorPay callbacks in Python with requests and Flask.

This guide uses requests, flask and cryptography:

pip install requests flask cryptography

Create a payment address

create_address.py
import requests

API = "https://api.trezorpay.com"

def create_address(ticker: str, order_id: int, wallet: str) -> dict:
    response = requests.get(
        f"{API}/{ticker}/create/",
        params={
            "callback": f"https://shop.example/paid?order={order_id}",
            "address": wallet,
            "pending": 1,
        },
        timeout=15,
    )
    body = response.json()
    if body.get("status") != "success":
        raise RuntimeError(body.get("error"))
    return body  # address_in, minimum_transaction_coin, ...

Receive and verify the callback

app.py
import base64
import requests
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from flask import Flask, request

PUBKEY = serialization.load_pem_public_key(
    requests.get("https://api.trezorpay.com/pubkey/", timeout=15).json()["pubkey"].encode()
)
app = Flask(__name__)

def is_signed_by_trezorpay(data: bytes, signature: str) -> bool:
    try:
        PUBKEY.verify(base64.b64decode(signature), data, padding.PKCS1v15(), hashes.SHA256())
        return True
    except Exception:
        return False

@app.get("/paid")
def paid():
    if not is_signed_by_trezorpay(request.url.encode(), request.headers.get("x-ca-signature", "")):
        return "", 401
    if request.args.get("pending") == "0":
        order = request.args["order"]
        amount = request.args["value_forwarded_coin"]
        # mark the order paid, once per uuid
    return "*ok*"

request.url must be the URL exactly as we called it; behind a proxy, configure Flask's ProxyFix. For post=1 or json=1 callbacks, verify request.get_data() instead.

On this page