api.video

Features

Documentation

Tutorials

Delegated Uploads for Videos Large and Small (Python)

February 12, 2021 - Erikka Innes

api.video offers delegated uploads! For uploading video, this means you can create an authorization token, and choose how long your authorization token lasts, anywhere from a few seconds (this might be a bit extreme) to forever. The value in using a delegated upload token is that you don't expose your api key, authorization token, or refresh token. All you need is the delegated token you create. You can create tokens for users if you want them to be able to do uploads and you can delete tokens at any time if they are compromised, or no longer needed.

How Does a Delegated Video Upload Differ From a Regular Video Upload?

Glad you asked! There are a few differences. If you use the regular upload endpoint, you must:

  • Use the authorization token you retrieve with your API key.
  • Create a video container with any details you want to provide about your video.
  • Upload your video into the video container you created.

If you use the delegated video upload endpoint, you must:

  • Create a delegated token for use with the delegated upload endpoint.
  • Upload your video - api.video creates the container for you. You don't provide more detail than the file title.

You can use the delegated token for as many uploads as you like, or delete the token if you don't need it any longer. You can add details about your video later using the update a video endpoint.

The Authorization Flow for Delegated Uploads

You use your api key to authenticate and get a token. Then, you use your token to request a delegated token. The delegated token may be used for uploads through the delegated upload endpoint only. What's great about it, is if you want you can create and give this token to someone else to make uploads with. You can give the delegated token an expiry time, or let it last forever. Don't worry, you can also delete tokens if one of then is compromised, or if you don't need it any longer.

What's In This Tutorial

We'll go over a code sample for:

  • Uploading a Video Under 128 MB with a Delegated Token
  • Uploading a Video Over 128 MB with a Delegated Token

Delegated Upload for Video Under 128 MB

If you have a video under 128 MB, upload is fairly straightforward. Here's the code sample:

# How to upload a video that is under 128 MB to api.video. 

import requests

# Set up variables for endpoints
auth_url = "https://ws.api.video/auth/api-key"
token_url = "https://ws.api.video/upload-tokens"
delegated_upload_url = "https://ws.api.video/upload"

# Set up headers and payload for first authentication request
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json"
}

payload = {
    "apiKey": "your api key here"
}

# Send the first authentication request to get a token. The token can be used for one hour with the rest of the API endpoints.
response = requests.request("POST", auth_url, json=payload, headers=headers)
response = response.json()
token = response["access_token"]

# Set up headers and payload to generate your delegated upload token and request a token

auth_string = "Bearer " + token

delegate_headers = {
    "Accept": "application/vnd.api.video+json",
    "Content-Type": "application/json",
    "Authorization": auth_string
}

delegate_payload = {
    "ttl": 0
}

response = requests.request("POST", token_url, json=delegate_payload, headers=delegate_headers)

response = response.json()
token = response.get("token")

# Upload your video using the token. This token will not expire unless you 
# specify an expiry time, or you delete it. 

# Upload by URL

d_upload_headers = {
    "Accept": "application/vnd.api.video+json"
}

d_query = {"token": token}

d_payload = {
    "file": open("small_vid.mp4", "rb")
}

response = requests.request("POST", delegated_upload_url, files=d_payload, params=d_query, headers=d_upload_headers)

print(response.json())

Walkthrough - Delegated Upload for a Video Under 128MB

The start of this you're probably familiar with by now if you've tried the other tutorials. You're going to add the requests library, grab your API key (you can use sandbox or production, the difference being that for sandbox all video will be watermarked), and authenticate so you can get a token.

import requests

# Set up variables for endpoints
auth_url = "https://ws.api.video/auth/api-key"
token_url = "https://ws.api.video/upload-tokens"
delegated_upload_url = "https://ws.api.video/upload"

# Set up headers and payload for first authentication request
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json"
}

payload = {
    "apiKey": "your api key here"
}

# Send the first authentication request to get a token. The token can be used for one hour with the rest of the API endpoints.
response = requests.request("POST", auth_url, json=payload, headers=headers)
response = response.json()
token = response["access_token"]

Retrieve a Delegated Token for Video Upload

Use your access token to set up the bearer auth header you'll need to retrieve a delegated token. For the body of your request, you need to add a value for the ttl field. TTL stands for time-to-live. In this walkthrough, we are setting ttl equal to 0, which means the token will last forever. You can set the token to other lengths of time in seconds.

After you've set the payload, send your request, then retrieve the delegated token from the response. Armed with your shiny new token, you're ready to upload your video!

# Set up headers and payload to generate your delegated upload token and request a token

auth_string = "Bearer " + token

delegate_headers = {
    "Accept": "application/vnd.api.video+json",
    "Content-Type": "application/json",
    "Authorization": auth_string
}

delegate_payload = {
    "ttl": 0
}

response = requests.request("POST", token_url, json=delegate_payload, headers=delegate_headers)

response = response.json()
token = response.get("token")

Upload Your Video That's Under 128 MB

To upload with the token, you need to send with the application/vnd.api.video+json header. Then the token is sent as a query field. The payload will be your video file, opened in binary. The title of your uploaded file will be the same name as the title of the file you send.

# Upload by URL

d_upload_headers = {
    "Accept": "application/vnd.api.video+json"
}

d_query = {"token": token}

d_payload = {
    "file": open("small_vid.mp4", "rb")
}

response = requests.request("POST", delegated_upload_url, files=d_payload, params=d_query, headers=d_upload_headers)

print(response.json())

Delegated Upload for Video Over 128 MB

This section shows you how to complete a chunked video upload. Because some of the code is the same as what was in the walkthrough directly preceding this one, we'll post the code sample, then focus in on what's different.

