Skip to main content

An asset's thumbnail

Choose an asset's thumbnail by sending it with PUT /v1/assets/{asset_id}/thumbnail, then show it in your pages with thumbnail_url: a stable, anonymous address to put as it is in an <img>, in several formats and sizes.

An asset’s thumbnail is the picture it is shown with — in Videas, on its channels, and in your own pages. The API writes it and serves it:

  • PUT /v1/assets/{asset_id}/thumbnail chooses the thumbnail, by sending it;
  • thumbnail_url, on every asset GET /v1/assets and GET /v1/assets/{asset_id} answer, is the address to show it from.

Send a thumbnail

The request’s body is the picture itself, not JSON: a JPEG, a PNG or a WebP of at most 10 MiB, with a Content-Type naming which. The key needs Edit the library through the API (assets.library.edit).

curl -X PUT https://api.videas.com/v1/assets/0192a6e4-3b5c-7d6e-8f90-a1b2c3d4e5f6/thumbnail \
  -H "Authorization: Bearer $VIDEAS_API_KEY" \
  -H "Content-Type: image/jpeg" \
  --data-binary @thumbnail.jpg

The same in Node.js (18 or later) and in Python:

import { readFile } from 'node:fs/promises'

const response = await fetch(
  'https://api.videas.com/v1/assets/0192a6e4-3b5c-7d6e-8f90-a1b2c3d4e5f6/thumbnail',
  {
    method: 'PUT',
    headers: {
      Authorization: `Bearer ${process.env.VIDEAS_API_KEY}`,
      'Content-Type': 'image/webp',
    },
    body: await readFile('thumbnail.webp'),
  },
)
const asset = await response.json()
if (!response.ok) throw new Error(`${asset.code}: ${asset.message}`)
import os

import requests

with open("thumbnail.png", "rb") as picture:
    response = requests.put(
        "https://api.videas.com/v1/assets/0192a6e4-3b5c-7d6e-8f90-a1b2c3d4e5f6/thumbnail",
        headers={
            "Authorization": f"Bearer {os.environ['VIDEAS_API_KEY']}",
            "Content-Type": "image/png",
        },
        data=picture,
    )
response.raise_for_status()

The picture becomes the one the asset is shown with, in Videas and on its channels, and the one its thumbnail_url serves from then on. The answer is a 200 carrying the whole asset, as GET /v1/assets/{asset_id} reads it.

  • Sending the picture the asset already has changes nothing — not even its updated_at.
  • A different picture moves updated_at, as its words do.
  • The last request to arrive wins, and a PUT sent again as it is after a timeout or a 5xx does nothing more.
  • An asset validated in the organization’s shared pool is refused with a 403, as for its words.

A video added from YouTube, Vimeo or Dailymotion takes its provider’s poster when it arrives in time; this request replaces it, or gives one to an asset that has none.

Show the thumbnail: thumbnail_url

{
  "id": "0192a6e4-3b5c-7d6e-8f90-a1b2c3d4e5f6",
  "thumbnail_url": "https://app.videas.com/images/assets/0192a6e4-3b5c-7d6e-8f90-a1b2c3d4e5f6/thumbnail.jpg"
}

thumbnail_url is the address of the asset’s thumbnail — the one the organization chose, else the one Videas picked —, and is null while it has none.

  • It is stable and anonymous. It needs no key: put it as it is in a web page’s <img>.
  • It follows the asset, not a picture: when another thumbnail is chosen, the same address serves the new one. Store the address, not the bytes.
  • It is on the domain your organization’s Videas app is served on, not on the API’s.
  • It serves a JPEG at the picture’s own size, at most 3,840 pixels a side.
  • Its answers may be cached for a few minutes and carry an ETag: a thumbnail that just changed may take those few minutes to show.
<img
  src="https://app.videas.com/images/assets/0192a6e4-3b5c-7d6e-8f90-a1b2c3d4e5f6/thumbnail.jpg"
  alt="Recycling carbon fibre: three processes compared"
  loading="lazy"
/>

Other formats, other sizes

The same address serves other formats and other sizes with its last segment changed:

Last segment What it serves
thumbnail.jpg the picture at its own size, as a JPEG — the address as the API gives it
thumbnail.webp, thumbnail.png the picture at its own size, as a WebP or a PNG
{fit}-{width}x{height}.{ext} the picture fitted to a box

In the last form:

  • fit is cover — the picture fills the box and is cropped to it — or contain — it fits inside the box, and is never cropped;
  • ext is jpg, webp or png;
  • for example cover-320x180.jpg or contain-1280x720.webp.

The boxes served are a fixed list. A box that is not in it is redirected (308) to the smallest box served that covers it; a browser follows the redirect on its own. A picture is never enlarged.

A srcset is therefore built from thumbnail_url:

function pictureSources(thumbnailUrl) {
  const base = thumbnailUrl.slice(0, thumbnailUrl.lastIndexOf('/') + 1)
  return {
    src: `${base}cover-640x360.jpg`,
    srcset: [320, 640, 1280]
      .map((width) => `${base}cover-${width}x${(width * 9) / 16}.webp ${width}w`)
      .join(', '),
  }
}
<img
  src="https://app.videas.com/images/assets/0192a6e4-…/cover-640x360.jpg"
  srcset="https://app.videas.com/images/assets/0192a6e4-…/cover-320x180.webp 320w,
          https://app.videas.com/images/assets/0192a6e4-…/cover-640x360.webp 640w,
          https://app.videas.com/images/assets/0192a6e4-…/cover-1280x720.webp 1280w"
  sizes="(max-width: 640px) 100vw, 640px"
  width="640" height="360"
  alt="Recycling carbon fibre: three processes compared"
  loading="lazy"
/>

When the address answers 404

thumbnail_url answers 404 once the asset is deleted or hidden, or no longer has a thumbnail. It is not a passing failure: read the asset again with GET /v1/assets/{asset_id} — a 404 there too says it is no longer in the library, and a thumbnail_url of null that it no longer has a picture.

Errors

Every error of PUT …/thumbnail has the same JSON body — {"code": "…", "message": "…", "request_id": "…"} —, even though the request sends a picture.

Status code What happened
400 validation Bytes that are not a JPEG, a PNG or a WebP, or not the one the Content-Type names; an asset_id that is not a uuid; a query parameter.
401 unauthorized No key, or a key that is unknown, expired or revoked.
403 forbidden The key does not carry assets.library.edit; or the asset is validated in the organization’s shared pool.
404 not_found No asset GET /v1/assets lists has this id.
413 payload_too_large The picture is larger than 10 MiB.
415 unsupported_media_type The body is not sent as image/jpeg, image/png or image/webp.
429 rate_limited Too many requests: wait the number of seconds Retry-After gives.

Next steps