---
title: "Bisque SDK"
description: "@bisquecloud/sdk, the TypeScript client: publish from a script or a CI job."
canonical: https://bisque.cloud/docs/sdk
---

# SDK

@bisquecloud/sdk, the TypeScript client: publish from a script or a CI job.

Page: https://bisque.cloud/docs/sdk

`@bisquecloud/sdk` is the TypeScript client for the Bisque API: publish a
presentation from a script, a CI job, or a server, and read any shared one back
as text. It has zero dependencies and runs anywhere `fetch` does: Node 18 and
later, Bun, Deno, and browsers. The current version is 0.2.0, under the MIT
license.

```sh
npm install @bisquecloud/sdk
```

## Read a presentation, no sign-in

```ts
import { Bisque } from "@bisquecloud/sdk";

const bisque = new Bisque();
const ctx = await bisque.presentations.context({
  url: "https://bisque.today/p/siderakis/claude-system-card",
});
console.log(ctx.title);
for (const slide of ctx.transcript) console.log(slide.startSec, slide.text);
```

Public and unlisted presentations need no credential. `ctx.contextMd` carries
the presentation's `context.md` when it has one.

## Publish

Publishing needs a credential: an API key from
[bisque.cloud/setup/keys](https://bisque.cloud/setup/keys), or an OAuth 2.1
token for a hosted agent. [auth.md](https://bisque.today/auth.md) walks through
both. Pass the key as `apiKey` when you construct the client; it is sent as a
bearer token on every call that needs one.

```ts
const bisque = new Bisque({ apiKey: process.env.BISQUE_API_KEY });

// 1. Read the authoring format. Never write html-presentation/v1 from memory.
const spec = await bisque.presentations.spec();

// 2. Write index.html to that spec (your agent does this), then publish.
const created = await bisque.presentations.create({
  indexHtml,
  slug: "release-notes-2026-08",
  visibility: "unlisted",
});

// 3. Narration finishes in the background; wait for it.
const status = await bisque.presentations.waitUntilReady(
  created.presentationId,
);
console.log(status.webUrl); // https://bisque.today/p/<handle>/release-notes-2026-08
```

`create` sends an `Idempotency-Key` on every call (a UUID unless you pass
`{ idempotencyKey }`), so a retried request replays the first result instead
of publishing twice.

## The calls

| Call                                               | What it does                                                                           |
| -------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `presentations.spec(part?)`                        | The authoring format, or one module of it (`charts`, `macos`, and so on), as markdown. |
| `presentations.context(ref)`                       | Metadata, per-slide transcript, and `context.md` for any shared presentation.          |
| `presentations.list(params?)` / `listAll()`        | Your presentations, one page or every page.                                            |
| `presentations.create(req)`                        | Create from HTML and have the server narrate it.                                       |
| `presentations.status(id)` / `waitUntilReady(id)`  | Narration and publish progress.                                                        |
| `presentations.startCreation(req)`                 | Create from HTML and narrate it yourself. The slides are viewable immediately, silent. |
| `presentations.addSlideAudio(id, slideKey, audio)` | Give one slide its narration; anyone watching sees it appear.                          |
| `presentations.finalize(id)`                       | Finish the creation and claim its version.                                             |
| `presentations.publishNarrated(req)`               | Deprecated. One call, but nothing is viewable until every slide is narrated.           |
| `oembed(url)`                                      | The oEmbed payload for a watch URL.                                                    |
| `ask(query)`                                       | A natural-language question over the docs and public presentations.                    |
| `openapi()`                                        | The OpenAPI 3.1 document this SDK wraps.                                               |

Every method takes an optional `{ signal }` for cancellation. The client talks
to `https://bisque.today` unless you pass `baseUrl`.

## Errors and rate limits

Failures throw `BisqueError` with `status`, the API's stable `code`
(`NOT_FOUND`, `CONTEXT_RATE_LIMITED`, and so on), and a `requestId` to quote
in a bug report. A 429 or 5xx is retried twice, honouring `Retry-After`;
`maxRetries` changes that. The rate-limit headers from the latest response are
on `bisque.lastRateLimit`.

## Reference

- The REST API it wraps: [API](/docs/api), and the OpenAPI document at
  [bisque.today/openapi.json](https://bisque.today/openapi.json)
- Credentials: [bisque.today/auth.md](https://bisque.today/auth.md)
- The same tools over MCP: [MCP](/docs/mcp)
- Source: [github.com/bisque-cloud/presenter/tree/main/sdk](https://github.com/bisque-cloud/presenter/tree/main/sdk)
