Upload from external providers

This guide shows how you can upload a video from an external platform. Currently, only YouTube is supported as an external provider, but we will add support for additional providers in the future.

For a description of each field in the request and response, see the API Reference > Upload from external providers page.


  • You’re familiar with the concepts that are described on the Platform overview page.
  • You’ve created an index, and the unique identifier of your index is stored in a variable named INDEX_ID. For details, see the Create indexes page.
  • The video that you want to upload must be embeddable.
  • The URL of the video that you want to upload is stored in a variable named VIDEO_URL.
  • Your video must meet the following requirements:
    • Video resolution: Must be greater or equal than 360p and less or equal than 4K.
    • Duration: For Marengo, it must be between 4 seconds and 2 hours (7,200s). For Pegasus, it must be between 30 seconds and 30 minutes (1800s).
    • File size: Must not exceed 2 GB.
      If you require different options, email us at [email protected].
    • Audio track: If the conversation indexing option is selected, the video you're uploading must contain an audio track.



For consistent search results, Twelve Labs recommends you upload 360p videos.


  1. Declare the /tasks/external-provider endpoint:

    TASKS_URL = f"{API_URL}/tasks/external-provider"
    const TASKS_URL = `${API_URL}/tasks/external-provider`
  2. Declare a dictionary named data and use it to store the unique identifier of the index to which you want to upload the video and the URL of the video:

    data = {
      "index_id": INDEX_ID,
      "url": "<YOUTUBE_URL>",
    const data = {
      index_id: INDEX_ID,
      url: '<YOUTUBE_URL'
  3. To upload the video, call the POST method of the /tasks/external-provider endpoint and store the result in a variable named response:

    response = requests.post(TASKS_URL, headers=headers, json=data)
    const config = {
      method: 'post',
      url: TASKS_URL,
      headers: headers,
      data : data
    const resp = await axios(config)
    const response = await resp.data
  4. Store the unique identifier of your video indexing task in a variable named TASK_ID and print the status code and response:

    TASK_ID = response.json().get("_id")
    print (f"Status code: {response.status_code}")
    pprint (response.json())
    const TASK_ID = response._id
    console.log(`Status code: ${resp.status}`)

    The output should look similar to the following one:

      "_id": "6515616f9dc9a5f98820d463"
  5. (Optional) You can use the GET method of the /tasks/{_id} endpoint to monitor the indexing process. Construct the URL for retrieving the status of your video indexing task based on the TASK_ID variable you’ve declared in the previous step, and wait until the status shows as ready:

    TASK_STATUS_URL = f"{API_URL}/tasks/{TASK_ID}"
    while True:
        response = requests.get(TASK_STATUS_URL, headers={"x-api-key": API_KEY})
        STATUS = response.json().get("status")
        if STATUS == "ready":
    const TASK_STATUS_URL = `${API_URL}/tasks/${TASK_ID}`
    const uploadResp = await new Promise((res) => {
      const interval = setInterval(async () => {
          const { data: response } = await axios.get(
                    headers: {
                        'x-api-key': API_KEY
            if (response.status == 'ready') {
        }, 1000)



    • For details about the possible statuses, see the Tasks page.
    • You can also use webhooks to monitor the status of the indexing process. For details, see the Webhooks section.
  6. (Optional) Store the unique identifier of your video in a variable named VIDEO_ID:

    VIDEO_ID = response.json().get('video_id')
    const VIDEO_ID = uploadResp.video_id
  7. (Optional) Print the unique identifier of your video, the status code, and the response:

    print (f"Status code: {STATUS}")
    print(f"VIDEO ID: {VIDEO_ID}")
    pprint (response.json())
    console.log(`Status code: ${uploadResp.status}`)
    console.log(`VIDEO_ID: ${VIDEO_ID}`)

    The output should look similar to the following one:

    Status code: ready
    VIDEO ID: 6526308e53fa6fed0e2fbe53
    {'_id': '65263085bcfa300d56b6bce2',
     'created_at': '2023-10-11T05:20:05.975Z',
     'estimated_time': '2023-10-11T05:25:47.66Z',
     'hls': {'status': 'COMPLETE',
             'thumbnail_urls':    ['https://d2cp8xx7n5vxnu.cloudfront.net/6298aa0b535db125bf6e1d10/65263085bcfa300d56b6bce2/thumbnails/e89f258e-bab5-4142-855d-321233efe2b8.0000001.jpg'],
             'updated_at': '2023-10-11T05:24:11.844Z',
             'video_url': 'https://d2cp8xx7n5vxnu.cloudfront.net/6298aa0b535db125bf6e1d10/65263085bcfa300d56b6bce2/stream/e89f258e-bab5-4142-855d-321233efe2b8.m3u8'},
     'index_id': '65262d5dbcfa300d56b6bcdf',
     'metadata': {'duration': 1073,
                  'filename': 'How to Achieve Your Most Ambitious Goals | Stephen '
                           'Duneier | TEDxTucson',
                  'height': 720,
                  'width': 1280},
     'status': 'ready',
     'type': 'index_task_info',
     'updated_at': '2023-10-11T05:29:24.154Z',
     'video_id': '6526308e53fa6fed0e2fbe53'}