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

Справочные страницы — на английском.

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.

text
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 invoice

1. 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.

bash
# 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"
json
{
  "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_crypto is what you receive; payer_amount is what the payer must send (equal, unless fee_paid_by: payer — then the platform fee is on top). A small shortfall within the underpayment tolerance of your account still counts as paid.
  • 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 answers 503 unavailable — retry, or create the invoice in crypto.
  • Late payments. Funds that arrive after expired/cancelled/final underpaid are still credited to your balance, the invoice gets late_payment: true and you receive invoice.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 on paid, and handle reverted.

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", never 1e-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). Filters from (inclusive) / to (exclusive) take the same format.
  • Pagination is keyset: next_cursor is opaque, valid for the same filters, null on 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 /v1 at 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).