---
title: "Set Content Thumbnail From Frame"
method: POST
path: "/v2/contents/{content_id}/thumbnail"
tags: ["v2 - Contents"]
---

# Set Content Thumbnail From Frame

`POST /v2/contents/{content_id}/thumbnail`

## Request

- Base URL: `https://api.jubjubapp.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.jubjubapp.com/v2/contents/{content_id}/thumbnail`
- Auth: HTTP bearer

Set this piece's thumbnail to a frame at the given timestamp.

A NEW media_v2 image is created every time and thumbnail_id is repointed
at it. The previous image is left exactly where it is, still public, still
at its URL. That is not tidiness — one of them is already embedded in a
published Farcaster cast, and cast previews resolve the image at render
time, so overwriting the object would change what a historical post shows.
Orphaned images are the cheaper problem.

NO `if not content.thumbnail_id` GUARD. That guard belongs to
create_content, where a supplied thumbnail must not be overwritten. Here
the piece always has one already — that is what re-picking means — so the
guard would make this endpoint a permanent no-op.

ON FAILURE THIS RETURNS AN ERROR, NOT A SILENT 200. create_content
swallows extraction failures and continues, which is right at ingest: the
upload should not fail because ffmpeg timed out. Here the thumbnail IS the
request, so a 200 with the old image still attached would be
indistinguishable from success — the same invisible failure that let a
Farcaster cast publish under a camera filename with nothing to explain it.

Access: CONTENT_EDIT on the parent workspace.

## Path parameters

- `content_id` string, required

## Headers

- `Authorization` string
- `X-JubJub-Service-Key` string
- `X-JubJub-Agent-Key` string
- `X-JubJub-Platform-Key` string
- `Origin` string
- `Referer` string
- `X-JubJub-Trial-Token` string

## Request body

- SetThumbnailFromFrameRequest: Pick a frame from the content's video as its thumbnail.
  - `timestamp_seconds` number, required: Seconds into the video to extract. Passed to extract_thumbnail as seek_to, which takes precedence over its 25%-of-duration default.

## Response `201`

Successful Response

- SetThumbnailFromFrameResponse: The newly created thumbnail. The previous one is left in place.
  - `content_id` string, required
  - `thumbnail_id` string, required
  - `thumbnail_url` string, nullable: Public URL of the new thumbnail. None when STORAGE_BUCKET is unset (local dev); the id is authoritative either way.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/jubjubapp/apis/jubjub-api.md) - [All operations](https://skmtc.dev/jubjubapp/apis/jubjub-api/llms.txt) - [OpenAPI document](https://skmtc.dev/jubjubapp/apis/jubjub-api/revisions/353157b296f2?raw)
