DocsSDKs & OpenAPI

Open the app →

SDKs & OpenAPI

An OpenAPI 3.1 spec for generating clients in any language, and a typed Node SDK. The spec and the REST API work today.

OpenAPI

The full spec lives at /openapi.json. Feed it to openapi-generator, Kiota, Speakeasy, or your tool of choice to generate a client in any language.

Node: @invoicejetai/node

Zero-dependency and fully typed. Runs on Node 18+, Bun, Deno, and edge runtimes (anything with fetch; webhook verification uses WebCrypto, falling back to node:crypto on Node 18).

shell
npm install @invoicejetai/node
Node
import { readFile } from "node:fs/promises";
import { InvoiceJet, InvoiceJetError } from "@invoicejetai/node";

const client = new InvoiceJet({ apiKey: process.env.INVOICEJET_API_KEY! });

// extract and wait
const invoice = await client.invoices.extract({
  fileUrl: "https://example.com/invoices/june.pdf",
  wait: true,
});

// or fire-and-poll
const queued = await client.invoices.extract({
  file: await readFile("june.pdf"),
  fileName: "june.pdf",
  mimeType: "application/pdf",
});
const done = await client.waitForCompletion(queued.id); // complete, failed, or held

// every complete invoice ingested through the API (follows next_cursor)
for await (const inv of client.invoices.iterate({ status: "complete", source: "api", limit: 100 })) {
  console.log(inv.id, inv.amount, inv.paid_at);
}

// export unpaid invoices as a QuickBooks bill-import CSV
const csv = await client.exports.create({ shape: "lines", format: "csv", paid: false });

// key + quota check
const me = await client.me();

// errors carry status, type, code, requestId, and extra fields in details
try {
  await client.invoices.extract({ fileUrl: "https://example.com/july.pdf" });
} catch (e) {
  if (e instanceof InvoiceJetError && e.code === "monthly_quota_reached") {
    console.log("upgrade:", e.details.upgrade_url);
  } else throw e;
}

Timeouts, retries & errors

Each attempt times out after 60s, or 120s for file uploads and wait: true. Failed requests are retried up to twice with exponential backoff and full jitter. Retried failures are network errors, timeouts, and 408, 429, 500, 502, 503 and 504; other 4xx responses, 409 included, are not. A Retry-After header is honored, and a 429 without one waits for X-RateLimit-Reset. If the server asks for more than 60s, the SDK throws instead, with retryAfter set.

Only requests that are safe to repeat are retried: GETs, invoices.update, and invoices.extract. extract always sends an Idempotency-Key, yours or a generated one, and reuses it on every retry, so a retried create never duplicates an invoice. retryExtraction and requestApproval are never retried automatically. Files are buffered in memory (15 MB max), so retries resend them in full.

Node
import { InvoiceJet, InvoiceJetError, InvoiceJetTimeoutError } from "@invoicejetai/node";

const client = new InvoiceJet({
  apiKey: process.env.INVOICEJET_API_KEY!,
  timeout: 60_000, // per attempt, ms; 0 = none
  uploadTimeout: 120_000, // uploads and wait: true
  maxRetries: 2, // 0 = no retries
});

// per-request overrides and cancellation, on every method
const page = await client.invoices.list(
  { paid: false },
  { timeout: 10_000, maxRetries: 5, signal: AbortSignal.timeout(30_000) },
);

try {
  await client.invoices.extract({ fileUrl: "https://example.com/july.pdf", wait: true });
} catch (e) {
  if (e instanceof InvoiceJetTimeoutError) {
    // outcome unknown: the same key replays the original result, no duplicate
    await client.invoices.extract({
      fileUrl: "https://example.com/july.pdf",
      idempotencyKey: e.idempotencyKey!,
    });
  } else if (e instanceof InvoiceJetError) {
    console.error(e.status, e.code, e.message, e.requestId, e.retryAfter, e.attempts);
  } else throw e; // your own AbortSignal rejects with its reason
}

console.log(client.lastRateLimit); // { limit, remaining, reset } from the last response
InvoiceJetError fieldMeaning
statusHTTP status; 0 when no response arrived.
type / code / messageFrom the API error body. Connection failures: connection_error / connection_failed or timeout.
detailsExtra body fields, e.g. limit, used, upgrade_url on 402 monthly_quota_reached.
requestIdThe request id, when the API sends one.
retryAfterSeconds the API asked you to wait, or null.
rateLimitX-RateLimit-* values: limit, remaining, reset (Unix seconds).
attemptsAttempts made, retries included.
idempotencyKeyThe key an extract was sent with; pass it back to retry safely.

Subclasses: InvoiceJetConnectionError (no response) and InvoiceJetTimeoutError. The CLI takes --timeout <seconds> and --max-retries <n>; the MCP server reads INVOICEJET_TIMEOUT and INVOICEJET_MAX_RETRIES.

CLI & MCP

Built on the same SDK: the invoicejet CLI for scripts and pipelines, and the MCP server that gives Claude, Cursor, and any Model Context Protocol client invoice-extraction tools.

Base URL

Base URL
https://nzsktgwehyzltgagloox.supabase.co/functions/v1/api

All endpoints are versioned under /v1. Breaking changes ship as a new version prefix; /v1 stays stable.