# REST integration

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](/docs/proctoring/lti-1-3) 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.

## Authentication

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"}`.

## Create a session

```http
POST /proctoring/api/v1/webhooks/exam/register
Authorization: Bearer <api key>
Content-Type: application/json
```

```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:

```json
{
  "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

`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.

## Drive the lifecycle

```http
POST /proctoring/api/v1/webhooks/exam/status
Authorization: Bearer <api key>
Content-Type: application/json
```

```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:

```json
{
  "success": true,
  "session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
  "current_status": "completed"
}
```

`assessment_ended` also returns:

```json
{
  "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`.

## Reschedule or cancel

```http
POST /proctoring/api/v1/webhooks/exam/reschedule
```

```json
{
  "session_id": "9d2b6c31-1f45-4a80-b7de-5c1e0a3f9b22",
  "exam": {
    "date": "2026-09-12T09:00:00Z",
    "duration": 120
  }
}
```

```http
POST /proctoring/api/v1/webhooks/exam/cancel
```

```json
{
  "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`.

## Read results

```http
GET /proctoring/api/v1/sessions/{session_id}/violations
Authorization: Bearer <api key>
```

```json
{
  "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"
    }
  ]
}
```

```http
GET /proctoring/api/v1/sessions/{session_id}/recordings
Authorization: Bearer <api key>
```

```json
{
  "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.

## Prefer webhooks

Configure a webhook URL and secret so you receive live `violation.detected` events and `exam.completed` after recording resolution. See [Webhooks and events](/docs/proctoring/webhooks-and-events).

## Onboarding checklist

- API key issued.
- Exam hostnames registered.
- Optional partner S3 credentials configured.
- Webhook URL and secret configured.
- `register` returns `201` and you store `session_id`.
- Candidate completes check-in and reaches your exam URL.
- Your platform sends `assessment_ended` when the attempt ends.
- Your receiver verifies `X-Webhook-Signature`.

## Related

- [Overview](/docs/proctoring/overview)
- [Webhooks and events](/docs/proctoring/webhooks-and-events)
- [Proctoring settings](/docs/proctoring/proctoring-settings)
- [LTI 1.3 Proctoring Services](/docs/proctoring/lti-1-3)

_Last verified: 2026-09-03 against main._
