SuperBooksDevelopers
SDKs

TypeScript

The official superbooks npm package — typed per-domain methods, error handling, and retries.

The superbooks package wraps the MCP API in typed, per-domain methods, so you call sb.transactions.list() instead of assembling JSON-RPC envelopes.

Ships both ESM and CommonJS, requires Node.js 20 or newer, and has zero runtime dependencies.

Install

npm install superbooks

Creating a client

import { SuperBooks } from "superbooks";

const sb = new SuperBooks({ apiKey: process.env.SUPERBOOKS_API_KEY });

apiKey falls back to the SUPERBOOKS_API_KEY environment variable. If neither is set, the constructor throws a SuperBooksError with code unauthorized — so you find out at construction, not on the first call.

OptionDefaultNotes
apiKeySUPERBOOKS_API_KEYMinted at Settings → Developer. See Authentication.
baseUrlhttps://api.superbooks.ioA URL already ending in /mcp is accepted as-is.
timeoutMs60000Per request. Pass 0 to disable.
maxRetries2See Retries.
maxRetryDelaySeconds60Caps how long a Retry-After may park a call.
headersMerged into every request. Cannot override Authorization.
fetchglobal fetchInjection point for proxies and tests.
clientInfo{ name, version } advertised during MCP initialize.
throwOnToolErrortrueSee Error handling.

Note the exact names: timeoutMs, not timeout; maxRetries, not maxAttempts.

Calling tools

Each MCP tool maps to a method on its domain — strip the domain prefix, camelCase the rest:

const { data } = await sb.transactions.list({
  from: "2026-01-01",
  to: "2026-03-31",
  limit: 50,
});

await sb.invoices.createDraft({
  customer_id: "00000000-0000-0000-0000-000000000000",
  currency: "USD",
  issue_date: "2026-04-01",
  due_date: "2026-04-30",
  line_items: [{ name: "Consulting", quantity: 10, price: 150 }],
});

Three worth knowing because they read a little oddly: bank_accounts_list is sb.bankAccounts.list(), search_global is sb.search.global(), and delete and void are legal method names — sb.transactions.delete() and sb.invoices.void() are real.

Every tool, with its full parameter list, is in the API reference.

What a call returns

A ToolResult, not plain parsed JSON:

interface ToolResult {
  data: unknown;
  content: ContentBlock[];
  isError: boolean;
}

data is the parsed payload, so destructuring is the idiomatic form:

const { data } = await sb.customers.list({ limit: 5 });

Argument types are exported; result types are not. Every tool has a PascalCase(toolName) + "Params" type — TransactionsListParams, InvoicesCreateDraftParams, BankAccountsListParams.

The asymmetry is deliberate: input schemas are a published contract served by tools/list, but result shapes are not part of that contract, so data is unknown rather than a promise the server never made. Narrow it yourself:

const { data } = await sb.customers.list({ limit: 5 });
const { items } = data as { items: Array<{ id: string; name: string }> };

Pagination

Manual — there is no auto-paginating iterator.

The field names are asymmetric: you pass cursor in and read nextCursor out. nextCursor is null on the last page.

let cursor: string | undefined;

do {
  const { data } = await sb.transactions.list({ cursor, limit: 100 });
  const page = data as { items: unknown[]; nextCursor: string | null };

  for (const transaction of page.items) {
    // ...
  }

  cursor = page.nextCursor ?? undefined;
} while (cursor);

limit accepts 1–100 on every paginated tool, but the default varies by tool — 25 for transactions.list, invoices.list, customers.list and tracker.listProjects, 50 for tracker.listEntries, 30 for search.global, and 10 for reports.topCustomers. Pass it explicitly rather than relying on the default. Prefer large pages: one call for 100 rows costs a hundredth of the rate-limit budget that a hundred single-row calls would.

Error handling

Everything extends SuperBooksError, which carries status?: number, rpcCode?: number, and a code — one of unauthorized, forbidden, rate_limited, bad_request, server_error, connection_error, protocol_error, or tool_error. A single instanceof therefore catches the whole surface:

import {
  SuperBooks,
  SuperBooksError,
  SuperBooksRateLimitError,
} from "superbooks";

try {
  const { data } = await sb.transactions.list({ limit: 10 });
} catch (error) {
  if (error instanceof SuperBooksRateLimitError) {
    console.error(`Rate limited; retry in ${error.retryAfterSeconds}s`);
  } else if (error instanceof SuperBooksError) {
    console.error(error.code, error.status, error.message);
  }
  throw error;
}
ConditionClassExtra fields
401SuperBooksAuthError
403SuperBooksPermissionError
429SuperBooksRateLimitErrorretryAfterSeconds?
Network, timeout, abortSuperBooksConnectionError
Malformed or non-JSON-RPC replySuperBooksProtocolError
Tool ran and refusedSuperBooksToolErrortoolName, rpcCode, data

A JSON-RPC error on a tool call raises SuperBooksToolError with both toolName and rpcCode populated.

There is no requestId field. The API returns no correlation id, so do not build logging or support workflows around one.

SuperBooksToolError is thrown by default when a tool reports isError. Pass throwOnToolError: false to get the ToolResult back with isError: true instead — the better shape when refusals are ordinary control flow for you rather than exceptions.

Retries

On by default, but narrower than you might assume.

Only 429 is retried. Two retries by default, so three requests worst case. Retry-After is honoured and capped at maxRetryDelaySeconds (60); if the header is missing or unparseable, the delay falls back to 2^attempt seconds.

5xx is deliberately not retried. A 429 was rejected before the tool ran, so replaying it is safe. A 500 from invoices_send may mean the email already went out — and tool calls are not idempotent, so replaying a write is the caller's decision, not the client's.

Using SuperBooks from an AI client

The SDK is for writing code. If you want Claude, Cursor, or another AI client to work with your SuperBooks data, you do not need this package at all — connect the client to the hosted endpoint directly:

claude mcp add --transport http superbooks https://api.superbooks.io/mcp \
  --header "Authorization: Bearer sb_your_api_key_here"

See Connecting AI clients for per-client setup.

On this page