Python
Эта инструкция на английском.
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-Keygenerated for everyPOST(pass your own to make retries exact)- Retries with exponential backoff and jitter on
429(honoursRetry-After),5xxand 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_urlyour 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.
pip install "$CL/sdk/python"
# after the release:
pip install cryptolikeQuickstart — to the first confirmed payment
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)# 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">200Full 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
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
python -m venv .venv && . .venv/bin/activate
pip install -e '.[test]'
pytest # vectors of docs/sdk/vectors.json + client behaviour