Playback Authentication
A playback access token authorizes an embedded player to load one specific chapter content. Tokens are generated by your backend and passed to the player through the returned playback_url.
Who should generate the token?
Your trusted application backend should call this endpoint using a Testpress moderator or staff JWT.
- A student frontend must not call it directly.
- A normal student JWT is rejected with
403 Forbidden. - Your backend should authenticate the student and confirm their entitlement to the requested content before generating a token.
- Return only
playback_url(or, if required, the tokencode) to the frontend. Never return the moderator/staff JWT.
The frontend embeds the returned URL as an iframe src. It does not need to add an authorization header to the iframe request because authorization is carried by the access_token query parameter.
Endpoint
POST /api/v2.5/admin/videos/<chapter_content_uuid>/access-tokens/
chapter_content_uuid is the top-level uuid returned by GET /api/v2.4/contents/<chapter_content_id>/. The endpoint's older {video_id} terminology refers to this UUID—not to the numeric video.id.
Token creation requires a JWT for an institute moderator or staff user. A normal student receives 403 Forbidden.
Request body
All fields are optional.
| Name | Type | Description |
|---|---|---|
| time_to_live | integer | Token lifetime in seconds. If omitted, valid_until remains null and the token has no time-based expiry. |
| expires_after_first_usage | boolean | When true, the token is expired after its first accepted playback access. Defaults to false. |
| annotations | array | Optional watermark annotations. See Watermarking. |
- cURL
- Ruby
- Python
curl --request POST \
--url 'https://lmsdemo.testpress.in/api/v2.5/admin/videos/7aBM7cOyDTi/access-tokens/' \
--header 'authorization: JWT your_moderator_jwt' \
--header 'content-type: application/json' \
--data '{"time_to_live":600,"expires_after_first_usage":false}'
require 'json'
require 'uri'
require 'net/http'
url = URI('https://lmsdemo.testpress.in/api/v2.5/admin/videos/7aBM7cOyDTi/access-tokens/')
request = Net::HTTP::Post.new(url)
request['authorization'] = 'JWT your_moderator_jwt'
request['content-type'] = 'application/json'
request.body = {
time_to_live: 600,
expires_after_first_usage: false
}.to_json
response = Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |http|
http.request(request)
end
puts response.read_body
import requests
url = "https://lmsdemo.testpress.in/api/v2.5/admin/videos/7aBM7cOyDTi/access-tokens/"
headers = {
"authorization": "JWT your_moderator_jwt",
"content-type": "application/json",
}
payload = {
"time_to_live": 600,
"expires_after_first_usage": False,
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
Response
A successful request returns 201 Created:
{
"playback_url": "https://lmsdemo.testpress.in/embed/7aBM7cOyDTi/?access_token=ef5c288a-ee85-4840-a4f3-f39d7091938f",
"expires_after_first_usage": false,
"code": "ef5c288a-ee85-4840-a4f3-f39d7091938f",
"status": "Active",
"valid_until": "2026-08-18T10:10:00+05:30",
"annotations": [],
"created": "2026-08-18T10:00:00+05:30",
"modified": "2026-08-18T10:00:00+05:30"
}
Use playback_url as the iframe src. If constructing the URL yourself, the query parameter is singular: access_token.
Token behavior
- A token is valid only for the chapter content used to create it.
- A missing
time_to_livedoes not create a short-lived token; it creates one without time-based expiry. expires_after_first_usageis independent oftime_to_live. Either condition can expire the token.- Playback with a token requires video embedding to be enabled for the institute.
- An authenticated student may view content through normal course-access checks, but cannot call this admin token-generation endpoint.