Skip to content

TypeScript SDK

The @xos/sdk client, generated from the OpenAPI document, with typed models, pagination, filters, idempotency, ETags and problem errors.

@xos/sdk covers every operation in the OpenAPI document. Its models, method signatures and operation table are generated from the document by CI and never edited by hand, so a new operation appears in the SDK as soon as it appears in the API. It runs on Node.js 22 or later, in browsers and on edge runtimes, with no dependencies.

Create a client

import { XosClient } from "@xos/sdk";

const xos = new XosClient({
  baseUrl: "https://api.ghxstship.tech/v1",
  apiKey: process.env.XOS_API_KEY,
});

Instead of apiKey, pass accessToken for a session token, or getToken to supply a fresh token before every request. Other options: maxRetries (default 2), timeoutMs (default 30000) and a custom fetch.

Call operations

Each resource is a property and each operation a method named after its operation id: projects.list is xos.projects.list(), purchaseOrders.approve is xos.purchaseOrders.approve(id, body).

const { data: project, etag } = await xos.projects.get(projectId, {
  fields: ["name", "project_state"],
});

await xos.projects.update(projectId, { name: "Harborfront Fall Series" }, { ifMatch: etag! });

await xos.records.transition(recordId, {
  expected_state: "Scheduled",
  to_state: "Blocked",
  blocker_text: "Waiting on the rigging plot.",
});

Every result has data, status, etag, rateLimit and headers. Path parameters come first, then the body, then query parameters, then options.

Lists

list() returns one page with data and nextCursor. listAll() iterates every row across pages. Filters and sorting are typed against the row:

for await (const po of xos.purchaseOrders.listAll({
  filter: { po_state: { eq: "Approved" } },
  sort: ["-created_at"],
  fields: ["id", "po_number", "currency_code"],
})) {
  console.log(po.po_number);
}

Writes

POST methods send an Idempotency-Key automatically and reuse it on retries. Pass idempotencyKey to make a call safe across restarts. Updates require ifMatch; the type system will not let you omit it.

Errors

import { XosPreconditionFailedError, XosRefusalError, XosValidationError } from "@xos/sdk";

try {
  await xos.purchaseOrders.approve(poId, {});
} catch (error) {
  if (error instanceof XosRefusalError) console.log(error.refusal, error.reason, error.rule);
  else if (error instanceof XosValidationError) console.log(error.errors);
  else if (error instanceof XosPreconditionFailedError) console.log("Read again and retry");
  else throw error;
}

See Errors and refusals for every class.

Webhooks

verifyWebhookSignature and signWebhookPayload are exported from @xos/sdk/webhooks. See Webhooks.

Calling an operation by id

xos.request(OPERATIONS["projects.get"], { path: { id } }) calls any operation from the generated table. The CLI and the MCP server are built this way.