К содержимому

Python

Python 3.10+

Настроить в кабинетеКлючи, URL вебхуков и загрузки для этой платформы — в кабинете, раздел «Интеграции».

Эта инструкция на английском.

cryptolike (Python SDK)

Official server-side SDK for the CryptoLike merchant API (Python ≥ 3.10, requests; typed, py.typed).

  • Signed requests (X-API-Key / X-Timestamp / X-Signature, HMAC-SHA256 — API-AUTH)
  • Idempotency-Key generated for every POST (pass your own to make retries exact)
  • Retries with exponential backoff and jitter on 429 (honours Retry-After), 5xx and transport errors
  • Dataclasses for every object; amounts are Decimal — floats are refused
  • verify_webhook() — signature and timestamp check of webhook deliveries (WEBHOOKS)

The secret stays on your server

The API secret signs requests as you: whoever has it can create payments, read balances and change your webhooks. Use this SDK from your backend only; never put the secret into code that ships to a browser or a mobile app. Your page needs only the invoice id / checkout_url your server obtained — see WIDGET §1.

The client reads CRYPTOLIKE_API_KEY_ID and CRYPTOLIKE_API_SECRET from the environment when you do not pass them, never logs them and redacts them from repr(client) — and therefore from print(client), f-strings and most log formatters. vars(client) still shows _secret.

Install

Pre-release: PyPI has nothing under this name yet. Install from a checkout of the repository ($CL = path to the clone, see SDK.md); the command below is the one for after the public release.

bash
pip install "$CL/sdk/python"

# after the release:
pip install cryptolike

Quickstart — to the first confirmed payment

python
from cryptolike import Client, ApiError

api = Client()  # CRYPTOLIKE_API_KEY_ID + CRYPTOLIKE_API_SECRET from the environment

# 1. Create a payment on your server; send the customer to checkout_url.
invoice = api.invoices.create(
    amount="10.50", currency="USD", order_id="A-1001",
    return_url="https://shop.example/orders/A-1001",
    idempotency_key="order-A-1001",  # a retry never creates a second payment
)
redirect(invoice.checkout_url)

# 2. Learn the outcome from the webhook (below) — or poll:
detail = api.invoices.get(invoice.id)
if detail.status == "paid":
    fulfil(detail.order_id)
python
# 3. Webhook receiver (Flask) — verify over the RAW body, dedupe by event_id, answer 2xx fast.
from flask import request, abort
from cryptolike import verify_webhook, WebhookVerificationError

@app.post("/hooks/cryptolike")
def hook():
    try:
        event = verify_webhook(request.headers, request.get_data(), os.environ["CRYPTOLIKE_WEBHOOK_SECRET"])
    except WebhookVerificationError:
        abort(class="tok-num">401)
    if not already_seen(event.event_id):
        handle(event)  # event.type == "invoice.paid" → fulfil
    return "", class="tok-num">200

Full examples: examples/create_payment.py, examples/flask_webhook.py.

Resources

Resource Methods
api.invoices create(amount, currency, *, coin_id, description, order_id, ttl_seconds, return_url, webhook_url, fee_paid_by, idempotency_key), get(id), list(**filters), iterate(**filters), cancel(id), export_csv(**filters)
api.addresses create(coin_id, customer_id, *, label), get(id, limit=, cursor=), list, iterate, archive(id)
api.transactions list, iterate, get, export_csv
api.balances / api.currencies / api.rates list() (rates.list(fiat="EUR"))
api.withdrawals estimate(coin_id, amount, *, to_address), create(coin_id, amount, to_address, *, payout_id, comment), get, list, iterate, cancel
api.webhooks.endpoints list, create(url, events, *, secret), get, update(id, *, url, events, enabled), delete, rotate_secret
api.webhooks.deliveries list, get, retry
api.embed get(), set(allowed_origins) — checkout widget allowlist
api.request(method, path, query=, body=, idempotency_key=) any endpoint, signed

List filters are keyword arguments named as in the API (status="paid", from_="2026-09-01T00:00:00Z"from_ because from is a keyword). list() returns a Page (items, next_cursor); iterate() walks every page. Unknown response fields are kept in .raw.

Errors

Every non-2xx response raises ApiError with status, code (stable machine code), message, details, field, retry_after and request_id. Transport failures after all retries raise NetworkError. Codes: API-AUTH §5, API §5.

Retries and idempotency

429 (after Retry-After, or backoff), 5xx except 501, and connection/timeout errors are retried up to max_retries (default 3) with min(retry_max, retry_base · 2^attempt) full-jitter backoff. Every POST carries an Idempotency-Key (yours, or a UUID generated once per call and reused on each retry), so a retry never creates a second invoice, address or withdrawal. Each attempt is signed with a fresh timestamp. A 401 auth.replay — two identical requests signed within the same second share a signature — waits for the next second and signs afresh.

Options

python
Client(key_id=None, secret=None, *, base_url=None, session=None, timeout=class="tok-num">30.0,
       max_retries=class="tok-num">3, retry_base=class="tok-num">0.5, retry_max=class="tok-num">8.0, retry_after_max=class="tok-num">30.0,
       api_version="v1", app_info="my-shop/2.3")

Webhook verification

verify_webhook(headers, raw_body, secret, *, tolerance=300, now=None) returns a WebhookEvent (event_id, type, created_at, data, raw) or raises WebhookVerificationError (reason: missing_header | invalid_timestamp | timestamp_out_of_tolerance | invalid_signature | invalid_body). raw_body must be the bytes as received (Flask request.get_data(), Django request.body). Answer 401/400 on failure, 2xx on success, and deduplicate by event_id — deliveries are at least once and may arrive out of order.

Development

bash
python -m venv .venv && . .venv/bin/activate
pip install -e '.[test]'
pytest            # vectors of docs/sdk/vectors.json + client behaviour