---
title: "Send a render to Publishing, or remove it."
method: POST
path: "/artifacts/{artifactId}/publish-state"
tags: ["Artifacts"]
---

# Send a render to Publishing, or remove it.

`POST /artifacts/{artifactId}/publish-state`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/artifacts/{artifactId}/publish-state`
- Auth: HTTP bearer

Marks the table-read render publishable (`action: "mark"`) so it surfaces in Publishing and becomes eligible for an RSS/podcast feed — ensuring the durable full-mix render exists first, free and replay-guarded — or removes it (`action: "unmark"`). FREE and naturally idempotent: no `Idempotency-Key`. An `unmark` a live/published RSS release backs comes back `{ requiresConfirm: true, inFeed: true }` until sent again with `confirm: true`. An artifact that is not yours, or does not exist, is a 404 `artifact_not_found`; a `mark` whose durable render cannot start refuses before the flag is set. Scope: `artifact:publish`.

## Request body

- ArtifactPublishStateRequest: Set a render's publish state. `mark` sends it to Publishing (ensuring its durable render exists); `unmark` removes it.
  - `action` 'mark' | 'unmark', required: mark | unmark.
  - `confirm` boolean: Only read for `action: "unmark"`. Without it, a render a live/published RSS release backs comes back `{ requiresConfirm: true, inFeed: true }` instead of being removed.

## Response `200`

The render's publish state after the change.

- ArtifactPublishStateResult: The render's publish state after the change. A `mark` also carries `renderRequest` (`complete` when the durable render already existed, `rendering` when it was just queued). An `unmark` a live feed backs carries `requiresConfirm: true` and `inFeed: true` and the remaining state fields may be absent.
  - `artifactId` string, nullable: The Story artifact behind the render.
  - `publishable` boolean: True once the render has been sent to Publishing.
  - `renderStatus` 'complete' | 'rendering' | 'needs_recording' | 'not_finalized' | 'failed'
  - `recordingReady` boolean
  - `inFeed` boolean, required: True when a live/published release in an RSS feed backs this render.
  - `renderRequest` 'complete' | 'rendering': Present on a `mark` that also ensured the durable render: `complete` when it already existed, `rendering` when it was just queued.
  - `requiresConfirm` boolean: Present (true) on an `unmark` a live feed backs, until `confirm: true` is sent.

## Other responses

- `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 story artifact does not exist or is owned by another account.
- `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/64c1102ccb2f?raw)
