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.