Recipes
Node.js integration
A small, retry-safe client using fetch.
No SDK is required — the API is plain JSON over HTTPS. Here is a minimal, production-shaped client with retry handling.
const BASE = 'https://api.getkanal.com/api';
type KanalOptions = { apiKey: string; storeId: number | string };
export class KanalClient {
constructor(private opts: KanalOptions) {}
private async request<T>(
method: string,
path: string,
body?: unknown,
attempt = 0,
): Promise<T> {
const res = await fetch(`${BASE}/v1/stores/${this.opts.storeId}${path}`, {
method,
headers: {
Authorization: `Bearer ${this.opts.apiKey}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
// Retry 429 and 5xx — safe because writes are idempotent.
if ((res.status === 429 || res.status >= 500) && attempt < 4) {
const retryAfter = Number(res.headers.get('Retry-After')) || 0;
const backoff = retryAfter * 1000 || 2 ** attempt * 500;
await new Promise((r) => setTimeout(r, backoff));
return this.request<T>(method, path, body, attempt + 1);
}
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(
`Kanal ${res.status}: ${err.message ?? err.error ?? res.statusText}`,
);
}
return res.status === 204 ? (undefined as T) : await res.json();
}
upsertOrder(order: Record<string, unknown>) {
return this.request('POST', '/orders', order);
}
updateOrder(externalId: string, patch: Record<string, unknown>) {
return this.request('PATCH', `/orders/${encodeURIComponent(externalId)}`, patch);
}
upsertCheckout(checkout: Record<string, unknown>) {
return this.request('POST', '/checkouts', checkout);
}
upsertCustomer(customer: Record<string, unknown>) {
return this.request('POST', '/customers', customer);
}
upsertShipment(shipment: Record<string, unknown>) {
return this.request('POST', '/shipments', shipment);
}
}const kanal = new KanalClient({
apiKey: process.env.KANAL_API_KEY!,
storeId: 123,
});
await kanal.upsertOrder({
external_id: 'ORDER-1001',
placed_at: new Date().toISOString(),
total_price: 49.9,
currency: 'EUR',
customer: { phone: '+33612345678', first_name: 'Marie' },
});Read KANAL_API_KEY from the environment. Never hardcode keys or expose them
to the browser.