Use this path when your platform is not launching Endpoint through LTI. If your platform supports LTI Proctoring Services, use LTI 1.3 Proctoring Services for the full lifecycle.
Production host: https://app.endpoint.solutions
All endpoints here are server-to-server. Do not call them from browser JavaScript; the credential is a long-lived tenant API key.
Send:
Authorization: Bearer <api key>
The prefix must be exactly Bearer with one space. Missing or malformed auth returns 401 with {"error":"Missing Authorization header"}. An unknown key returns 401 with {"error":"Invalid API key"}.
POST /proctoring/api/v1/webhooks/exam/register
Authorization: Bearer <api key>
Content-Type: application/json
{
"user": {
"id": "u-8814",
"firstName": "Ada",
"lastName": "Lovelace",
"email": "ada@example.com"
},
"course": {
"id": "c-204",
"name": "Network Security"
},
"exam": {
"id": "exam-204",
"name": "Network Security Final",
"url": "https://exams.example.com/instances/exam-204",
"duration": 90,
"date": "2026-09-10T14:00:00Z",
"level": "professional",
"instructions": "Closed book."
}
}
user, course, and exam must all be present. user.email must be a valid email address. Other fields are stored as metadata and may be blank.
Send user.firstName and user.lastName if you want name matching during ID verification. Send exam.url; it is where the candidate is sent after check-in, and its host must be registered so the extension can arm.
Success:
{
"success": true,
"session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
"check_in_url": "https://app.endpoint.solutions/proctoring/candidate/start/xF3k...",
"message": "Exam registration received"
}
Store session_id. It is the stable identifier for lifecycle updates and read endpoints.
check_in_url is a bearer secret. It is not single-use. The candidate can reopen it to resume check-in or staging.
The URL stops working once the session reaches in_progress, completed, finalized, or cancelled. Deliver it only to the intended candidate.
REST sessions use the default candidate policy unless Endpoint changes tenant settings. There is no REST per-attempt policy claim.
POST /proctoring/api/v1/webhooks/exam/status
Authorization: Bearer <api key>
Content-Type: application/json
{
"session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
"event_type": "assessment_ended"
}
Identify sessions by session_id whenever possible. reservation_uuid and exam.id fallback lookups exist, but session_id is the reliable key.
event_type |
Current behavior |
|---|---|
assessment_started |
Starts monitoring only if the candidate has completed staging. Returns 200 either way; check current_status. |
assessment_ended |
Ends the attempt from in_progress or stopping, calculates compliance score, starts recording finalization, and returns results inline. |
assessment_finalized |
Moves a completed session to finalized. |
assessment_canceled, assessment_reservation_canceled |
Cancels the session. Use before the exam starts. |
assessment_no_showed, assessment_archived, assessment_passed |
Logged; no state change. |
assessment_errored, assessment_failed, assessment_failed_exit_interview |
Logged for investigation; no automatic termination. |
assessment_built |
Not a supported partner event. Do not send it. |
Standard response:
{
"success": true,
"session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
"current_status": "completed"
}
assessment_ended also returns:
{
"results": {
"compliance_score": 90,
"started_at": "2026-09-10T14:02:11Z",
"ended_at": "2026-09-10T15:28:40Z",
"duration_minutes": 86,
"violations": [
{
"id": 4412,
"type": "tab_switch",
"severity": "medium",
"description": "Switched away from the exam tab",
"occurred_at": "2026-09-10T14:41:03Z"
}
]
}
}
Recordings are not in the inline results because they may still be uploading. Use webhooks or the recordings read endpoint.
Cancel is not a clean end for an in-progress attempt. To keep evidence, send assessment_ended.
POST /proctoring/api/v1/webhooks/exam/reschedule
{
"session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
"exam": {
"date": "2026-09-12T09:00:00Z",
"duration": 120
}
}
POST /proctoring/api/v1/webhooks/exam/cancel
{
"session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
"reason": "candidate withdrew"
}
Both require bearer auth. reschedule requires an exam object. cancel sets status to cancelled and does not produce exam.completed.
GET /proctoring/api/v1/sessions/{session_id}/violations
Authorization: Bearer <api key>
{
"session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
"violations": [
{
"id": 4412,
"type": "tab_switch",
"severity": "medium",
"description": "Switched away from the exam tab",
"occurred_at": "2026-09-10T14:41:03Z"
}
]
}
GET /proctoring/api/v1/sessions/{session_id}/recordings
Authorization: Bearer <api key>
{
"session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
"recordings_ready": true,
"recordings": [
{
"type": "camera",
"url": "s3://your-bucket/proctoring/9d2b6c31/camera.webm",
"storage_provider": "partner_s3",
"duration_seconds": 5189,
"file_size_bytes": 104857600
}
]
}
The recordings endpoint lists only partner_s3 recordings. recordings_ready means no upload is still pending; it does not mean every upload succeeded. Failed and skipped recordings are terminal states.
Routes for GET /proctoring/api/v1/sessions/{session_id}, /status, and /report may appear in older material, but they are not implemented read APIs. Use the two endpoints above.
Configure a webhook URL and secret so you receive live violation.detected events and exam.completed after recording resolution. See Webhooks and events.
register returns 201 and you store session_id.assessment_ended when the attempt ends.X-Webhook-Signature.Last verified: 2026-09-03 against main.