Build your integrationTargetsSDKs

TypeScript

Generate a typed, zero-dependency TypeScript client for your API.

Typeship generates a typed TypeScript client for your API as a focused, zero-dependency npm package. This page covers the TypeScript-specific surface; shared client behavior is on the SDK overview.

CLI and MCP packages are generated and released separately.

Package

  • The npm name initially derives from your API’s title. Configure its repository Delivery under Targets → TypeScript SDK → npm package name, for example parcel-client for the fictional Parcel API. The public Delivery field is package_name; separate Targets can have different identities.
  • Zero runtime dependencies. The only entries in package.json are dev dependencies needed to build: typescript and @types/node.
  • ESM only. "type": "module", an exports map with an import entry, no require(). Node 20 or newer, every modern bundler, browsers, and edge runtimes.
  • Bundler-friendly: "sideEffects": false. The validation schema table is a separate module the client loads only when you turn on validate; bundlers that split dynamic imports (Vite, Rollup, webpack, or esbuild with --splitting) keep it out of your main bundle.
  • Ships as readable TypeScript source and compiles with npm run build. main, types, and exports point into dist/, which holds the compiled JavaScript, .d.ts declarations, and declaration maps.

What is exported

import {
  ParcelClient,          // the client
  environments,        // named servers, when the spec declares two or more
  VERSION,             // the package version
  NotFoundError,       // one class per status family: 400, 401, 403, 404, 409, 422, 429, 5xx
  ApiError, SdkError, UnexpectedApiError, RateLimitError, ServerError, PayloadError, ResponseParseError, TransportError, ValidationError,
  ShipmentStatus,       // enums as runtime values
  formatDebugEvent,
} from "parcel-client";
import type { Shipment, ShipmentsListParams, ShipmentsListError, RequestOptions } from "parcel-client";

Every schema is a type. Every operation has a <Resource><Method>Params type when it takes parameters and a <Resource><Method>Error union.

Choose credentials for each endpoint

When your API has more than one security scheme, customers can pass credentials by the names in components.securitySchemes. For example, an API with customer bearer auth and a serviceKey header exposes credentials.customer and credentials.serviceKey in ClientOptions. Token and API-key values can be strings or callbacks; basic-auth values contain username and password.

Each request sends the first complete permitted combination in the Spec. Alternatives are checked in order. If an endpoint requires two schemes together, both must be available; a partial combination sends neither. Public endpoints receive no generated credentials. Callbacks run only for selected credentials, before each attempt. Your API still enforces token validity and permissions.

Convenience options such as bearerToken, basicAuth, and apiKey remain available when they identify one scheme. Use named credentials to distinguish multiple registrations with the same credential type. Explicit defaultHeaders, per-call headers, and onRequest hooks remain under the application's control and can implement custom authentication.

The generated MCP uses this same request routing. Scope requirements stay attached to each named alternative in operation metadata and tool descriptions.

Environment variables

The client reads the following environment variables. API credentials are passed through client options; the webhook key below is a separate signing secret:

VariableEffect
PARCEL_DEBUG=1Turns on debug logging when debug is not set.
PARCEL_WEBHOOK_KEYThe 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 PARCEL_TOKEN and PARCEL_BASE_URL.

Idioms

  • Awaited calls resolve to data or throw. Status family errors (NotFoundError, RateLimitError, and the rest) extend ApiError and are thrown whether or not the operation documents the status; transport, parse, GraphQL, and validation failures have their own classes. See Results and errors.
  • PagePromise for list operations: await returns the first Page; for await walks every page. Either path throws the typed error if a page fails. See Pagination.
  • Data keeps its wire names. Body fields, query parameters, and response fields use the names in your Spec, quoted when a name is not a JavaScript identifier: client.shipments.list({ page_size: 20, "created[gte]": "2026-01-01" }). Path parameters are positional camelCase arguments, and header parameters are camelCase keys such as idempotencyKey.
  • Directional models stay honest. A component whose request and response contracts differ becomes ShipmentWrite and ShipmentRead; identical contracts keep the clean Shipment name.
  • Enums are values. Request enums are closed. Response enums preserve documented autocomplete while accepting (string & {}), so a new server value does not make a successful response impossible to represent.
  • Streams are AsyncIterable<SseEvent>, or AsyncIterable of the parsed event type for the ...Stream method of an operation that streams on request. See Streaming.
  • Webhooks verify with WebCrypto, so unwrap is async and 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, and an array of files is Blob[], sent as one part per file. Pass a File (a Blob with a name, global in browsers and Node 20+) so the part carries its filename and type; a bare Blob is named after its field. Anything else in a file field, such as a path string or a Node stream, is rejected with a ValidationError before the request is sent; read the file first with new File([await readFile(path)], name). The other fields travel alongside: an object is one JSON part (application/json), and a type the spec's encoding names for a field is used for that part. A raw binary body (application/octet-stream, image/png, ...) is a Blob too, sent under the spec's content type.

A response whose media type is not JSON is typed Blob (audio, a file, an archive) or string (text/*).

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

Awaited list calls return a Page with response: { status, headers, requestId, rawBody }. For other successful calls, use onResponse to inspect HTTP metadata. HTTP and parse errors expose the response on the error. Every SDK error has a stable code, status, requestId, body, and a message with the next step.

const page = await client.shipments.list();
page.response.headers.get("ratelimit-remaining");
page.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.shipment({ id }, { id: true, recipient: { 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. Errors in a 200 throw GraphQLRequestError, an ApiError 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 on node:test and a node:http mock. npm test builds 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 that call your API through the package.
  • PUBLISHING.md: how to build, publish, and customize the package. The README stays focused on the package's users.
  • CLI and MCP files are never included in this package. They belong to their own Targets and destination repositories.

The files field publishes dist/, src/, and api.md.

On this page