# How to upload a large video that is over 128 MB to api.video. (Though this script will also work for videos under 128 MB if you want to test it out.)

import requests
import os

# Set up variables for endpoints (we will create the third URL programmatically later)
auth_url = "https://ws.api.video/auth/api-key"
token_url = "https://ws.api.video/upload-tokens"
delegated_upload_url = "https://ws.api.video/upload"

# Set up headers and payload for first authentication request
headers = {
    "Accept": "application/json",
    "Content-Type": "application/json"
}

payload = {
    "apiKey": "your api key here"
}

# Send the first authentication request to get a token. The token can be used for one hour with the rest of the API endpoints.
response = requests.request("POST", auth_url, json=payload, headers=headers)
response = response.json()
token = response["access_token"]

# Set up headers and payload to generate your delegated upload token and request a token

auth_string = "Bearer " + token

delegate_headers = {
    "Accept": "application/vnd.api.video+json",
    "Content-Type": "application/json",
    "Authorization": auth_string
}

delegate_payload = {
    "ttl": 0
}

response = requests.request("POST", token_url, json=delegate_payload, headers=delegate_headers)

response = response.json()
token = response.get("token")

# Retrieve the token and upload your video using the token. This token will not expire unless you 
# specify an expiry time, or you delete it. 

CHUNK_SIZE = 1000000


# This is our chunk reader. This is what gets the next chunk of data ready to send.
def read_in_chunks(file_object, CHUNK_SIZE):
    while True:
        datas = file_object.read(CHUNK_SIZE)
        if not datas:
            break
        yield datas

# Upload your file by breaking it into chunks and sending each piece 
def upload(file, url, token):
    content_name = str(file)
    content_path = os.path.abspath(file)
    content_size = os.stat(content_path).st_size

    print(content_name, content_path, content_size)

    f = open(content_path, "rb")

    index = 0
    offset = 0
    headers = {}
    videoId = ""

    for chunk in read_in_chunks(f, CHUNK_SIZE):
        offset = index + len(chunk)
        headers['Content-Range'] = 'bytes %s-%s/%s' % (index, offset -1, content_size)
        
        try:
            if(index == 0):
                d_query = {"token": token}
                file = {"file name here": chunk}
                r = requests.post(url, files=file, params=d_query, headers=headers)
                json_response = r.json()
                videoId = json_response.get("videoId")
            else: 
                d_query = {"token": token}
                body = {"videoId": videoId}
                file = {"file name here": chunk}
                r = requests.post(url, files=file, data=body, params=d_query, headers=headers)
                
            print(r.json())
            print("r: %s, Content-Range: %s" % (r, headers['Content-Range']))
        except Exception as e:
            print(e)
            
        index = offset

# Add a path to the file you want to upload, and away we go! 
upload('your file goes here', delegated_upload_url, token)

After you get your delegated token, there are a few differences in the code to be aware of. Our read_in_chunks function stays the same, but for the upload function, notice that we set a videoId variable. This is because we are going to need to retrieve the videoId.

CHUNK_SIZE = 1000000

# This is our chunk reader. This is what gets the next chunk of data ready to send.
def read_in_chunks(file_object, CHUNK_SIZE):
    while True:
        datas = file_object.read(CHUNK_SIZE)
        if not datas:
            break
        yield datas

# Upload your file by breaking it into chunks and sending each piece 
def upload(file, url, token):
    content_name = str(file)
    content_path = os.path.abspath(file)
    content_size = os.stat(content_path).st_size

    print(content_name, content_path, content_size)

    f = open(content_path, "rb")

    index = 0
    offset = 0
    headers = {}
    videoId = ""

Because api.video creates the video container for you on a delegated upload, you don't know what videoId you're uploading to. This is fine if you're uploading a complete video, but if you're sending your video in chunks, you need to tell the server what video container you want to send the chunks to. When you send your first upload request for a chunked video, include the Content-Range header (the only header you'll need) and then retrieve the response from your request.

Get the videoId from the response, and in subsequent requests, you include the videoId. Like so:

for chunk in read_in_chunks(f, CHUNK_SIZE):
        offset = index + len(chunk)
        headers['Content-Range'] = 'bytes %s-%s/%s' % (index, offset -1, content_size)
        
        try:
            if(index == 0):
                d_query = {"token": token}
                file = {"file name here": chunk}
                r = requests.post(url, files=file, params=d_query, headers=headers)
                json_response = r.json()
                videoId = json_response.get("videoId")
            else: 
                d_query = {"token": token}
                body = {"videoId": videoId}
                file = {"file name here": chunk}
                r = requests.post(url, files=file, data=body, params=d_query, headers=headers)
                
            print(r.json())
            print("r: %s, Content-Range: %s" % (r, headers['Content-Range']))
        except Exception as e:
            print(e)
            
        index = offset

As you can see here, we use a few different tools from the requests library to make the subsequent requests. Your token for authenticating is a query parameter. The videoId goes in the body of your request. And you attach your file chunk as a file.

If you change the name of the file in your requests (the spot where it says "file name here") then your file will be named to match that. Use the same title in both places for "file name here" in the code. The file you open for upload won't be referenced, because in a chunked upload, the request doesn't get the name of the file, it just has a chunk of the file attached each time. So it's a little different than a regular upload.

There's only one step left for your chunked upload, and that's to use the function:

# Add a path to the file you want to upload, and away we go! 
upload('file_example_MP4.mp4', delegated_upload_url, token)

Ta-da! You've done it! You've uploaded a video or a chunked video... or at least read all about it. In future posts, we'll go over how to manage your tokens.

Posts You May Also Like...

Erikka Innes

Developer Evangelist

Get started now

Connect your users with videos