# Как принимать криптовалюту на Python

> Приём Bitcoin и USDT в приложении на Python: подпись запросов через hmac, создание платежа через requests, страница оплаты и проверка вебхука во Flask.

Source: https://cryptolike.net/ru/guides/accept-crypto-payments-python
Published: 2026-09-24 · Updated: 2026-10-04 · Author: CryptoLike team

Приложение на Python принимает криптовалюту через CryptoLike в три шага: подписать каждый запрос к API стандартными модулями `hmac` и `hashlib`, создать платёж по заказу и проверить подписанный вебхук, прежде чем отметить заказ оплаченным. В примерах — `requests` и Flask; та же логика подходит для Django, FastAPI и других фреймворков.

Магазину на WooCommerce, OpenCart, PrestaShop или Magento 2 код не нужен — смотрите [интеграции](https://cryptolike.net/ru/integrations). Это руководство — для собственного бэкенда.

## Что понадобится

Аккаунт CryptoLike, Python 3.10 или новее и публичный адрес `https://` для вебхуков. Секреты держите в окружении: в примерах это `CRYPTOLIKE_API_KEY_ID`, `CRYPTOLIKE_API_SECRET` и `CRYPTOLIKE_WEBHOOK_SECRET`, а также `CRYPTOLIKE_API_URL` для тестового адреса API (без него — рабочий). Начинайте с тестовых ключей и тестовых сетей.

## 1. Создайте тестовый API-ключ

В кабинете откройте **Разработчикам → API-ключи → Создать ключ** с правами `create_invoice` и `read`. Ключ `ck_test_` работает с тестовыми сетями, где монеты ничего не стоят. Тестовые ключи выдаёт тестовая среда: поддержка CryptoLike даст доступ к её кабинету, где вы создадите такой же ключ, и адрес её API (`CRYPTOLIKE_API_URL` в примерах). Рабочий кабинет выпускает только боевые ключи, а в основных сетях тестовый ключ получает `401 auth.test_key`. Секрет показывается один раз — сразу положите его в окружение или менеджер секретов.

## 2. Подписывайте запросы через hmac

Подпись — HMAC-SHA256 от четырёх строк: времени Unix в секундах, метода, пути с query и SHA-256 тела, с ключом — API-секретом:

```python
import hashlib, hmac, json, os, time
import requests

def cryptolike(method: str, path: str, payload: dict | None = None, idempotency_key: str | None = None) -> dict:
    body = b"" if payload is None else json.dumps(payload, separators=(",", ":")).encode()
    ts = str(int(time.time()))
    canonical = "\n".join([ts, method.upper(), path, hashlib.sha256(body).hexdigest()])
    headers = {
        "X-API-Key": os.environ["CRYPTOLIKE_API_KEY_ID"],
        "X-Timestamp": ts,
        "X-Signature": hmac.new(os.environ["CRYPTOLIKE_API_SECRET"].encode(), canonical.encode(), hashlib.sha256).hexdigest(),
        "Content-Type": "application/json",
    }
    if idempotency_key:
        headers["Idempotency-Key"] = idempotency_key
    r = requests.request(method, os.environ.get("CRYPTOLIKE_API_URL", "https://api.cryptolike.net") + path, data=body or None, headers=headers, timeout=30)
    data = r.json()
    if r.status_code >= 400:
        raise RuntimeError(f"{data.get('error', {}).get('code', r.status_code)}: {data.get('error', {}).get('message', '')}")
    return data
```

Отправляйте те же байты, что хешировали: `data=body`, а не `json=payload`, который сериализует тело заново. Сверьте функцию с эталонным вектором из раздела [аутентификация API](https://cryptolike.net/ru/docs/auth).

## 3. Создайте платёж по заказу

Создавайте платёж на сервере в момент оформления заказа. Укажите цену в USD или EUR и дайте покупателю выбрать монету или передайте `coin_id` из `GET /v1/currencies`. Без `coin_id` страница покажет монеты, доступные для инвойсов, с ориентировочной суммой ≈ у каждой; добавьте `allowed_coin_ids` (id с `invoice_enabled: true` из подписанного `GET /v1/currencies`), чтобы предложить только часть из них. Номер заказа как ключ идемпотентности вернёт тот же платёж при повторе:

```python
invoice = cryptolike("POST", "/v1/invoices", {
    "amount": "49.90",
    "currency": "USD",
    "order_id": order.id,
    "idempotency_by_order_id": True,
    "return_url": f"https://example.com/orders/{order.id}",
}, idempotency_key=f"order-{order.id}")

order.invoice_id = invoice["id"]
```

Храните суммы строками или `Decimal` — никогда не `float`.

## 4. Отправьте покупателя на страницу оплаты

Перенаправьте на `invoice["checkout_url"]` (во Flask — `redirect(invoice["checkout_url"], code=303)`). На странице видны сумма, сеть, адрес с QR-кодом, оставшееся время и статус в реальном времени, а после оплаты покупатель вернётся на `return_url`. Чтобы он не уходил с сайта, встройте страницу [виджетом оплаты](https://cryptolike.net/ru/docs/widget).

## 5. Проверьте вебхук во Flask

Добавьте вебхук-эндпоинт в разделе **Разработчикам → Вебхуки** с событиями `invoice.*`. Проверяйте подпись по сырому телу из `request.get_data()`, отсеивайте повторы по `event_id` и отвечайте быстро:

```python
from flask import Flask, request

app = Flask(__name__)

@app.post("/webhooks/cryptolike")
def cryptolike_webhook():
    raw = request.get_data()
    ts = request.headers.get("X-Timestamp", "")
    got = request.headers.get("X-Signature", "")
    secret = os.environ.get("CRYPTOLIKE_WEBHOOK_SECRET", "")
    want = "sha256=" + hmac.new(secret.encode(), ts.encode() + b"." + raw, hashlib.sha256).hexdigest()
    if not secret or not ts.isdigit() or abs(time.time() - int(ts)) > 300 or not hmac.compare_digest(got, want):
        return "", 401
    event = json.loads(raw)
    if first_time(event["event_id"]) and event["type"] == "invoice.paid":
        mark_order_paid(event["data"]["invoice"]["order_id"])
    return "", 200
```

Доставка — «хотя бы один раз», и порядок может нарушаться: опирайтесь на статус внутри `data`. Полная процедура — в руководстве [по проверке подписи вебхуков](https://cryptolike.net/ru/guides/verify-crypto-payment-webhooks).

## 6. Проверьте в тестовой сети и запускайте

Создайте платёж тестовым ключом и оплатите его тестовыми монетами в той сети, что указана на странице: сначала придёт `invoice.pending`, затем `invoice.paid`. Обработайте также `invoice.underpaid`, `invoice.expired` и `invoice.reverted`, затем перейдите на рабочий ключ и пройдите чек-лист запуска из [руководства разработчика](https://cryptolike.net/ru/docs).

## Частые ошибки

| Ошибка | Что произошло | Что сделать |
|---|---|---|
| `401 auth.invalid_signature` | Тело запроса отличается от подписанного | Отправляйте хешированные байты через `data=`, а не `json=` |
| `401 auth.expired_timestamp` | Часы расходятся больше чем на 5 минут | Синхронизируйте часы сервера через NTP |
| `401` на вашем вебхуке | Тело разобрано или декодировано до проверки | Проверяйте по `request.get_data()` |
| `400 validation_error` | Поле отсутствует или в неверном формате | Посмотрите `details.field`; суммы передавайте строками |
| `409 conflict` | У заказа уже есть платёж | Возьмите `details.invoice_id` вместо создания нового |
| `422 no_allowed_coins` | Ни одна монета из `allowed_coin_ids` не доступна для инвойсов в этой валюте | Передайте другие id или уберите поле, чтобы предложить все монеты |

## Удобнее с SDK?

Официальный [Python SDK](https://cryptolike.net/ru/integrations/sdk-python) для Python 3.10+ оборачивает эти вызовы: подпись запросов, повторы при `429` и `5xx`, `Idempotency-Key` на каждом `POST`, постраничные списки и проверку вебхуков. Код выше — то, что SDK делает внутри, так что перейти на него можно позже, не меняя схему.

## Вопросы и ответы

### Почему подпись не проходит, если передавать тело через json= в requests?

`json=payload` сериализует тело заново, со своими пробелами, и отправленные байты отличаются от хешированных. Сериализуйте один раз, хешируйте эти байты и передавайте их же через `data=`. То же на стороне вебхука: проверяйте подпись по `request.get_data()`, прежде чем что-то разбирать.

### Можно ли использовать Django или FastAPI вместо Flask?

Да. Логика во всех фреймворках одна: прочитать сырое тело, вычислить `sha256=` и HMAC от метки времени, точки и тела, сравнить через `hmac.compare_digest`, отклонить метки, которые расходятся с вашими часами больше чем на 300 секунд, и только потом разбирать JSON. В Django сырое тело — `request.body`, в FastAPI — `await request.body()`.

### Как проверить интеграцию, не тратя настоящую криптовалюту?

Используйте ключ `ck_test_` и тестовый адрес API от поддержки CryptoLike. Тестовые ключи работают с тестовыми сетями, где тестовые монеты ничего не стоят, а весь сценарий — страница оплаты, подтверждения, подписанные вебхуки — ведёт себя как в рабочем режиме. Держите тестовые и рабочие ключи в разных конфигурациях, чтобы они не смешивались.
