TypeScript
The generated TypeScript SDK: readable source, zero runtime dependencies, ESM, and the package the CLI and MCP server are built on.
The TypeScript SDK is the reference implementation of every feature on the SDKs overview, and the package the other TypeScript platforms import. This page covers what is specific to the TypeScript package.
Package
- The npm name derives from your API's title. The Acme API produces
acme. Set a scoped or different name per project under package names, for example@acme/api. - Zero runtime dependencies. The only entries in
package.jsonare dev dependencies needed to build:typescriptand@types/node. - ESM only.
"type": "module", anexportsmap with animportentry, norequire(). Node 18 or newer, every modern bundler, browsers, and edge runtimes. - Tree-shakeable: one module per resource and
"sideEffects": false, so bundlers drop the resources you never call. - Ships as readable TypeScript source and compiles with
npm run build.main,types, andexportspoint intodist/, which holds the compiled JavaScript,.d.tsdeclarations, and declaration maps.
What is exported
import {
AcmeClient, // the client
environments, // named servers, when the spec declares two or more
VERSION, // the package version
unwrap, // ApiResult -> data, or throw the typed error
NotFoundError, // one class per documented status
UnexpectedApiError, TransportError, ValidationError,
AccountStatus, // enums as runtime values
formatDebugEvent,
} from "acme";
import type { Account, AccountsListParams, AccountsListError, ApiResult, RequestOptions } from "acme";Every schema is a type. Every operation has a <Resource><Method>Params type when it takes parameters and a <Resource><Method>Error union.
Environment variables
The client reads two, and neither is a credential:
| Variable | Effect |
|---|---|
ACME_DEBUG=1 | Turns on debug logging when debug is not set. |
ACME_WEBHOOK_KEY | The webhook signing key when webhookKey is not set. |
Credentials are passed explicitly. That keeps the client safe in browsers and edge runtimes, where process.env may not exist. The generated CLI and MCP server are the pieces that read ACME_TOKEN and ACME_BASE_URL.
Idioms
- Nothing throws on HTTP errors. Every call returns
ApiResult<T, E>with a typed error union.unwrapopts into exceptions. See Results and errors. PagePromisefor list operations:for awaitwalks every page,awaitreturns one page. See Pagination.readOnlybecomesOmit. A referenced schema in a request position appears asOmit<Account, "id" | "balance">.- Enums are values.
AccountStatus.FROZENexists at runtime andAccountStatusis also the literal-union type. - Streams are
AsyncIterable<SseEvent>. See Streaming. - Webhooks verify with WebCrypto, so
unwrapisasyncand the same code runs on Node, browsers, edge runtimes, and Workers. - Async by nature. Every call returns a promise; there is no separate async client because there is nothing else to be.
Uploads
A multipart/form-data field is typed Blob. Pass a File (a Blob with a name, global in browsers and Node 20+) so the part carries a filename; a bare Blob is sent under the field name. The other fields of the body travel alongside as form parts, nested values as JSON. A raw binary body (application/octet-stream, image/png, ...) is a Blob too, sent under the spec's content type. fetch sets the multipart boundary.
await client.files.create({ file: new File([bytes], "report.pdf", { type: "application/pdf" }), purpose: "evidence" });Unions
oneOf and anyOf become TypeScript unions of the variant types, narrowed the way you narrow any union: on a discriminator property, or with in checks. Nothing is wrapped and nothing is guessed at runtime; the payload is the JSON as sent.
Response metadata
Every ApiResult, success or failure, carries response: { status, headers, requestId }, so rate-limit headers, a Location, or a request id to quote are one property away without going through the onResponse hook. Error classes carry the same response.
const result = await client.accounts.get("acct_123");
result.response.headers.get("x-ratelimit-remaining");
result.response.requestId;GraphQL
A GraphQL schema generates one method per query and mutation field on client.query and client.mutation. Arguments are the first argument and become variables. Every scalar field to depth 2 is selected by default, with a fragment per concrete type for unions and interfaces, and the optional second argument is a typed selection that replaces it and narrows the result: client.query.account({ id }, { id: true, owner: { email: true } }). Unions and interfaces take on: { TypeName: { ... } } and come back discriminated by __typename. A raw selection-set string is the escape hatch. Connection fields return a PagePromise like everything else. Errors in a 200 come back as GraphQLRequestError on the error side of the result, carrying the raw errors array. See Generate from GraphQL.
Transport
Everything rides on platform fetch. Pass fetch: to substitute your own for proxies, recording, or tests; connection reuse is whatever the runtime's fetch does (Node's undici and every browser pool keep-alive connections by default). Per-call signal composes with the per-attempt timeout, so an AbortController cancels a request, a paginated walk, or a stream. Streams are read incrementally through the same fetch.
What else is in the package
tests/*.test.mjs: one smoke test per operation onnode:testand anode:httpmock.npm testbuilds and runs them. No framework installed, nothing contacted.api.md: the complete surface reference in one file: every method, parameter table, return type, and error class.AGENTS.md: context for coding agents.- With the
cliplatform,src/cli.tsand theacmebin. With themcpplatform,src/mcp.ts, theacme-mcpbin,src/worker.ts, andwrangler.toml.
The files field publishes dist/, src/, and api.md.
Overview
A typed client for your API with zero runtime dependencies, in TypeScript, Python, or Go. Typed errors, auto-pagination, retries, hooks, and validation, generated from your spec.
Python
The generated Python SDK: a typed, zero-dependency client built on the standard library, written the way Python developers expect.