Справочные страницы — на английском.
CryptoLike API — Overview
From API call to payment status. One REST API, JSON in and out, signed with an API key. This
page is the map; every route, field and error is in the OpenAPI document
(docs/openapi.yaml, Swagger UI on /docs of a dev/stage instance). Authentication details —
docs/API-AUTH.md; webhook contract — docs/WEBHOOKS.md; the payment page — docs/CHECKOUT-API.md.
Base URL https://api.cryptolike.net (version in the path: /v1)
Auth X-API-Key + X-Timestamp + X-Signature (HMAC-SHA256) docs/API-AUTH.md
Format JSON, snake_case; amounts are decimal strings; times RFC 3339 UTC; ids UUID
Pagination ?limit=50&cursor=… → {"items":[…],"next_cursor":"…"|null}
Errors {"error":{"code","message","details"}} details.field names the bad field
Retries POST + Idempotency-Key → same response for 24 h, never a second invoice1. Quickstart — to the first confirmed payment
1. Create a key. Cabinet → API keys → Create key with create_invoice (and read). Copy the
secret: it is shown once. Keep it on your server (env var / secret manager) — never in a web
page or mobile app: whoever reads it can sign requests as you. Browser code talks to your
backend, your backend talks to us.
2. Create a payment. One call; the response carries the page to send the payer to.
# see docs/API-AUTH.md §4 for the signing lines (TS, SIG); body first, then sign it
BODY='{"amount":"10.50","currency":"USD","order_id":"A-1001","return_url":"https://shop.example/thanks"}'
curl -s https://api.cryptolike.net/v1/invoices \
-H "Content-Type: application/json" -H "Idempotency-Key: order-A-1001" \
-H "X-API-Key: $KEY_ID" -H "X-Timestamp: $TS" -H "X-Signature: $SIG" -d "$BODY"{
"id": "4e2bc88c-cb79-4afc-b864-c1ba8e9d50c9",
"status": "new",
"currency": "USD", "amount": "10.5",
"coin_id": null, "ticker": null, "network": null, "address": null,
"amount_crypto": null, "payer_amount": null,
"paid_amount": "0", "remaining_amount": "0", "overpaid_amount": "0",
"amount_fiat": "10.5", "fiat_currency": "USD", "rate_locked": null, "rate_locked_at": null,
"late_payment": false, "fee_paid_by": "merchant",
"order_id": "A-1001", "description": null, "return_url": "https://shop.example/thanks", "webhook_url": null,
"checkout_url": "https://pay.cryptolike.net/checkout/4e2bc88c-cb79-4afc-b864-c1ba8e9d50c9",
"ttl_expires_at": "2026-09-16T12:30:00Z", "expired_at": null,
"created_at": "2026-09-16T12:00:00Z", "updated_at": "2026-09-16T12:00:00Z"
}currency may be a fiat code (USD, EUR — the payer chooses the coin on the page and the
rate is locked at that moment) or a coin ticker (BTC, USDT). Pass coin_id (from
GET /v1/currencies) to fix the coin now: the address and the exact amount are in the response.
3. Send the payer to checkout_url. The page shows the address, QR, amount, network warning
and live status. After payment it offers return_url.
4. Learn the result. Either subscribe a webhook endpoint (POST /v1/webhooks/endpoints,
events invoice.paid, invoice.underpaid, invoice.expired, …; docs/WEBHOOKS.md) or poll
GET /v1/invoices/{id} — no more often than every few seconds. status: paid means the funds
are confirmed and credited to your balance (GET /v1/balances).
Test against a dev/stage instance with a ck_test_ key first; the reference signature vector
in docs/API-AUTH.md §3 tells you in one call whether your signing is right.
2. Resources
| Resource | Routes | Permission |
|---|---|---|
| Currencies | GET /v1/currencies (signed: the coins enabled for you; unsigned: the public catalogue) |
read |
| Rates | GET /v1/rates?fiat=USD |
read |
| Balances | GET /v1/balances |
read |
| Invoices | POST /v1/invoices, GET /v1/invoices, GET /v1/invoices/{id}, POST /v1/invoices/{id}/cancel |
create_invoice / read |
| Static addresses | POST /v1/addresses, GET /v1/addresses, GET /v1/addresses/{id} (with deposit history) |
create_address / read |
| Transactions | GET /v1/transactions (?format=csv to export), GET /v1/transactions/{id} |
read |
| Webhooks | GET/POST /v1/webhooks/endpoints, GET/PATCH/DELETE …/{id}, POST …/{id}/rotate-secret, GET /v1/webhooks/deliveries, GET …/{id}, POST …/{id}/retry |
create_invoice for changes, read for reads |
| Withdrawals | POST /v1/withdrawals, POST /v1/withdrawals/{id}/cancel; GET /v1/withdrawals, GET /v1/withdrawals/{id}, POST /v1/withdrawals/estimate |
withdraw / read |
3. Payment (invoice) status model
| Status | Meaning | Terminal |
|---|---|---|
new |
Created; nothing received. | no |
pending |
A transfer was detected; waiting for confirmations. | no |
paid |
Full amount confirmed and credited. An overpayment is still paid, with overpaid_amount > 0 (invoice.paid carries it). |
yes |
underpaid |
Less than the amount confirmed; open for a top-up to the same address until ttl_expires_at, then final. remaining_amount says how much is missing. |
after the TTL |
expired |
TTL passed with nothing confirmed. | yes |
cancelled |
You cancelled it (POST …/cancel, only from new). |
yes |
Rules worth knowing:
- Amounts.
amount_cryptois what you receive;payer_amountis what the payer must send (equal, unlessfee_paid_by: payer— then the platform fee is on top). A small shortfall within the underpayment tolerance of your account still counts aspaid. - Fiat pricing. The rate is locked when the coin is known (creation with
coin_id, or the payer's choice) and does not change for the TTL. If no fresh rate is available the request answers503 unavailable— retry, or create the invoice in crypto. - Late payments. Funds that arrive after
expired/cancelled/finalunderpaidare still credited to your balance, the invoice getslate_payment: trueand you receiveinvoice.late_payment. Decide with the customer what to do; the status does not change. - Reorganisations. If a chain reorganisation reverts a confirmed transfer, the invoice is
recomputed and you receive
invoice.reverted. Ship onpaid, and handlereverted.
4. Static addresses and transactions
A static address is a permanent deposit address of one currency for one of your customers
(customer_id). Every deposit is credited after the currency's confirmations and announced by
deposit.pending / deposit.confirmed (deposit.reverted after a reorganisation). One active
address per (currency, customer); archive in the cabinet to issue a new one — the old address
keeps receiving.
GET /v1/transactions lists every movement: invoice_payment, deposit, withdrawal,
adjustment. Each row has the gross amount, the platform fee (known once confirmed) and
net_amount, the chain txid, and the related invoice or static address. ?format=csv
streams the same list with the same filters; amounts stay text.
4a. Withdrawals
A withdrawal sends amount of a coin from your available balance to to_address. Ask
POST /v1/withdrawals/estimate first: it returns the platform fee, the reserved network fee
and total_debit — what leaves available the moment the withdrawal is created. The whole
total_debit sits in hold until the payout ends:
| Status | Meaning | Hold |
|---|---|---|
pending |
queued for the payout worker | held |
review |
a manual check is needed (review_reason: limit, pattern, manual, compliance, signer_limit); up to 24 h |
held |
awaiting_approval |
above your account's dual-approval threshold: a second owner/admin confirms in the cabinet | held |
processing |
being signed and sent — can no longer be cancelled | held |
broadcast |
in the network (txid, confirmations growing) |
held |
completed |
confirmed; amount left, platform_fee and network_fee_charged were charged |
released |
failed |
the network refused or dropped the transaction (failure_reason) — everything is back in available; create a new withdrawal |
released |
rejected |
refused on review — everything is back in available |
released |
cancelled |
you cancelled before processing (POST …/{id}/cancel) |
released |
Rules: the key needs withdraw; the account must be verified (403 kyb_required); when the
account enforces its withdrawal whitelist only an active whitelisted address is accepted
(403); a destination the platform does not accept is 422 address_refused (no detail is
given); an insufficient balance is 409 with details.reason = insufficient_funds. Send your
own payout_id: repeating the request with the same coin, amount and address returns the
existing withdrawal (200; a repeat within the first seconds after creation may still answer
201 — the body and id are the same; use Idempotency-Key for exact replay semantics),
different parameters are 409 — your retries can never pay twice.
The network fee you are charged is either the reserved estimate (default) or the fee actually
paid (network_fee_mode: actual on the estimate; the unused reservation returns to
available on completion). Webhooks: withdrawal.processing, withdrawal.completed,
withdrawal.failed, withdrawal.rejected (plus the progress events of docs/WEBHOOKS.md §5).
5. Errors
Every error is one envelope; branch on code, show message to a human, read details for
specifics (field, required, retry_after, server_time).
| HTTP | code |
Recovery |
|---|---|---|
| 400 | validation_error |
Fix details.field and resend. |
| 401 | auth.missing_header, auth.invalid_key, auth.invalid_timestamp, auth.expired_timestamp, auth.invalid_signature, auth.replay |
docs/API-AUTH.md §5 and §10. |
| 403 | auth.permission_denied (details.required), auth.ip_not_allowed |
Grant the permission / whitelist the IP in the cabinet. |
| 403 | kyb_required, forbidden (whitelist) |
Complete the account verification in the cabinet / whitelist the destination (or switch the whitelist off) in the cabinet. |
| 422 | address_refused |
The destination is not accepted by the platform; use another address. |
| 404 | not_found |
Wrong id, or the resource belongs to another account. |
| 409 | conflict |
The state does not allow it (cancel a paid invoice, second active address, retry of a pending delivery). Read the current state first. |
| 409 | idempotency.in_progress |
The first request with this key is still running; wait and retry. |
| 413 | payload_too_large |
Body over 1 MiB. |
| 422 | idempotency.mismatch |
Same Idempotency-Key, different request — use a new key. |
| 429 | rate_limited |
Wait Retry-After seconds; the limit is per key (600/min by default). |
| 503 | unavailable |
Rate feed or coin temporarily unavailable — retry with backoff. |
| 504 | timeout |
Retry with the same Idempotency-Key. |
6. Conventions
- Amounts are strings.
"0.00000001", never1e-8; up to 18 decimals; the API refuses more precision than the currency has. - Times are RFC 3339 in UTC (
2026-09-16T12:00:00Z). Filtersfrom(inclusive) /to(exclusive) take the same format. - Pagination is keyset:
next_cursoris opaque, valid for the same filters,nullon the last page; rows inserted meanwhile never shift or duplicate pages. - Stable shape. Optional blocks are present as
null, so a client can parse every response the same way. - Versioning. Breaking changes get a new prefix (
/v2); fields may be added under/v1at any time — ignore unknown fields. - Providers are never named. Rates, nodes and screening vendors are internal; you see values and timestamps.
7. Client libraries
web/packages/api-client — TypeScript types generated from the OpenAPI document plus a
signing fetch wrapper (createMerchantClient). Any language works with the four signing
lines of docs/API-AUTH.md §4 (curl, Node, Python, Go examples there).