---
title: TypeScript SDK
description: @sume-com/sdk — install, create a client, authenticate, and run a Format end to end from Node, Bun, Deno, or Workers.
---

`@sume-com/sdk` is the official TypeScript client for `api.sume.com`. It covers every
operation in the public OpenAPI schema, plus the helpers every partner otherwise
writes by hand: [`subscribeFormatRun`](/sdk/runs), [`waitForRun`](/sdk/runs),
[`waitForJob`](/sdk/runs), [`uploadFile`](/sdk), and
[`verifyWebhook`](/sdk/webhooks).

```bash
npm install @sume-com/sdk
```

Published as [`@sume-com/sdk@0.2.0`](https://www.npmjs.com/package/@sume-com/sdk),
MIT licensed, with **no runtime dependencies**. It needs `fetch` and WebCrypto —
Node 18+, Bun, Deno, or Cloudflare Workers.

**This page is not a method reference.** Request and response fields come from the
[API reference](/api/reference) and live OpenAPI
(`https://api.sume.com/reference/json`), which stay the source of truth. What follows is
the client-shaped part: the factory, auth, and the helpers that have no REST
equivalent.

## Create a client

```ts
import { createSumeClient } from "@sume-com/sdk";

const client = createSumeClient({
  apiKey: process.env.SUME_API_KEY!,
});
```

| Option | Default | Notes |
|---|---|---|
| `apiKey` | — | Required. A Developer API key from [API Keys](https://www.sume.com/dashboard/api-keys). |
| `baseUrl` | `https://api.sume.com` | Point at `https://api.dev.sume.com` for development. |
| `fetch` | the runtime's `globalThis.fetch` | A seam for instrumentation, retries, or tests. |

**Pass `client` on every call.** Operations accept a module-level default client, but
that default is created without a base URL or a key — it is there so the generated code
compiles, not so you can skip the factory. Thread the client you made:

```ts
import { createSumeClient, listFormats } from "@sume-com/sdk";

const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });
const { data } = await listFormats({ client });
```

## Authentication

The client sends **`x-api-key` only**. It does not set `Authorization`, and you should
not add one yourself.

The API accepts either header alone (see [Authentication](/authentication)), but it
rejects **both at once**: a request carrying `Authorization: Bearer` and `x-api-key`
together fails `401 unauthorized` with `Send only one API key credential.` There is no
precedence rule — neither header wins. So an `Authorization` header added on top of the
client's own — a session token, a gateway's credential, an interceptor you forgot about
— fails the request even though `x-api-key` was correct. If you wrap `fetch` via the
`fetch` option, make sure your wrapper is not adding one.

Your key needs `formats:read` and `formats:write` to run Formats. Scopes are fixed when
a key is created and cannot be added later; an older key returns `403
insufficient_scope` on every run. Create a new one and rotate.

**Team Formats need a team (workspace) key.** A personal key calling a team Format
fails with `403 workspace_key_required` — see [Calling a Format](/formats/call#team-formats-need-a-team-key).

**Server-side only.** A Sume API key spends your credits, and there is no browser-safe
variant. Never ship one to client JavaScript, a mobile bundle, or a `NEXT_PUBLIC_*`
variable — put your own endpoint in front and construct the Sume request there. The full
custody rules are in [Embed a Format in your product](/cookbooks/embed-a-format#1-key-custody).

## A Format run, end to end

Prefer **`subscribeFormatRun`** for Formats: one call creates the run and waits for the
terminal receipt. Pair it with [run webhooks](/agents/run-webhooks) when you can skip
the wait entirely.

```ts
import { createSumeClient, subscribeFormatRun } from "@sume-com/sdk";

const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });

const run = await subscribeFormatRun({
  client,
  path: { handle: "acme", slug: "product-promo" },
  idempotencyKey: "order-8823-promo-v1",
  body: {
    input: { product_url: "https://shop.example.com/p/8823" },
    generation_spend_cap_usd: 3,
  },
  onStatus: (status, snapshot) => console.log(status, snapshot.next_action),
});

if (run.status === "completed") {
  console.log(run.primary_output_url);
}
```

What to expect today:

- **`subscribeFormatRun` polls.** There is no SSE stream, so `onStatus` reflects status
  polling rather than a push feed. For progress detail while you wait, read
  `events_url` — a phase timeline, not a log feed. See
  [Watch a run progress](/formats/runs#watch-a-run-progress).
- **Prefer a webhook** when delivery is available for your environment: pass
  `communication.webhook_url` on create (or skip the wait and handle the push). See
  [Verifying webhooks](/sdk/webhooks).
- **Default timeout is 20 minutes** (video Formats routinely run 10–20). It resolves for
  any terminal status; it throws only when the create call itself is refused.
- **Generated operations do not throw on an API error.** They resolve with
  `{ data, error, response }`. `subscribeFormatRun` / `waitForRun` throw, because a
  poll loop has nowhere to put a non-result.

Use [`waitForRun`](/sdk/runs) when you already have a run id (Action / Agent
Completion, or a create you made yourself), and [`waitForJob`](/sdk/runs) for
**generation jobs** — `/v1/image-1.0/generate`, `/v1/video-1.0/generate`, the
Avatar routes — which live at `/v1/jobs/:id` and are not runs.

## Where to go next

| You want | Read |
|---|---|
| Create + wait (or poll an existing run or job) | [Waiting for runs and jobs](/sdk/runs) |
| Verify a signed webhook delivery | [Verifying webhooks](/sdk/webhooks) |
| Exact request and response fields | [API reference](/api/reference) |
| The whole partner integration | [Embed a Format in your product](/cookbooks/embed-a-format) |

## Scope of this section

These pages document the hand-written surface: the client factory and the helpers.
Everything else the package exports is generated from the same OpenAPI schema the [API
reference](/api/reference) describes, one function per operation, named after the
operation id — `listFormats`, `createFormatRun`, `getFormatRunStatus`, `cancelFormatRun`,
and so on. Your editor's autocomplete is a better catalog than a copy of the schema would
be, so there is not one here.
