Skip to main content

Add a video hosted elsewhere

Add a video published on YouTube, Vimeo or Dailymotion to your library with POST /v1/assets: the address of its page is enough, the provider gives its title, its description and its poster, and the asset is ready at once.

A video already published on YouTube, Vimeo or Dailymotion does not need to be downloaded to enter your library: POST /v1/assets creates an asset that plays it from its provider’s site. The address of its page is all it takes. The asset is ready at once — there is no file to receive or process — and you can then edit it and publish it on a channel like any other.

A file is added with POST /v1/uploads instead: sent by you or fetched from a link.

Before you start

  • A key carrying two permissions: Add files to the library through the API (assets.library.upload) and Import videos from other platforms (assets.third_party_video.import). Either without the other is a 403. Tick Read the library through the API as well, to retry safely.
  • Videos hosted elsewhere turned on for your organization. It is turned on organization by organization, on request to Videas: until it is, POST /v1/assets answers 404. A key created beforehand works with no change once it is.
  • A workspace: the id of one of those GET /v1/workspaces returns, private ones included. The asset lands at its root.

Create the asset

curl -X POST https://api.videas.com/v1/assets \
  -H "Authorization: Bearer $VIDEAS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "0192a6b1-7c3e-7d40-9a51-3f0e2b6c8d10",
    "third_party_url": "https://www.youtube.com/watch?v=Xk3Ua9yQe7M",
    "language": "en",
    "external_ref": "webtv/2026/carbon-fibre-recycling"
  }'
Field
workspace_id Required. Where the asset lands.
third_party_url Required. The video’s address, as its page or its share button gives it.
name Optional. Its title — the provider’s when absent. Never blank, and at most 500 characters.
description Optional. Its description — the provider’s when absent, if it gives one. At most 50,000 characters.
excerpt Optional. A short summary, shown under the title where the description would not fit. At most 1,000 characters.
copyright Optional. The notice a reuser has to carry — who holds the rights, under what terms. At most 1,000 characters.
language Optional. The video’s language, as a BCP 47 tag (fr, en-GB).
external_ref Optional, and recommended: your own identifier for the asset, kept without the spaces around it and at most 500 characters. It is what makes a retry safe.

POST /v1/assets takes no query parameter, and its body no other field.

The answer is a 201, with Location: /v1/assets/{asset_id} and the asset as GET /v1/assets/{asset_id} reads it:

{
  "id": "0192a6e4-3b5c-7d6e-8f90-a1b2c3d4e5f6",
  "name": "Recycling carbon fibre: three processes compared",
  "type": "third_party",
  "status": "ready",
  "workspace_id": "0192a6b1-7c3e-7d40-9a51-3f0e2b6c8d10",
  "description": "Pyrolysis, solvolysis and mechanical grinding, put side by side on the same production offcuts.",
  "external_ref": "webtv/2026/carbon-fibre-recycling",
  "language": "en",
  "duration_ms": null,
  "created_at": "2026-10-15T08:30:12Z",
  "updated_at": "2026-10-15T08:30:12Z",
  "third_party": {
    "provider": "youtube",
    "video_id": "Xk3Ua9yQe7M",
    "player_url": "https://www.youtube.com/embed/Xk3Ua9yQe7M"
  },
  "thumbnail_url": "https://app.videas.com/images/assets/0192a6e4-3b5c-7d6e-8f90-a1b2c3d4e5f6/thumbnail.jpg",
  "excerpt": null,
  "copyright": null,
  "seo_title": null,
  "seo_description": null,
  "tags": [],
  "custom_fields": []
}
  • type is third_party, and status is ready from the moment it exists.
  • third_party says which video the asset plays: provider (youtube, vimeo or dailymotion), video_id, the video’s identifier at its provider — the v of a YouTube address —, and player_url, the address of its player, to put in an <iframe>.
  • thumbnail_url is the poster the provider gave, if it arrived in time (see below).

The addresses accepted

