---
title: "Set a custom thumbnail"
method: PUT
path: "/media/{mediaId}/thumbnail"
tags: ["Media (Audio/Video)"]
---

# Set a custom thumbnail

`PUT /media/{mediaId}/thumbnail`

## Request

- Base URL: `https://api.speakai.co/v1`
- URL: `https://api.speakai.co/v1/media/{mediaId}/thumbnail`
- Auth: API key in header `x-speakai-key` and API key in header `x-access-token`

Replace a video's thumbnail with your own image or with a frame from the video. Send exactly one of:

- an image file as multipart form data in the `image` field, for example `-F 'image=@cover.png'`
- JSON `{ "url": "https://..." }`, a public https link to an image, which the server downloads
- JSON `{ "seekSec": 12.5 }`, to use the video frame at that many seconds from the start

The image must be JPEG, PNG or WebP and at most 10 MB. The server checks the file's content, not its name or declared type, so a GIF is refused. A `url` must be https and point to a public address, every redirect included. The server follows up to 3 redirects and gives up after 8 seconds.

A frame request answers `202` straight away and the frame is saved in the background. A `seekSec` past the end of the video uses the frame one second before the end. To follow it, poll `GET /media/status/{mediaId}` and read `data.thumbnail`: `pending` is true while the frame is being made, `error` says why it failed, and once it is saved `url` points to the new frame and `source` is `custom`. While a frame request for the video is still running, another one returns `409`. A request that has not finished after 5 minutes no longer blocks a new one.

Each change replaces the current thumbnail and deletes the previous custom image. There is no way back to the automatic thumbnail. Only a video can have a thumbnail, and a frame cannot be taken from an archived video. You need permission to edit media.

#### Errors

- `400` when the request does not carry exactly one of `image`, `url` and `seekSec`: "Send exactly one of an image file, an https url or seekSec."
- `400` when `url` is not https or `seekSec` is below 0, with the validation message.
- `400` when the media is not a video: "Only a video can have a thumbnail."
- `400` when the image is not a JPEG, PNG or WebP file: "Use one JPEG, PNG or WebP image of up to 10 MB."
- `400` when the link is blocked or cannot be downloaded: "That image url could not be downloaded."
- `400` when a frame is asked of an archived video, or of one whose file Speak does not hold: "A frame cannot be taken from this video."
- `400` when the frame service refuses the request: "That frame could not be taken."
- `403` when you do not have permission to edit media.
- `404` when the media does not exist.
- `409` when a frame is already being taken for this video.
- `413` when the image is larger than 10 MB: "Use one JPEG, PNG or WebP image of up to 10 MB."
- `503` when the frame service is busy: "Thumbnails are busy right now. Try again in a minute."

## Path parameters

- `mediaId` string, required

## Request body

- object
  - `url` string, uri: A public https link to a JPEG, PNG or WebP image of up to 10 MB. The server downloads it. Send this or `seekSec`, not both.
  - `seekSec` number: Use the video frame at this many seconds from the start. A value past the end uses the frame one second before the end. Send this or `url`, not both.

## Response `200`

The image is saved as the thumbnail

- object
  - `status` 'success': `success` on every 2xx response.
  - `data` object
    - `thumbnail` object
      - `url` string: A signed link to the new thumbnail. It expires, so do not store it.
      - `source` 'custom': `custom` for a thumbnail you set.

## Other responses

- `202`: The frame request is accepted and runs in the background
- `400`: Not exactly one of image, url and seekSec, an unsupported image, a link that cannot be downloaded, or a frame that cannot be taken
- `403`: You do not have permission to edit media
- `404`: The media does not exist
- `409`: A frame is already being taken for this video
- `413`: The image is larger than 10 MB
- `503`: The frame service is busy

---

[API](https://skmtc.dev/speakai/apis/speak-ai-api.md) · [All operations](https://skmtc.dev/speakai/apis/speak-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/speakai/apis/speak-ai-api/revisions/52d777e6d46e?raw)
