Skip to content

JavaScript / TypeScript SDK

The official JS/TS SDK ships both ESM and CommonJS with full TypeScript declarations. Universal: works in Node 18+, Deno, Bun, Cloudflare Workers, Vercel Edge, and browsers — built on globalThis.fetch, no HTTP-client dependency.

Terminal window
npm install @zutax/sdk
  1. Sign in to your ZUTAX workspace.
  2. Settings → API keysCreate key.
  3. Copy the key — you’ll only see it once.
import { ZutaxClient, type InvoiceTransmitInput } from '@zutax/sdk';
const client = new ZutaxClient({
apiKey: 'zk_test_...',
baseUrl: 'https://staging-api.getzutax.com',
});
const payload: InvoiceTransmitInput = {
external_id: 'INV-2026-0042',
issue_date: '2026-05-03',
due_date: '2026-06-03',
customer: {
external_id: 'C-100',
legal_name: 'Acme Industries Limited',
tin: '12345678-0001',
address: { city_name: 'Lagos', country_code: 'NG' },
},
lines: [
{
name: 'Consulting services — May 2026',
quantity: '1',
unit_price_naira: '250000.00',
vat_rate: '7.5',
},
],
};
const result = await client.invoices.transmit(payload, {
idempotencyKey: 'INV-2026-0042',
});
console.log(result.invoice_id, result.irn);
import {
ValidationError,
RateLimitError,
ZutaxError,
} from '@zutax/sdk';
try {
await client.invoices.transmit(payload);
} catch (err) {
if (err instanceof ValidationError) {
for (const e of err.errors) console.log(e.loc, e.msg);
} else if (err instanceof RateLimitError) {
console.log(`Slow down, retry in ${err.retryAfter}s`);
} else if (err instanceof ZutaxError) {
console.log(`Failed: ${err.statusCode} ${err.message}`);
} else {
throw err;
}
}

| Exception | When it fires | |---|---| | AuthError | 401 / 403 | | NotFoundError | 404 | | ValidationError | 400 / 422 (carries errors from the server) | | ConflictError | 409 | | RateLimitError | 429 (carries retryAfter in seconds) | | ServerError | 5xx | | ZutaxError | base class |

Pass per-call:

await client.invoices.transmit(payload, { idempotencyKey: 'INV-2026-0042' });

…or scope to an async block (uses AsyncLocalStorage in Node so it flows through await chains):

import { withIdempotencyKey } from '@zutax/sdk';
await withIdempotencyKey('INV-2026-0042', async () => {
await client.invoices.transmit(payload);
});
client.invoices // transmit, get, getByExternalId, list, cancel
client.parties // create, get, getByExternalId, list
client.products // create, get, getByExternalId, list
client.creditNotes // create, get, getByExternalId, list

For Cloudflare Workers / Vercel Edge: bundle as ESM and configure your bundler to mark node:async_hooks as external (or stub it). Without ALS, withIdempotencyKey falls back to a module-level variable — fine for single-task usage, but pass idempotencyKey: explicitly for safety with concurrent requests.

A complete end-to-end example — pulls pending invoices from a generic REST API and transmits each one — lives in zutax-sdks/reference-connectors/typescript-rest-source/. Fork it as a starting point for your own custom-ERP integration.

Zulaiy/zutax/zutax-sdks/javascript/