Skip to content

TypeScript / Node.js

Node.js 18+

Set up in the cabinetKeys, webhook URLs and downloads for this platform are in the cabinet under Integrations.

@cryptolike/sdk

Official server-side SDK for the CryptoLike merchant API (Node.js ≥ 18, TypeScript types included).

  • 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
  • Typed resources generated from docs/openapi.yaml" target="_blank" rel="noopener noreferrer">docs/openapi.yaml
  • verifyWebhook() — signature and timestamp check of webhook deliveries (WEBHOOKS)
  • No runtime dependencies

The secret stays on your server

Never load this SDK in a browser or a mobile app. The API secret signs requests as you: whoever can read your page's JavaScript could create payments, read balances and change your webhooks. The constructor throws BrowserSecretError when it detects a browser. Your page needs only the invoice id / checkout_url that your server obtained — see WIDGET §1.

Keep the key id and secret in your environment or secret manager; the SDK reads CRYPTOLIKE_API_KEY_ID and CRYPTOLIKE_API_SECRET when you do not pass them and never logs them. The secret lives in a #private field, so it is redacted from console.log(client) / util.inspect(client) (which ignore toJSON()) as well as from JSON.stringify(client).

Install

Pre-release: npm 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
(cd "$CL/sdk/typescript" && npm ci && npm run pack)   # → pack/cryptolike-sdk-0.1.0.tgz
npm install "$CL/sdk/typescript/pack/cryptolike-sdk-0.1.0.tgz"

# after the release:
npm install @cryptolike/sdk

Quickstart — to the first confirmed payment

ts
import { CryptoLike, ApiError } from "@cryptolike/sdk";

const api = new CryptoLike(); // CRYPTOLIKE_API_KEY_ID + CRYPTOLIKE_API_SECRET from the environment

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

// 2. Learn the outcome from the webhook (below) — or poll:
const detail = await api.invoices.get(invoice.id);
if (detail.status === "paid") fulfil(detail.order_id);
ts
// 3. Webhook receiver (Express) — verify over the RAW body, dedupe by event_id, answer 2xx fast.
import express from "express";
import { verifyWebhook, WebhookVerificationError } from "@cryptolike/sdk";

app.post("/hooks/cryptolike", express.raw({ type: "application/json" }), (req, res) => {
  try {
    const event = verifyWebhook(req.headers, req.body, process.env.CRYPTOLIKE_WEBHOOK_SECRET!);
    if (!alreadySeen(event.event_id)) handle(event); // event.type === "invoice.paid" → fulfil
    res.sendStatus(200);
  } catch (e) {
    if (e instanceof WebhookVerificationError) return res.sendStatus(401);
    throw e;
  }
});

Full examples: examples/create-payment.ts, examples/express-webhook.ts.

Resources

Resource Methods
api.invoices create(body, idempotencyKey?), get(id), list(query), iterate(query), cancel(id), exportCsv(query)
api.addresses create, get(id, {limit, cursor}), list, iterate, archive
api.transactions list, iterate, get, exportCsv
api.balances / api.currencies / api.rates list()
api.withdrawals estimate(body), create(body), get, list, iterate, cancel
api.webhooks.endpoints list, create, get, update, delete, rotateSecret
api.webhooks.deliveries list, get, retry
api.embed get(), set({ allowed_origins }) — checkout widget allowlist
api.request(method, path, opts) any endpoint, signed

Amounts are decimal strings ("10.50"), never floats. Lists return { items, next_cursor }; iterate() walks every page for you.

Errors

Every non-2xx response is an ApiError with status, code (stable machine code), message, details, field, retryAfter and requestId. Transport failures after all retries are a NetworkError. Codes: API-AUTH §5, API §5.

ts
try { await api.invoices.create(body); }
catch (e) {
  if (e instanceof ApiError && e.code === "validation_error") console.log(e.field, e.message);
  else throw e;
}

Retries and idempotency

429 (after Retry-After, or backoff), 5xx except 501, and transport errors are retried up to maxRetries (default 3) with min(retryMaxMs, retryBaseMs · 2^attempt) full-jitter backoff. Every POST carries an Idempotency-Key (yours, or a random 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

ts
new CryptoLike({
  keyId, secret,                // default: CRYPTOLIKE_API_KEY_ID / CRYPTOLIKE_API_SECRET
  baseUrl,                      // default: CRYPTOLIKE_API_URL or https://api.cryptolike.net
  timeoutMs: 30_000, maxRetries: 3, retryBaseMs: 500, retryMaxMs: 8_000, retryAfterMaxMs: 30_000,
  apiVersion: "v1",             // X-API-Version pin
  appInfo: "my-shop/2.3",       // appended to User-Agent: cryptolike-sdk-typescript/<version>
  fetch,                        // custom fetch (proxies, tests)
});

Webhook verification

verifyWebhook(headers, rawBody, secret, { tolerance = 300, now }) returns the parsed event or throws WebhookVerificationError (reason: missing_header | invalid_timestamp | timestamp_out_of_tolerance | invalid_signature | invalid_body). headers may be Node's req.headers, a Headers instance or a plain object; rawBody must be the bytes as received. 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
npm ci
npm run generate    # docs/openapi.yaml → src/schema.d.ts (commit the result)
npm run typecheck
npm test            # vectors of docs/sdk/vectors.json + client behaviour (node --test)
npm run build       # dist/
npm run pack        # pack/cryptolike-sdk-<version>.tgz (CI artifact; not published automatically)