Skip to main content

Getting started

Testpress video embedding lets you play a video hosted in your Testpress institute on another website or application. Playback uses two values:

  • The video chapter content's uuid
  • A playback access token generated for that chapter content

The API paths historically call the UUID video_id. In these endpoints, video_id means ChapterContent.uuid. It is not the numeric chapter-content id, video id, course id, or content slug.

Before you begin

Ensure that:

  • Video embedding is enabled for your Testpress institute.
  • The video has been added to a course chapter and is available for playback.
  • Your server has a Testpress JWT belonging to a moderator or staff user. Student JWTs cannot generate playback access tokens.
  • Token generation happens on your backend. Never expose an admin or moderator JWT in browser or mobile application code.

Who calls each API?

ComponentResponsibility
Student frontendAsks your backend to start playback for a chapter content, then places the returned playback_url in an iframe. It must not call the Testpress admin token endpoint.
Your backendAuthenticates the student, verifies that the student may view the requested content, calls Testpress's access-token endpoint with a moderator or staff JWT, and returns only the resulting playback_url to the frontend.
Testpress APICreates a token scoped to the requested chapter-content UUID and returns the embed playback URL.

The access-token endpoint grants moderator-level callers the ability to create playback credentials. It does not use a student JWT to decide which student receives the URL. Your backend must perform that authorization before issuing a playback URL.

Integration flow

1. Find the numeric chapter-content ID

Retrieve the contents of a course:

GET /api/v3/courses/<course_id>/contents/?type=video

Each item in results.contents is a chapter content. Its numeric id identifies the placement of the video in that course chapter.

{
"results": {
"contents": [
{
"id": 10639,
"title": "Introduction",
"content_type": "Video",
"video_id": 3557
}
]
}
}

See Get Course Contents for filters and the complete response structure.

2. Resolve the chapter-content UUID

Use the numeric chapter-content ID from step 1:

GET /api/v2.4/contents/10639/
Authorization: JWT <student_or_admin_jwt>

Read the top-level uuid from the response:

{
"id": 10639,
"uuid": "7aBM7cOyDTi",
"content_type": "Video",
"video": {
"id": 3557,
"title": "Introduction"
}
}

Use 7aBM7cOyDTi as {video_id} in the token and embed URLs. See Get Chapter Content Details.

3. Generate a playback access token

From your backend, send a moderator or staff JWT to:

POST /api/v2.5/admin/videos/7aBM7cOyDTi/access-tokens/
Authorization: JWT <moderator_or_staff_jwt>
Content-Type: application/json

For a token valid for 10 minutes:

{
"time_to_live": 600,
"expires_after_first_usage": false
}

The response includes both the token in code and a ready-to-use playback_url:

{
"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": []
}

See Playback Authentication for request examples and token options.

In a typical integration, your application exposes its own student-facing endpoint, such as POST /api/video-playback, and keeps the Testpress moderator JWT only on the server:

# Example server-side flow. Adapt authentication and authorization to your app.
import requests

def create_playback_url(authenticated_student, chapter_content_uuid):
if not student_can_view(authenticated_student, chapter_content_uuid):
raise PermissionError("The student cannot view this content")

response = requests.post(
"https://lmsdemo.testpress.in/api/v2.5/admin/videos/"
f"{chapter_content_uuid}/access-tokens/",
headers={
"authorization": "JWT " + TESTPRESS_MODERATOR_JWT,
"content-type": "application/json",
},
json={"time_to_live": 600},
timeout=10,
)
response.raise_for_status()
return {"playback_url": response.json()["playback_url"]}

TESTPRESS_MODERATOR_JWT must come from protected server configuration, not from a request sent by the browser.

4. Embed the returned playback URL

Prefer the server-provided playback_url instead of constructing it manually:

<iframe
width="560"
height="315"
src="https://lmsdemo.testpress.in/embed/7aBM7cOyDTi/?access_token=ef5c288a-ee85-4840-a4f3-f39d7091938f"
title="Introduction"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>

For a dynamic student frontend, request a fresh URL from your backend and assign it to the iframe:

<iframe id="testpress-player" width="560" height="315" allowfullscreen></iframe>

<script>
async function loadVideo(chapterContentUuid) {
const response = await fetch('/api/video-playback', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({chapter_content_uuid: chapterContentUuid}),
});

if (!response.ok) {
throw new Error('Unable to authorize video playback');
}

const {playback_url} = await response.json();
document.querySelector('#testpress-player').src = playback_url;
}

loadVideo('7aBM7cOyDTi');
</script>

The browser receives only the short-lived playback URL. It never receives the Testpress moderator JWT.

Identifier reference

ValueExampleWhere it is used
Course ID1583/api/v3/courses/1583/contents/
Numeric chapter-content ID10639/api/v2.4/contents/10639/
Video record ID3557Returned inside video data; not used in the embed URL
Chapter-content UUID7aBM7cOyDTiToken endpoint and /embed/ playback URL; historically named video_id
Access-token codeef5c288a-...The access_token query parameter in the playback URL

Security recommendations

  • Generate short-lived tokens just before playback instead of reusing permanent embed codes.
  • Generate tokens on your server and return only playback_url or code to the frontend.
  • Use expires_after_first_usage only when a token truly needs to be single-use.
  • Configure domain restrictions when playback should work only on approved websites.
  • Do not log JWTs, access-token codes, or signed playback URLs.