third_party_url is the address of a video on one of the three sites, in the form its page or its share button gives:

Provider For example
YouTube https://www.youtube.com/watch?v=…, https://youtu.be/…
Vimeo https://vimeo.com/…
Dailymotion https://www.dailymotion.com/video/…

Nothing else is taken, and everything else answers a 400 that gives the reason: an embed code (<iframe …>), an address on another site, or a link to a file — which is added with POST /v1/uploads.

The provider is asked while your request waits

Before anything is created, Videas asks the provider what the video is, and your request waits for its answer. It is used for three things:

  • naming and describing the asset — its title becomes the asset’s name unless you send one, its description the description unless you send one;
  • checking that the video may be played outside its site: a private, deleted or non-embeddable video is refused with a 400, and nothing is created;
  • giving the asset its poster: it becomes its thumbnail if it arrives in time. Otherwise the asset is created without one, and PUT /v1/assets/{asset_id}/thumbnail gives it one.

A provider that does not answer in time, or answers with a failure of its own, is a 502 with the code upstream_error: nothing is created, send the request again in a moment.

{
  "code": "upstream_error",
  "message": "YouTube could not be asked about this video; try again in a moment",
  "request_id": "0192a6e4-1f2a-7b3c-8d4e-5f6a7b8c9d0e"
}

Finding your videos again

third_party is on every row of GET /v1/assets, not only on the read of one asset. To match a library’s videos with your own records — including those added before you set external_refs —, walk the assets of type third_party and compare third_party.video_id with the video’s identifier on your side:

import os

import requests

API = "https://api.videas.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['VIDEAS_API_KEY']}"}

def videos_by_provider_id():
    """{(provider, video_id): asset} for every video hosted elsewhere."""
    found, params = {}, {"type": "third_party"}
    while True:
        page = requests.get(f"{API}/assets", headers=HEADERS, params=params)
        page.raise_for_status()
        body = page.json()
        for asset in body["data"]:
            video = asset["third_party"]
            if video and video["video_id"]:
                found[(video["provider"], video["video_id"])] = asset
        if body["next"] is None:
            return found
        params["after"] = body["next"]

provider may also be other — a player from another site, added from the Videas app — and then has no video_id. The list of providers may grow: read a value you do not know as other.

Retrying safely

POST /v1/assets is not idempotent: sent twice, it creates two assets. A request that timed out or answered a 5xx may have created one. So:

  1. set external_ref on every request;

  2. after a timeout or a 5xx, look it up before sending the request again — with a key that reads the library:

    curl "https://api.videas.com/v1/assets?external_ref=webtv%2F2026%2Fcarbon-fibre-recycling" \
      -H "Authorization: Bearer $VIDEAS_API_KEY"
  3. nothing found: send it again. Found: it is the asset the first request created, and it is complete — ready from the moment it exists. There is nothing to resume.

A 502 created nothing: it is sent again as it is.

Errors

Every error has the same body — {"code": "…", "message": "…", "request_id": "…"}. Branch on code; message is written for a human and may change.

Status code On POST /v1/assets
400 validation A third_party_url that is not a YouTube, Vimeo or Dailymotion video; a private, deleted or non-embeddable video; a blank name or external_ref; a name or an external_ref longer than 500 characters, an excerpt or a copyright longer than 1,000, or a description longer than 50,000; a malformed language; a query parameter. The message names the field.
401 unauthorized No key, or a key that is unknown, expired or revoked.
403 forbidden The key does not carry both assets.library.upload and assets.third_party_video.import.
404 not_found Videos hosted elsewhere are not turned on for your organization — ask Videas —, or no workspace of your organization has this workspace_id.
415 unsupported_media_type The body is not sent as application/json.
422 validation workspace_id or third_party_url missing, a field of the wrong type, or a field the body does not list.
429 rate_limited Too many requests: wait the number of seconds Retry-After gives.
502 upstream_error The provider did not answer in time, or answered with a failure. Nothing is created: send the request again in a moment.

Next steps