---
title: "Publish with audio you synthesized locally (deprecated)"
method: POST
path: "/api/v1/presentations/publish-narrated"
tags: ["Publish"]
deprecated: true
---

# Publish with audio you synthesized locally (deprecated)

`POST /api/v1/presentations/publish-narrated`

## Request

- Base URL: `https://bisque.today`
- URL: `https://bisque.today/api/v1/presentations/publish-narrated`
- Auth: HTTP bearer

> **Deprecated.**

Versioned address of `/api/presentations/publish-narrated` — the same endpoint and contract. Superseded by `POST /v1/presentations`, which puts the slides up before narrating them. This one publishes nothing until every slide is narrated, so the watch URL does not work until the whole run finishes. It keeps working. Narrate each slide with the `bisque-voice` CLI, then post the HTML plus per-slide MP3s and word timings; slides you omit from `audio` carry their audio forward when their narration text is unchanged. API-key callers only.

## Headers

- `Idempotency-Key` string

## Request body

- PublishNarratedRequest
  - `indexHtml` string, required: The whole `html-presentation/v1` file.
  - `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` string[]: 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: 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.
  - `assets` object: Page assets (fonts, images) keyed by bundle path.

## Response `200`

Accepted; upload the bytes to `uploadUrls`, then POST `completeUrl`.

- PublishNarratedResult
  - `requestId` string, required
  - `presentationId` string, required
  - `webUrl` string, uri
  - `uploadUrls` object[], required: One signed PUT target per file whose bytes the server does not already have.
  - `completeUrl` string, uri, required: POST here with `files` once every upload succeeded.
  - `files` object[], required: Echo back verbatim as the `files` of the complete call.

## Other responses

- `400`: Audio or HTML failed validation; the message names the slide.
- `401`: Missing or invalid credential.

---

[API](https://skmtc.dev/bisque/apis/bisque-api.md) · [All operations](https://skmtc.dev/bisque/apis/bisque-api/llms.txt) · [OpenAPI document](https://skmtc.dev/bisque/apis/bisque-api/revisions/5dd7a3c62937?raw)
