---
title: "Set up or change a show."
method: PATCH
path: "/publishing-series/{seriesId}/show"
tags: ["Shows"]
---

# Set up or change a show.

`PATCH /publishing-series/{seriesId}/show`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/publishing-series/{seriesId}/show`
- Auth: HTTP bearer

The show's setup (its cast, tone, format and language live in the Series Bible and are refused here). Only the fields sent change: `sources[]` ({ adapter, params, label }: rss { feedUrl (required), maxItems, lookbackDays, readArticles, order }; web-search { query (required), topic, site, maxItems, lookbackDays }; hackernews { count, minComments, itemId, skipObituaries }; github { repo (required), lookbackDays }; url-watch { url (required), label }; upload { text (required), label }); `schedule[]` (see its own description); `episodePages`; `episodesAtOnce` (1–3, default 2: how many episodes of a run are made at once; they still publish in order); `profanity` (none|mild|open); `punchUp` (sharper jokes, with a clean first line); `hardLines[]` (words never said, checked across the whole script); `commenterNames` (handles|pseudonyms: made-up names, the default for a new show); `episodeNotes` (direction for the writer, ≤8,000); the planner fields, each replacing the platform's default: `planningNotes[]` (≤12 × 220), `castNotes` (≤1,000), `writingStyle` (≤500), `objective` (≤400), `outcome` (≤400), `musicStyle` (≤500), `sfxPolicy` (≤500); `themePrompt` (what the theme sounds like, ≤240); `sounds[]` ({ name, prompt, matches[] }, ≤24); `voiceEffects[]` ({ character, effect: "autotune", when: { direction }, sound? }, ≤8); `memory` ({ rotating[], escalating[] }); `episodeCap` and `monthlyCap` (Studio Credits; setting them takes `userConfirmed: true`); `holdForReview` (each episode waits for you to publish or drop it). A text over its cap is refused, never shortened. Example: {"sources":[{"adapter":"rss","label":"arXiv robotics","params":{"feedUrl":"https://rss.arxiv.org/rss/cs.RO"}}],"schedule":[{"every":"week","at":"07:00","weekday":"monday","covers":"roundup","episodes":1}],"episodePages":9,"profanity":"none"}. The first write on an audio series makes it a show; refused on a season run, on a video series, and (409 `project_not_story`) on a product project. A show that is on keeps a setup it can run on: a change that would stop it is refused, naming why.

## Request body

- ShowSetupUpdateRequest: The show's setup (its cast, tone, format and language live in the Series Bible and are refused here). Only the fields sent change: `sources[]` ({ adapter, params, label }: rss { feedUrl (required), maxItems, lookbackDays, readArticles, order }; web-search { query (required), topic, site, maxItems, lookbackDays }; hackernews { count, minComments, itemId, skipObituaries }; github { repo (required), lookbackDays }; url-watch { url (required), label }; upload { text (required), label }); `schedule[]` (see its own description); `episodePages`; `episodesAtOnce` (1–3, default 2: how many episodes of a run are made at once; they still publish in order); `profanity` (none|mild|open); `punchUp` (sharper jokes, with a clean first line); `hardLines[]` (words never said, checked across the whole script); `commenterNames` (handles|pseudonyms: made-up names, the default for a new show); `episodeNotes` (direction for the writer, ≤8,000); the planner fields, each replacing the platform's default: `planningNotes[]` (≤12 × 220), `castNotes` (≤1,000), `writingStyle` (≤500), `objective` (≤400), `outcome` (≤400), `musicStyle` (≤500), `sfxPolicy` (≤500); `themePrompt` (what the theme sounds like, ≤240); `sounds[]` ({ name, prompt, matches[] }, ≤24); `voiceEffects[]` ({ character, effect: "autotune", when: { direction }, sound? }, ≤8); `memory` ({ rotating[], escalating[] }); `episodeCap` and `monthlyCap` (Studio Credits; setting them takes `userConfirmed: true`); `holdForReview` (each episode waits for you to publish or drop it). A text over its cap is refused, never shortened. Example: {"sources":[{"adapter":"rss","label":"arXiv robotics","params":{"feedUrl":"https://rss.arxiv.org/rss/cs.RO"}}],"schedule":[{"every":"week","at":"07:00","weekday":"monday","covers":"roundup","episodes":1}],"episodePages":9,"profanity":"none"}.
  - `sources` union[]
    - union
      - object: An RSS or Atom feed: a blog, a newsletter (Substack: https://<name>.substack.com/feed), an arXiv listing (https://rss.arxiv.org/rss/cs.RO), Product Hunt. Each feed entry is one item.
        - `adapter` 'rss', required
        - `params` object, required
          - `feedUrl` string, uri, required: The feed URL (http or https).
          - `maxItems` integer: The most entries read per run. Default 12.
          - `lookbackDays` integer: How many days back to read. Defaults to the schedule: 1 for a daily one, 7 for a weekly one, 31 for a monthly one.
          - `readArticles` boolean: true reads each entry's linked page whole (the same reader a Hacker News thread's article goes through); an entry whose page is paywalled or unreadable is passed over. Off (the default), an entry is the feed's own text, shortened past 8,000 characters.
          - `order` string: "newest" (the default) reads what the feed published in the window. "oldest" works through the feed's archive instead: the oldest entries no episode has covered yet, whatever their date, so a feed that carries its whole history (a newsletter, a podcast, a blog) becomes a backlog the show reads in order.
        - `label` string
      - object: A topic searched on the web at each run: the newest articles about it, each one item, never one an earlier episode covered. Searches run on Sleeper's own search service (no key needed), up to 40 a day per account.
        - `adapter` 'web-search', required
        - `params` object, required
          - `query` string, required: What to search for, as you would type it ("solid-state battery breakthroughs", "Mars sample return").
          - `topic` string: "news" (the default) searches news coverage; "general" searches the whole web.
          - `site` string: Only results from this site, as a host name ("nasa.gov").
          - `maxItems` integer: The most articles taken per run. Default 5.
          - `lookbackDays` integer: How many days back to read. Defaults to the schedule: 1 for a daily one, 7 for a weekly one, 31 for a monthly one.
        - `label` string
      - object: Hacker News front-page discussions, from the top 100: each story with enough comments is one item, carrying its whole comment thread (every comment, with who replied to whom) and its linked article read whole.
        - `adapter` 'hackernews', required
        - `params` object
          - `count` integer: The most stories taken per run. Default 5.
          - `minComments` integer: A story needs at least this many comments, by Hacker News' own count. Default 10.
          - `itemId` string: One specific story id instead of the front page.
          - `skipObituaries` boolean: true passes over a thread about a real person's death (from its title, the post and the article's opening); the next thread takes its place. Off by default.
        - `label` string
      - object: A public GitHub repository: its releases, merged pull requests and commit flow over the window, as one item.
        - `adapter` 'github', required
        - `params` object, required
          - `repo` string, required: The repository as owner/name.
          - `lookbackDays` integer: How many days back to read. Defaults to the schedule: 1 for a daily one, 7 for a weekly one, 31 for a monthly one.
        - `label` string
      - object: One web page, read whole at each run (a changelog, a status page, a running list).
        - `adapter` 'url-watch', required
        - `params` object, required
          - `url` string, uri, required: The page URL (http or https).
          - `label` string: What to call the page in the episode material.
        - `label` string
      - object: Text the writer supplies once (notes, an archive excerpt). The same text every run, so pair it with another source.
        - `adapter` 'upload', required
        - `params` object, required
          - `text` string, required: The text itself, up to 12,000 characters.
          - `label` string: What to call the text in the episode material.
        - `label` string
  - `schedule` ShowScheduleEntryInput[]: When the show runs, in the series' timezone: `schedule[]` entries `{ id, every: "day"|"week"|"month", at: "HH:MM", weekday (a week's entry: "monday"…), dayOfMonth (a month's entry: 1–28), covers: "item" (one episode per item a source gives, the default) | "roundup" (one episode from everything new; it claims every item it covers, and makes 1 episode), episodes: 1–5 }`. A new entry has no `id` and gets one; an entry with an `id` changes only the fields sent; `{ id, remove: true }` removes it; entries not named stay. Example: [{"every":"day","at":"19:00","covers":"item","episodes":5}].
    - `id` string
    - `remove` true
    - `every` 'day' | 'week' | 'month'
    - `at` string: Local time in the series' timezone, "HH:MM".
    - `weekday` 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday': A weekly entry's day.
    - `dayOfMonth` integer: A monthly entry's day.
    - `covers` 'item' | 'roundup': `item`: one episode per item a source gives. `roundup`: one episode from everything new; it claims every item it covers, and makes 1 episode.
    - `episodes` integer: Episodes each run sets out to publish (a roundup: 1).
  - `episodePages` integer, nullable: The episode length in script pages: one page is about a minute of audio (a cast of hosts runs about 1.3 minutes a page, so ~9 pages is a ~12-minute episode). 4–20. Unset, the length follows the amount of material (5–10 pages).
  - `episodesAtOnce` integer: How many episodes of one run are made at once, 1–3 (default 2). They still publish one after another, in the order the run started them. A show's first episode is always made alone.
  - `profanity` 'none' | 'mild' | 'open'
  - `punchUp` boolean: Sharper jokes, with a clean first line.
  - `hardLines` string[]: Words the show never says, checked across the whole script.
  - `commenterNames` 'handles' | 'pseudonyms': How the people in a thread are named: `handles`, or `pseudonyms` (made-up names, stable per show).
  - `episodeNotes` string, nullable: Direction for the writer, first in the job notes.
  - `planningNotes` string[], nullable: What the planner must know: replaces the platform's default list.
  - `castNotes` string, nullable: Replaces the platform's cast notes for the planner.
  - `writingStyle` string, nullable: Replaces the platform's writing style line.
  - `objective` string, nullable: What an episode is for: replaces the platform's default.
  - `outcome` string, nullable: What the listener comes away with: replaces the platform's default.
  - `musicStyle` string, nullable: Music direction: replaces the platform's theme line.
  - `sfxPolicy` string, nullable: Sound direction: replaces the platform's sound line.
  - `themePrompt` string, nullable: What the theme sounds like: the same intro and outro every episode.
  - `sounds` object[]
    - `name` string, required
    - `prompt` string, required: The sound's prompt: its key in the sound bank.
    - `matches` string[], required
  - `voiceEffects` object[]
    - `character` string, required
    - `effect` 'autotune', required
    - `when` object, required
      - `direction` string, required
    - `sound` string: One of the show's sounds, placed where the effect starts.
  - `memory` object, nullable: What the show rotates so episodes stay fresh: `rotating` values it varies (and `retired` ones it never reuses), and `escalating` threads that build, each found by its `matches`.
    - `enabled` boolean
    - `depth` integer
    - `rotating` object[]
      - `key` string, required
      - `label` string, required
      - `values` string[], required
      - `retired` string[]
    - `escalating` object[]
      - `key` string, required
      - `label` string, required
      - `matches` string[], required
  - `episodeCap` integer, nullable: The most one episode may spend, in Studio Credits. Setting it takes `userConfirmed: true`.
  - `monthlyCap` integer, nullable: The most a calendar month's episodes may spend, in the series' timezone. Setting it takes `userConfirmed: true`.
  - `holdForReview` boolean: Each episode waits for the creator to publish or drop it.
  - `userConfirmed` boolean: Required when the call sets a cap, after the user agrees to it.

## Response `200`

The show as it now reads.

- ShowRead: The show: its state (not_set_up, off, on, paused, or external when an outside app makes it), who makes it (`producer`), its setup with read-only summary lines, whether it can make an episode now (`readiness`), one episode's price and the caps suggested from it, when it runs next, its last run, its newest preview, whether shows are running across Sleeper (`showsRunning`), and its one next step (`nextStep`). Free.
  - `seriesId` string, required
  - `state` 'not_set_up' | 'off' | 'on' | 'paused' | 'external', required
  - `pausedReason` string, nullable, required
  - `showsRunning` boolean, required: False: shows aren't running across Sleeper (the operator's switch); a show made by Sleeper runs again when they do.
  - `producer` ShowProducer, required: Who makes a show's episodes, read from the feed and the ledger, key first: `external` when an API key holds its standing approval (an outside app makes and publishes it; Sleeper makes previews only), else `hosted` (Sleeper).
    - `kind` 'hosted' | 'external', required
    - `key` object, nullable, required
      - `id` string, required
      - `name` string, nullable, required
      - `start` string, nullable, required
      - `state` 'live' | 'expired' | 'disabled' | 'missing', required
    - `grantedAt` string, date-time, nullable, required
    - `website` string, nullable, required
    - `showOn` boolean, required
    - `paused` boolean, required
    - `lastEpisode` object, nullable, required
      - `releaseId` string, required
      - `label` string, required
      - `publishedAt` string, date-time, required
    - `publishedThisMonth` integer, required
    - `publishedInWindow` integer, required
    - `creditsThisMonth` integer, required
    - `monthFrom` string, date-time, required
    - `timezone` string, required
    - `observedCadence` string, nullable, required
    - `lines` string[], required
    - `summary` string, required
  - `setup` ShowSetup, required: The show's setup, every field with its default when unset.
    - `sources` union[], required
      - union
        - object: An RSS or Atom feed: a blog, a newsletter (Substack: https://<name>.substack.com/feed), an arXiv listing (https://rss.arxiv.org/rss/cs.RO), Product Hunt. Each feed entry is one item.
          - `adapter` 'rss', required
          - `params` object, required
            - `feedUrl` string, uri, required: The feed URL (http or https).
            - `maxItems` integer: The most entries read per run. Default 12.
            - `lookbackDays` integer: How many days back to read. Defaults to the schedule: 1 for a daily one, 7 for a weekly one, 31 for a monthly one.
            - `readArticles` boolean: true reads each entry's linked page whole (the same reader a Hacker News thread's article goes through); an entry whose page is paywalled or unreadable is passed over. Off (the default), an entry is the feed's own text, shortened past 8,000 characters.
            - `order` string: "newest" (the default) reads what the feed published in the window. "oldest" works through the feed's archive instead: the oldest entries no episode has covered yet, whatever their date, so a feed that carries its whole history (a newsletter, a podcast, a blog) becomes a backlog the show reads in order.
          - `label` string
        - object: A topic searched on the web at each run: the newest articles about it, each one item, never one an earlier episode covered. Searches run on Sleeper's own search service (no key needed), up to 40 a day per account.
          - `adapter` 'web-search', required
          - `params` object, required
            - `query` string, required: What to search for, as you would type it ("solid-state battery breakthroughs", "Mars sample return").
            - `topic` string: "news" (the default) searches news coverage; "general" searches the whole web.
            - `site` string: Only results from this site, as a host name ("nasa.gov").
            - `maxItems` integer: The most articles taken per run. Default 5.
            - `lookbackDays` integer: How many days back to read. Defaults to the schedule: 1 for a daily one, 7 for a weekly one, 31 for a monthly one.
          - `label` string
        - object: Hacker News front-page discussions, from the top 100: each story with enough comments is one item, carrying its whole comment thread (every comment, with who replied to whom) and its linked article read whole.
          - `adapter` 'hackernews', required
          - `params` object
            - `count` integer: The most stories taken per run. Default 5.
            - `minComments` integer: A story needs at least this many comments, by Hacker News' own count. Default 10.
            - `itemId` string: One specific story id instead of the front page.
            - `skipObituaries` boolean: true passes over a thread about a real person's death (from its title, the post and the article's opening); the next thread takes its place. Off by default.
          - `label` string
        - object: A public GitHub repository: its releases, merged pull requests and commit flow over the window, as one item.
          - `adapter` 'github', required
          - `params` object, required
            - `repo` string, required: The repository as owner/name.
            - `lookbackDays` integer: How many days back to read. Defaults to the schedule: 1 for a daily one, 7 for a weekly one, 31 for a monthly one.
          - `label` string
        - object: One web page, read whole at each run (a changelog, a status page, a running list).
          - `adapter` 'url-watch', required
          - `params` object, required
            - `url` string, uri, required: The page URL (http or https).
            - `label` string: What to call the page in the episode material.
          - `label` string
        - object: Text the writer supplies once (notes, an archive excerpt). The same text every run, so pair it with another source.
          - `adapter` 'upload', required
          - `params` object, required
            - `text` string, required: The text itself, up to 12,000 characters.
            - `label` string: What to call the text in the episode material.
          - `label` string
    - `schedule` ShowScheduleEntry[], required: When the show runs, in the series' timezone: `schedule[]` entries `{ id, every: "day"|"week"|"month", at: "HH:MM", weekday (a week's entry: "monday"…), dayOfMonth (a month's entry: 1–28), covers: "item" (one episode per item a source gives, the default) | "roundup" (one episode from everything new; it claims every item it covers, and makes 1 episode), episodes: 1–5 }`. A new entry has no `id` and gets one; an entry with an `id` changes only the fields sent; `{ id, remove: true }` removes it; entries not named stay. Example: [{"every":"day","at":"19:00","covers":"item","episodes":5}].
      - `id` string, required: Stable: made when the entry is added, kept on every edit.
      - `every` 'day' | 'week' | 'month', required
      - `at` string, required: Local time in the series' timezone, "HH:MM".
      - `weekday` 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday': A weekly entry's day.
      - `dayOfMonth` integer: A monthly entry's day.
      - `covers` 'item' | 'roundup', required: `item`: one episode per item a source gives. `roundup`: one episode from everything new; it claims every item it covers, and makes 1 episode.
      - `episodes` integer, required: Episodes each run sets out to publish (a roundup: 1).
    - `episodePages` integer, nullable, required: The episode length in script pages: one page is about a minute of audio (a cast of hosts runs about 1.3 minutes a page, so ~9 pages is a ~12-minute episode). 4–20. Unset, the length follows the amount of material (5–10 pages).
    - `episodesAtOnce` integer, required: How many episodes of one run are made at once, 1–3 (default 2). They still publish one after another, in the order the run started them. A show's first episode is always made alone.
    - `profanity` 'none' | 'mild' | 'open', required
    - `punchUp` boolean, required: Sharper jokes, with a clean first line.
    - `hardLines` string[], required: Words the show never says, checked across the whole script.
    - `commenterNames` 'handles' | 'pseudonyms', required: How the people in a thread are named: `handles`, or `pseudonyms` (made-up names, stable per show).
    - `episodeNotes` string, nullable, required: Direction for the writer, first in the job notes.
    - `planningNotes` string[], nullable, required: What the planner must know: replaces the platform's default list.
    - `castNotes` string, nullable, required: Replaces the platform's cast notes for the planner.
    - `writingStyle` string, nullable, required: Replaces the platform's writing style line.
    - `objective` string, nullable, required: What an episode is for: replaces the platform's default.
    - `outcome` string, nullable, required: What the listener comes away with: replaces the platform's default.
    - `musicStyle` string, nullable, required: Music direction: replaces the platform's theme line.
    - `sfxPolicy` string, nullable, required: Sound direction: replaces the platform's sound line.
    - `themePrompt` string, nullable, required: What the theme sounds like: the same intro and outro every episode.
    - `sounds` object[], required
      - `name` string, required
      - `prompt` string, required: The sound's prompt: its key in the sound bank.
      - `matches` string[], required
    - `voiceEffects` object[], required
      - `character` string, required
      - `effect` 'autotune', required
      - `when` object, required
        - `direction` string, required
      - `sound` string: One of the show's sounds, placed where the effect starts.
    - `memory` object, nullable, required: What the show rotates so episodes stay fresh: `rotating` values it varies (and `retired` ones it never reuses), and `escalating` threads that build, each found by its `matches`.
      - `enabled` boolean
      - `depth` integer
      - `rotating` object[]
        - `key` string, required
        - `label` string, required
        - `values` string[], required
        - `retired` string[]
      - `escalating` object[]
        - `key` string, required
        - `label` string, required
        - `matches` string[], required
    - `episodeCap` integer, nullable, required: The most one episode may spend, in Studio Credits.
    - `monthlyCap` integer, nullable, required: The most a calendar month's episodes may spend, in the series' timezone.
    - `holdForReview` boolean, required: Each episode waits for the creator to publish or drop it.
  - `summary` object, required: The setup as short read-only lines.
    - `status` string, required
    - `sources` string, nullable, required
    - `schedule` string, nullable, required
    - `length` string, nullable, required
    - `swearing` string, nullable, required
    - `commenters` string, nullable, required
    - `theme` string, nullable, required
    - `caps` string, nullable, required
    - `review` string, nullable, required
    - `pace` string, nullable, required
    - `voice` string, nullable, required
  - `readiness` object, required
    - `ready` boolean, required
    - `blocker` object, nullable, required
      - `code` string, required
      - `message` string, required
  - `quote` object, required
    - `episodeCredits` integer, required
    - `balanceAfter` integer, required
    - `sufficient` boolean, required
  - `suggestedCaps` object, required
    - `episodeCap` integer, required: One episode's price (with its hard-line refine, when it has hard lines) + 25%.
    - `monthlyCap` integer, required: The schedule's episodes in its busiest month × the episode cap.
    - `episodesPerMonth` integer, required
  - `monthToDate` object, required
    - `spent` integer, required
    - `from` string, date-time, required
  - `nextRunAt` string, date-time, nullable, required
  - `lastRun` object, nullable, required
    - `runId` string, required
    - `at` string, date-time, required
    - `target` integer, required
    - `made` integer, required
    - `state` 'open' | 'waiting' | 'done' | 'superseded', required
  - `preview` object, nullable, required
    - `episodeId` string, required
    - `outcome` 'queued' | 'making' | 'published' | 'held' | 'preview' | 'dropped' | 'skipped' | 'failed', required
    - `audioUrl` string, nullable, required
  - `nextStep` object, required
    - `kind` 'set_up' | 'get_ready' | 'set_caps' | 'make_preview' | 'turn_on' | 'review_held' | 'resume' | 'none', required
    - `sentence` string, required
  - `site` ShowSite, required: Where the show lives on the web (docs/show-sites.md): sleeper.show/{slug}, or its own domain once live.
    - `url` string, nullable, required: The show's public site; null while the show has no public page.
    - `sleeperUrl` string, required: Its address on sleeper.show.
    - `domain` object, nullable, required
      - `host` string, required
      - `state` 'needs_records' | 'securing' | 'live', required
      - `records` object[], required: The DNS records to add at the domain's DNS provider, exactly as written.
        - `type` 'CNAME' | 'TXT', required
        - `name` string, required
        - `value` string, required
      - `status` string, required: Where it stands and the one next step.
      - `checkedAt` string, date-time, nullable, required
    - `latestEpisodeUrl` string, nullable, required: The newest published episode's page: `{site}/{season}/{episode}` (`https://hnradio.net/4/429`), or its release id when the show is unlisted or another episode shares its numbers.
    - `redirects` integer, required: Old paths on its own domain that move to an episode.

## Other responses

- `400`: Request payload failed validation. The error message names the offending field.
- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `404`: The publishing series, destination, or release does not exist or is owned by another account.
- `409`: `project_not_story`: the series belongs to a product project, and a show is made from a story project. Nothing changed.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/86e084144cef?raw)
