---
title: "POST /v1/presentations"
description: "Put the slides up now and narrate them one at a time."
canonical: https://bisque.cloud/docs/api/presentations/create
---

# Create a presentation

Put the slides up now and narrate them one at a time.

Page: https://bisque.cloud/docs/api/presentations/create

`POST /v1/presentations` · API v1 · [versioning](/docs/api/versioning)

Start a creation: send the HTML and the assets, and the slides are viewable at the returned `webUrl` straight away — silent until narration arrives. The response names the slides that still need narrating (`needsAudio`) and the ones whose audio carried forward from last time (`reused`), with an upload target for each asset and each slide. Narrate each slide with the `bisque-voice` CLI, PUT the MP3 to its target, then PATCH the slide. While the creation is open it can take more slides (`PATCH /v1/presentations/{presentationId}`): the presentation document carries `live: { revision, startedAt }`, `revision` rises on every append, and the watch page appends the new slides in place. API-key callers only.

## Authentication

Send an API key as `Authorization: Bearer bisque_live_…`. Keys come from [bisque.cloud/setup/keys](https://bisque.cloud/setup/keys); see [Authentication](/docs/api/authentication).

A unique key per logical request (a UUID). A retry with the same key and body replays the first response with `Idempotent-Replayed: true` instead of publishing again; the same key with a different body is a 422 `IDEMPOTENCY_KEY_REUSED`. Keys last 24 hours.

## Request

`Content-Type: application/json`. Required: `indexHtml`.

| Field | Type | Meaning |
| --- | --- | --- |
| `indexHtml` | string, required | The whole `html-presentation/v1` file. |
| `audio` | array of object | One entry per narrated slide you synthesized. Omit a slide to carry its last-published audio forward when its narration text is unchanged; omit the array to carry every slide forward. |
| `assets` | object | Page assets (fonts, images) keyed by bundle path. |
| `title` | string | Overrides the title parsed from the HTML. |
| `slug` | string | URL slug under your channel. Reuse it to republish. |
| `presentationId` | string | Republish an existing presentation by id instead of slug. |
| `handle` | string | Which of your channels to publish on; defaults to your account's. |
| `dryRun` | boolean | Sandbox: run every check a real create runs (format, slug and org conflicts, tier cap, credit preflight) and write nothing. The reply is a 200 with status `validated`. |
| `visibility` | public · unlisted · private · org | Who can open the watch link. Unlisted unless you say otherwise; `org` publishes into the bisque.team organization named by `org`. |
| `org` | string | bisque.team organization slug; publishes into the company space. |
| `contextMd` | string | Agent-facing background shipped with the bundle as `context.md`. |
| `designMd` | string | Design notes shipped with the bundle. |
| `voiceId` | string | Narration voice tag; defaults to the account's saved voice. |
| `madeWith` | array of up to 8 of string, up to 80 characters | Models credited with making this presentation — e.g. ["Claude Opus 5", "Kokoro af_heart"]. Free text, shown to viewers in the watch page's ⋯ menu. Omit to keep what a previous publish recorded; send `[]` to clear it. |
| `description` | string, up to 5,000 characters | Plain-text description shown under the player on the watch page, with web URLs linked — a summary, then the sources. Omit to keep what a previous publish sent; send an empty string to clear it. |
| `speechSpeed` | number | Narration speed. 1.0 is normal. |
| `voiceStability` | number | How closely the voice keeps to its reference, for voices that take it. Omit for the voice's default. |

## Example

```bash
curl -X POST https://bisque.cloud/v1/presentations \
  -H "Authorization: Bearer $BISQUE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data @body.json
```

## Response

**200**: The creation is open and the slides are live.

Errors:

- `401`: Missing or invalid credential.

## Other endpoints

| Page | Call | What it does |
| --- | --- | --- |
| [Get a presentation](/docs/api/presentations/get) | `GET /v1/presentations/{presentationId}` | The open creation, to resume it from a new session. |
| [Add slides](/docs/api/presentations/add-slides) | `PATCH /v1/presentations/{presentationId}` | Append sections while the creation is open. |
| [Update a slide](/docs/api/presentations/update-slide) | `PATCH /v1/presentations/{presentationId}/slides/{slideKey}` | Give one slide its narration after the MP3 is uploaded. |
| [Wait for an answer](/docs/api/presentations/wait-for-answer) | `GET /v1/presentations/{presentationId}/surveys/{surveyId}/response` | Hold for the viewer's answer to a question on a slide. |
| [Finalize](/docs/api/presentations/finalize) | `POST /v1/presentations/{presentationId}:finalize` | Claim the version. Slides still without audio stay silent. |
| [Read as text](/docs/api/presentations/read-as-text) | `GET /api/presentations/context` | Any shared presentation as a transcript. No credential needed. |
