eProctor Gateway API
Use the gateway to connect external LMS, ERP, admission, candidate management, and result systems to eProctor through a stable, organization-scoped REST API.
https://gateway.eproctor.app/api/v1/organizations/{organizationId} Client integrations should call /api/v1/organizations/{organizationId} routes only. Gateway handles authentication, scopes, idempotency, rate limits, request logs, and stable responses.
Authentication
API clients use OAuth 2.0 client credentials. Store the client secret on the client server only.
curl https://gateway.eproctor.app/api/oauth/token \
-H 'Content-Type: application/json' \
-d '{
"grant_type": "client_credentials",
"client_id": "epc_live_...",
"client_secret": "eps_live_...",
"scope": "organization.read exams.read sessions.read results.read"
}'{
"access_token": "epat_...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "organization.read exams.read sessions.read results.read"
}Exam-to-session implementation flow
Follow this order when building a complete external integration from exam setup through official results and reports.
Gateway portal stepGET /api/v1/organizations/{organizationId}/capabilitiesGET/POST /api/v1/organizations/{organizationId}/proctoring-centersGET/POST /api/v1/organizations/{organizationId}/examsGET /api/v1/organizations/{organizationId}/exams/{examId}GET/POST /api/v1/organizations/{organizationId}/exams/{examId}/assessmentsPOST /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/bulkPOST /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groupsGET /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}POST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/scheduleGET/PUT /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/settingsGET /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/session-optionsPOST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessionsPOST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/candidates/bulkPOST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/credentials/bulkPOST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/close-and-generateGET /api/v1/organizations/{organizationId}/delete-impact?module=session&recordId={sessionId}&examId={examId}&assessmentId={assessmentId}&sessionId={sessionId}Production-ready endpoints
These endpoints are stable for backend integrations that need to connect an organization, list exams, select candidate lists, create lists, and sync large candidate batches.
| Method | Path | Scope | Status |
|---|---|---|---|
| GET | /api/v1/organizations/{organizationId}/capabilities | organization.read | Stable for integration capability checks. |
| GET | /api/v1/organizations/{organizationId}/exams | exams.read | Stable for listing exams available to the API client. |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists | candidate_lists.read | Stable for listing exam candidate lists. |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists | candidate_lists.write | Stable for creating candidate lists. |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/bulk | candidate_lists.write | Stable for high-volume candidate member upserts. |
For large jobs, create or select a candidate list, then send candidate-list member bulk upsert requests in background batches. Use a unique Idempotency-Key for every batch.
Scopes
Gateway checks public scopes before accepting requests. eProctor still enforces organization permissions, subscriptions, quotas, and domain rules.
organization.readRead organization profile and API capabilities.
deletions.readPreview delete/archive, cleanup, and evidence purge impact for child resources.
deletions.writeStart controlled cleanup or evidence purge workflows for child resources when allowed.
centers.readList and retrieve proctoring centers.
centers.writeCreate, update, and delete proctoring centers.
exams.readList and retrieve exams.
exams.writeCreate, update, and delete exams.
assessments.readList and retrieve assessments and assessment type options.
assessments.writeCreate, update, and delete assessments.
settings.readRead assessment settings.
settings.writeUpdate assessment settings.
grading.readRead assessment grading configuration.
grading.writeUpdate pass marks and grade bands.
schedules.readRead assessment schedules.
schedules.writeCreate, update, and delete assessment schedules.
sessions.readList sessions and read session creation options.
sessions.writeCreate, update, and delete sessions.
sessions.closeFinalize a session and generate official results/reports.
candidate_lists.readRead candidate lists, groups, and memberships.
candidate_lists.writeCreate/update candidate lists, groups, and memberships.
candidates.readRead candidates attached to a session target.
candidates.writeBulk add candidates into a session target list or group.
credentials.readRead credential generation status/list.
credentials.writeGenerate credentials through eProctor credential services.
results.readRead assessment/session results.
reports.readRead assessment/session reports.
webhooks.readList webhook endpoints.
webhooks.writeCreate/update webhook endpoints.
Capabilities
Check whether the selected organization can use the current API resources. Call this once when an integration starts or when you refresh integration metadata.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/capabilitiesReturns public API availability and supported resource groups. | organization.read |
{
"data": {
"status": "available",
"apiVersion": "v1",
"resources": [
"organization",
"deletionImpact",
"options",
"centers",
"exams",
"assessments",
"sessions",
"sessionCandidatesAndCredentials",
"finalizeAndResults"
]
}
}Returns public feature availability for the requested organization.
Safe deletion, archive impact, and cleanup
Preview the impact of a delete/archive operation before sending a DELETE request. eProctor decides whether a record can be deleted, archived, blocked, or handled through a separate cleanup or evidence purge flow.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/delete-impact?module={module}&recordId={recordId}&examId={examId}&assessmentId={assessmentId}&sessionId={sessionId}Preview blockers, warnings, and the recommended delete/archive action for a child resource. | deletions.read |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/cleanup-impactPreview complete cleanup impact for an exam. | deletions.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/cleanupStart complete exam cleanup when allowed. | deletions.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/cleanup-jobs/{jobId}Read exam cleanup job status. | deletions.read |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/cleanup-impactPreview complete cleanup impact for an assessment. | deletions.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/cleanupStart complete assessment cleanup when allowed. | deletions.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/cleanup-jobs/{jobId}Read assessment cleanup job status. | deletions.read |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/cleanup-impactPreview complete cleanup impact for a session. | deletions.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/cleanupStart complete session cleanup when allowed. | deletions.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/cleanup-jobs/{jobId}Read session cleanup job status. | deletions.read |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/evidence-impactPreview evidence/media purge impact for a session. | deletions.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/purge-evidenceStart the dedicated session evidence purge flow when storage must be freed. | deletions.write |
| Name | Type | Required | Description |
|---|---|---|---|
module | string | required | Child resource type: exam, assessment, session, schedule, candidate_list, candidate_member, candidate_group, candidate_group_member, or center. |
recordId | string | required | ID of the child record being reviewed. |
examId | string | optional | Exam ID when the resource belongs to an exam. |
assessmentId | string | optional | Assessment ID when the resource belongs to an assessment. |
sessionId | string | optional | Session ID for session delete/archive/evidence checks. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/cleanup \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d 'GET /api/v1/organizations/{organizationId}/delete-impact?module=session&recordId=sess_32f8&examId=exam_01hzy&assessmentId=asmt_8ds21&sessionId=sess_32f8'{
"ok": true,
"impact": {
"module": "session",
"recordId": "sess_32f8",
"recommendedAction": "archive",
"canHardDelete": false,
"canArchive": true,
"blockers": [],
"warnings": [
{
"key": "credentials_disabled",
"label": "Candidate credentials exist. They will be disabled with the archived session.",
"count": 120
}
]
}
}{
"ok": true,
"queued": true,
"impact": {
"scopeType": "exam",
"recordId": "exam_01hzy"
},
"job": {
"id": "cleanup_job_01",
"status": "queued",
"progressPercent": 0
}
}Returns the recommended safe action before delete/archive operations or starts a controlled cleanup job.
- Organization deletion is not available through the public API gateway. Manage organization deletion only in the eProctor dashboard owner Danger Zone.
- If recommendedAction is block, do not call DELETE. Show blockers to the operator or API client.
- If recommendedAction is archive, eProctor safely archives the record, preserves audit history, and disables related credentials where applicable.
- Complete cleanup confirmation text depends on scope: DELETE EXAM, DELETE ASSESSMENT, or DELETE SESSION. Evidence-only purge uses DELETE EVIDENCE.
- Session DELETE does not purge evidence. Use evidence-impact and purge-evidence only when storage must be freed.
Organization
Read the organization selected by the API client. Tokens are organization-scoped, so a token issued for one organization cannot access another organization.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}Retrieve organization profile visible to this integration. | organization.read |
{
"object": "organization",
"id": "org_7c7b1a",
"name": "Publish Jobs",
"status": "active",
"subscription_status": "active",
"created_at": "2026-06-16T09:00:00.000Z"
}Returns the Organization object for the organization in the URL.
Proctoring centers
Manage physical or logical proctoring centers that can be selected when creating assessment sessions.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/proctoring-centersList centers. | centers.read |
| POST | /api/v1/organizations/{organizationId}/proctoring-centersCreate a center. | centers.write |
| GET | /api/v1/organizations/{organizationId}/proctoring-centers/{centerId}Retrieve one center. | centers.read |
| PUT | /api/v1/organizations/{organizationId}/proctoring-centers/{centerId}Update a center. | centers.write |
| DELETE | /api/v1/organizations/{organizationId}/proctoring-centers/{centerId}Safely delete or archive a center after delete-impact review. | centers.write |
| GET | /api/v1/organizations/{organizationId}/centersAlias for /proctoring-centers. | centers.read |
| Name | Type | Required | Description |
|---|---|---|---|
title | string | required | Display title of the center. |
description | string | optional | Optional notes for administrators or API operators. |
status | string | optional | Center status, such as active or inactive. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/proctoring-centers \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"title": "Islamabad Center",
"description": "Main testing lab for Islamabad candidates",
"status": "active"
}'{
"object": "proctoring_center",
"id": "center_9b1f23",
"title": "Islamabad Center",
"description": "Main testing lab for Islamabad candidates",
"status": "active",
"created_at": "2026-06-16T09:15:00.000Z"
}curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/proctoring-centers/{centerId} \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"title": "Islamabad Center - Lab A",
"description": "Updated center description",
"status": "active"
}'{
"data": {
"id": "center_9b1f23",
"title": "Islamabad Center - Lab A",
"description": "Updated center description",
"status": "active",
"updated_at": "2026-06-16T10:15:00.000Z"
}
}Creates or returns a Proctoring Center object.
- The /centers path is also supported as a short alias. Prefer /proctoring-centers for clarity.
Assessment type options
Read supported assessment types before creating assessments.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/assessment-type-optionsList available assessment types. | assessments.read |
{
"object": "list",
"data": [
{ "id": "atype_cbt", "key": "cbt", "title": "Computer Based Test" },
{ "id": "atype_mcq_single", "key": "mcq_single", "title": "MCQ Single Correct" }
],
"has_more": false
}Returns a list of assessment type option objects.
Exams
Create and manage exams. An exam can contain one or more assessments and candidate lists.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/examsList exams. | exams.read |
| POST | /api/v1/organizations/{organizationId}/examsCreate an exam. | exams.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}Retrieve one exam. | exams.read |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}Update an exam. | exams.write |
| DELETE | /api/v1/organizations/{organizationId}/exams/{examId}Safely delete or archive an exam after delete-impact review. | exams.write |
| Name | Type | Required | Description |
|---|---|---|---|
name | string | required | Exam name shown in admin and integration responses. |
description | string | optional | Optional exam description. |
status | string | optional | Exam status, such as active or draft. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Mock Exam",
"description": "Optional description",
"status": "active"
}'{
"object": "exam",
"id": "exam_01hzy",
"name": "Mock Exam",
"description": "Optional description",
"status": "active",
"created_at": "2026-06-16T09:20:00.000Z"
}curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId} \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Exam By Postman",
"description": "Optional description Update By Postman",
"status": "active"
}'{
"data": {
"id": "exam_01hzy",
"name": "Exam By Postman",
"description": "Optional description Update By Postman",
"status": "active",
"updated_at": "2026-06-16T10:20:00.000Z"
}
}Creates or returns an Exam object.
Assessments under an exam
Create and manage assessments under an exam. Use assessment type options to select the assessment type.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessmentsList assessments under an exam. | assessments.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessmentsCreate an assessment. | assessments.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}Retrieve one assessment. | assessments.read |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}Update an assessment. | assessments.write |
| DELETE | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}Safely delete or archive an assessment after delete-impact review. | assessments.write |
| Name | Type | Required | Description |
|---|---|---|---|
name | string | required | Assessment name. |
assessment_type_option_id | string | required | Assessment type option returned by the assessment type options API. |
description | string | optional | Optional assessment description. |
status | string | optional | Assessment status. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Mock Assessment",
"description": "Optional description",
"assessment_type_option_id": "atype_cbt",
"status": "active"
}'{
"object": "assessment",
"id": "asmt_8ds21",
"exam_id": "exam_01hzy",
"name": "Mock Assessment",
"assessment_type_option_id": "atype_cbt",
"status": "active"
}curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId} \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Updated Mock Assessment",
"description": "Updated assessment description",
"assessment_type_option_id": "atype_cbt",
"status": "active"
}'{
"data": {
"id": "asmt_8ds21",
"exam_id": "exam_01hzy",
"name": "Updated Mock Assessment",
"status": "active",
"updated_at": "2026-06-16T10:25:00.000Z"
}
}Creates or returns an Assessment object.
Candidate lists
Create and manage exam-scoped candidate lists. Sessions can target a complete list or a group from a list.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-listsList candidate lists. | candidate_lists.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-listsCreate a candidate list. | candidate_lists.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}Retrieve one candidate list. | candidate_lists.read |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}Update a candidate list. | candidate_lists.write |
| DELETE | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}Safely delete or archive a candidate list after delete-impact review. | candidate_lists.write |
| Name | Type | Required | Description |
|---|---|---|---|
name | string | required | Candidate list name. |
description | string | optional | Optional notes. |
status | string | optional | List status. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Mock Candidate List",
"description": "Candidates imported from admission system",
"status": "active"
}'{
"object": "candidate_list",
"id": "clist_4f91",
"exam_id": "exam_01hzy",
"name": "Mock Candidate List",
"status": "active",
"candidate_count": 0
}curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId} \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Updated Candidate List",
"description": "Updated list notes",
"status": "active"
}'{
"data": {
"id": "clist_4f91",
"exam_id": "exam_01hzy",
"name": "Updated Candidate List",
"status": "active",
"candidate_count": 0
}
}Creates or returns a Candidate List object.
Candidate list members
Add, update, list, remove, or bulk upsert members inside a candidate list. Use the bulk endpoint for large integrations such as HR, ATS, LMS, or admissions systems.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/membersList members. | candidate_lists.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/membersCreate a single member. | candidate_lists.write |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/bulkBulk upsert 1–1000 members. Recommended batch size: 500. | candidate_lists.write |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/{memberId}Update a member. | candidate_lists.write |
| DELETE | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/{memberId}Remove or archive a member after delete-impact review where applicable. | candidate_lists.write |
| Name | Type | Required | Description |
|---|---|---|---|
mode | string | required | For bulk imports, use upsert. |
source | string | optional | Optional integration source label, such as publish_jobs. |
candidates | array | required | Array of 1–1000 candidates. Use 500 per request for large background sync jobs. |
candidates[].name | string | required | Candidate full name. |
candidates[].email | string | optional | Candidate email address. Used as fallback identity when external_candidate_id is absent. |
candidates[].external_candidate_id | string | optional | Your system candidate identifier. Used first for upsert matching. |
candidates[].meta | object | optional | Optional metadata for your integration, such as job, stage, or source IDs. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"mode": "upsert",
"source": "publish_jobs",
"candidates": [
{
"name": "Candidate One",
"email": "candidate@example.com",
"external_candidate_id": "pj_user_123",
"meta": {
"source": "publish_jobs",
"pj_business_id": "business_id",
"pj_job_id": "job_id",
"pj_stage_id": "stage_id",
"pj_user_draggable_id": "pivot_id"
}
}
]
}'{
"object": "bulk_candidate_list_member_import",
"inserted": 450,
"updated": 45,
"skipped": 5,
"failed": 0,
"errors": [],
"data": [
{
"id": "cand_70ae",
"external_candidate_id": "pj_user_123",
"email": "candidate@example.com",
"status": "active"
}
]
}curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/{memberId} \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Candidate One Updated",
"email": "candidate@example.com",
"external_candidate_id": "pj_user_123",
"meta": {
"source": "publish_jobs",
"pj_job_id": "job_id",
"pj_stage_id": "stage_id",
"campus": "Islamabad"
}
}'{
"data": {
"id": "cand_70ae",
"name": "Candidate One Updated",
"email": "candidate@example.com",
"external_candidate_id": "pj_user_123",
"status": "active"
}
}For bulk upsert, returns inserted, updated, skipped, and failed counts plus per-candidate errors for records that could not be imported.
- Bulk upsert requires an Idempotency-Key header. Retrying the same key with the same payload returns the original response instead of creating duplicates.
- Upsert matching is handled by eProctor: external_candidate_id is used first; normalized email is used as fallback when external_candidate_id is absent.
- The gateway accepts up to 1000 candidates per request. For jobs around 30k applicants, send 30–60 background batches with around 500 candidates per request.
- A few invalid candidates should be returned as per-candidate failures instead of failing the entire batch.
Candidate list groups
Create groups inside a list and attach or remove members. A session can target one group instead of the complete list.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groupsList groups. | candidate_lists.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groupsCreate a group. | candidate_lists.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups/{groupId}Retrieve one group. | candidate_lists.read |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups/{groupId}Update a group. | candidate_lists.write |
| DELETE | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups/{groupId}Safely delete or archive a group after delete-impact review. | candidate_lists.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups/{groupId}/membersList group members. | candidate_lists.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups/{groupId}/membersAttach members to group. | candidate_lists.write |
| DELETE | /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups/{groupId}/members/{memberId}Remove one member from group. | candidate_lists.write |
| Name | Type | Required | Description |
|---|---|---|---|
name | string | required | Group name. |
description | string | optional | Optional group notes. |
member_ids | array | optional | Optional array of candidate member IDs when attaching members. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Batch A",
"description": "Morning candidates",
"member_ids": ["cand_70ae"]
}'{
"object": "candidate_group",
"id": "cgrp_2ca4",
"candidate_list_id": "clist_4f91",
"name": "Batch A",
"member_count": 1
}curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups/{groupId} \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"name": "Batch A Updated",
"description": "Updated morning candidates"
}'{
"data": {
"id": "cgrp_2ca4",
"candidate_list_id": "clist_4f91",
"name": "Batch A Updated",
"member_count": 1
}
}Creates or returns a Candidate Group object.
Assessment schedules
Create and manage assessment schedules using timezone-aware datetimes.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/scheduleList schedules. | schedules.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/scheduleCreate a schedule. | schedules.write |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/schedule/{scheduleId}Update a schedule. | schedules.write |
| DELETE | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/schedule/{scheduleId}Safely delete or archive a schedule after delete-impact review. | schedules.write |
| Name | Type | Required | Description |
|---|---|---|---|
title | string | required | Schedule title. |
start_at | datetime | required | Start datetime with timezone offset. |
end_at | datetime | required | End datetime with timezone offset. |
duration_minutes | integer | required | Candidate attempt duration. |
buffer_minutes | integer | optional | Optional buffer window. |
capacity_per_slot | integer | optional | Optional capacity setting. |
status | string | optional | Schedule status. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/schedule \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"title": "Morning Schedule",
"start_at": "2026-06-16T09:00:00+05:00",
"end_at": "2026-06-16T12:00:00+05:00",
"duration_minutes": 180,
"buffer_minutes": 0,
"capacity_per_slot": 100,
"status": "active"
}'{
"object": "assessment_schedule",
"id": "sch_803b",
"assessment_id": "asmt_8ds21",
"title": "Morning Schedule",
"start_at": "2026-06-16T09:00:00+05:00",
"end_at": "2026-06-16T12:00:00+05:00",
"duration_minutes": 180,
"status": "active"
}curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/schedule/{scheduleId} \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"title": "Morning Schedule Updated",
"start_at": "2026-06-16T09:30:00+05:00",
"end_at": "2026-06-16T12:30:00+05:00",
"duration_minutes": 180,
"buffer_minutes": 10,
"capacity_per_slot": 100,
"status": "active"
}'{
"data": {
"id": "sch_803b",
"title": "Morning Schedule Updated",
"start_at": "2026-06-16T09:30:00+05:00",
"end_at": "2026-06-16T12:30:00+05:00",
"duration_minutes": 180,
"status": "active"
}
}Creates or returns an Assessment Schedule object.
Assessment settings
Read or update assessment settings. Use setting keys for easier API integration.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/settingsRead settings. | settings.read |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/settingsUpdate settings. | settings.write |
| Name | Type | Required | Description |
|---|---|---|---|
settings | array | required | Array of setting updates. |
settings[].key | string | optional | Setting key, such as show_immediate_result or delivery_mode. |
settings[].enabled | boolean | optional | Whether this setting is enabled. |
settings[].value | string | optional | Setting value stored as a string for consistency. |
curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/settings \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"settings": [
{ "key": "show_immediate_result", "enabled": true, "value": "true" },
{ "key": "delivery_mode", "enabled": true, "value": "online" },
{ "key": "webcam_required", "enabled": true, "value": "true" },
{ "key": "fullscreen_lock", "enabled": true, "value": "true" }
]
}'{
"object": "assessment_settings",
"assessment_id": "asmt_8ds21",
"settings": [
{ "key": "show_immediate_result", "enabled": true, "value": "true" },
{ "key": "delivery_mode", "enabled": true, "value": "online" },
{ "key": "webcam_required", "enabled": true, "value": "true" }
]
}Returns the updated Assessment Settings object.
Assessment grading
Read or update pass marks and grade bands. Band percentages are inclusive according to the configured range.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/gradingRead grading configuration. | grading.read |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/gradingUpdate grading configuration. | grading.write |
| Name | Type | Required | Description |
|---|---|---|---|
pass_marks_enabled | boolean | optional | Whether pass marks are enforced. |
pass_marks | number | optional | Minimum marks or percentage threshold, depending on assessment configuration. |
bands | array | optional | Grade band definitions. |
bands[].grade | string | optional | Grade key, such as A+. |
bands[].min_percentage | number | optional | Minimum percentage for this band. |
bands[].max_percentage | number | optional | Maximum percentage for this band. |
curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/grading \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"pass_marks_enabled": true,
"pass_marks": 50,
"bands": [
{ "grade": "A+", "grade_label": "A+", "min_percentage": 90, "max_percentage": 100, "sort_order": 1 },
{ "grade": "A", "grade_label": "A", "min_percentage": 80, "max_percentage": 89.99, "sort_order": 2 },
{ "grade": "F", "grade_label": "F", "min_percentage": 0, "max_percentage": 49.99, "sort_order": 6 }
]
}'{
"object": "assessment_grading",
"assessment_id": "asmt_8ds21",
"pass_marks_enabled": true,
"pass_marks": 50,
"bands": [
{ "grade": "A+", "min_percentage": 90, "max_percentage": 100 },
{ "grade": "A", "min_percentage": 80, "max_percentage": 89.99 },
{ "grade": "F", "min_percentage": 0, "max_percentage": 49.99 }
]
}Returns the updated Assessment Grading object.
Session creation options
Call before creating a session. This response contains the valid choices for schedule, paper variant, center, candidate target, settings summary, and grading summary.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/session-optionsRead session creation choices. | sessions.read |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/optionsAlias for /session-options. | sessions.read |
{
"object": "session_options",
"schedules": [
{ "id": "sch_803b", "title": "Morning Schedule", "status": "active" }
],
"papers": [
{ "id": "paper_24d2", "title": "English Mock Paper" }
],
"paper_variants": [
{ "id": "variant_a", "paper_id": "paper_24d2", "label": "A", "status": "locked" }
],
"proctoring_centers": [
{ "id": "center_9b1f23", "title": "Islamabad Center" }
],
"candidate_lists": [
{ "id": "clist_4f91", "name": "Mock Candidate List", "candidate_count": 120 }
],
"candidate_list_groups": [
{ "id": "cgrp_2ca4", "candidate_list_id": "clist_4f91", "name": "Batch A" }
],
"settings_summary": {
"delivery_mode": "online",
"webcam_required": true,
"fullscreen_lock": true
},
"grading_summary": {
"pass_marks_enabled": true,
"pass_marks": 50
}
}Returns a Session Options object used to build a valid Create Session request.
Sessions
Create and manage assessment sessions using selected schedule, paper variant, proctoring centers, and candidate target.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessionsList sessions. | sessions.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessionsCreate a session. | sessions.write |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}Retrieve one session. | sessions.read |
| PUT | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}Update a session. | sessions.write |
| DELETE | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}Safely archive/delete a session after delete-impact review. Sessions with attempts, credentials, results, or evidence are archived safely; evidence is retained. | sessions.write |
| Name | Type | Required | Description |
|---|---|---|---|
title | string | optional | Optional session title. |
status | string | required | Session status, such as active. |
schedule_id | string | required | Schedule selected from session-options. |
paper_id | string | required | Paper selected from session-options. |
paper_resolution_id | string | required | Locked paper variant selected from session-options. |
proctoring_center_ids | array | required | One or more center IDs selected from session-options. |
target_mode | string | required | list or group. |
candidate_list_id | string | required | Candidate list selected as the session target. |
candidate_list_group_id | string | optional | Required when target_mode is group. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"title": "Morning Session",
"status": "active",
"schedule_id": "sch_803b",
"paper_id": "paper_24d2",
"paper_resolution_id": "variant_a",
"proctoring_center_ids": ["center_9b1f23"],
"target_mode": "list",
"candidate_list_id": "clist_4f91",
"candidate_list_group_id": null
}'{
"object": "assessment_session",
"id": "sess_32f8",
"assessment_id": "asmt_8ds21",
"title": "Morning Session",
"status": "active",
"schedule_id": "sch_803b",
"paper_id": "paper_24d2",
"paper_resolution_id": "variant_a",
"target_mode": "list",
"candidate_list_id": "clist_4f91",
"candidate_count": 120,
"created_at": "2026-06-16T10:00:00.000Z"
}curl -X PUT https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId} \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"title": "Morning Session Updated",
"status": "active"
}'{
"data": {
"id": "sess_32f8",
"title": "Morning Session Updated",
"status": "active",
"updated_at": "2026-06-16T10:30:00.000Z"
}
}Creates or returns an Assessment Session object.
Add candidates into a session target
For gateway-created sessions, add candidates to the selected session target list or group. Duplicate emails are skipped and returned in the response.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/candidatesList candidates for the session target. | candidates.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/candidates/bulkBulk add candidates into the session target. | candidates.write |
| Name | Type | Required | Description |
|---|---|---|---|
candidates | array | required | Candidates to add to the session target. |
candidates[].name | string | required | Candidate name. |
candidates[].email | string | required | Candidate email. |
candidates[].external_candidate_id | string | optional | Your system candidate identifier. |
candidates[].meta | object | optional | Optional integration metadata. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/candidates/bulk \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"candidates": [
{
"name": "Candidate One",
"email": "candidate@example.com",
"external_candidate_id": "EXT-001",
"meta": { "rollNo": "101" }
},
{
"name": "Candidate Two",
"email": "candidate2@example.com",
"external_candidate_id": "EXT-002",
"meta": { "rollNo": "102" }
}
]
}'{
"object": "bulk_candidate_import",
"inserted": 2,
"updated": 0,
"skipped": 0,
"duplicates": [],
"data": [
{ "id": "cand_70ae", "external_candidate_id": "EXT-001", "email": "candidate@example.com" },
{ "id": "cand_89bd", "external_candidate_id": "EXT-002", "email": "candidate2@example.com" }
]
}Returns a bulk import summary and candidate objects created or attached.
Generate credentials
Read credential status or generate credentials through eProctor credential services.
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/credentialsRead credential status/list. | credentials.read |
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/credentials/bulkGenerate credentials for the session target. | credentials.write |
| Name | Type | Required | Description |
|---|---|---|---|
async | boolean | optional | When true, credential generation can run asynchronously. |
identifier_mode | string | optional | Identifier mode, such as email. |
password_mode | string | optional | Password generation mode, such as random. |
password_length | integer | optional | Generated password length. |
delivery.returnInResponse | boolean | optional | Whether generated credential values should be returned when allowed. |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/credentials/bulk \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"async": true,
"identifier_mode": "email",
"password_mode": "random",
"password_length": 10,
"delivery": { "returnInResponse": false }
}'{
"object": "credential_generation_job",
"id": "job_cred_11af",
"session_id": "sess_32f8",
"status": "queued",
"target_mode": "list",
"candidate_count": 120,
"created_at": "2026-06-16T10:10:00.000Z"
}Returns credential status or a credential generation job summary.
- candidateIds are not supported yet. Generate credentials for the session target list/group until selected-candidate credential generation is available.
Finalize session, results, and reports
Close the session and generate official admin results, rankings, exports, reports, and audit-ready session closure. Then read results and reports.
| Method | Path | Scope |
|---|---|---|
| POST | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/close-and-generateFinalize a session and generate official outputs. | sessions.close |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/resultsRead generated results. | results.read |
| GET | /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/reportsRead generated reports. | reports.read |
curl -X POST https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/close-and-generate \
-H 'Authorization: Bearer epat_...' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: request-2026-001' \
-d '{
"reason": "All candidate attempts completed",
"notify_webhooks": true
}'{
"object": "session_finalization",
"session_id": "sess_32f8",
"status": "closed",
"results_status": "generated",
"reports_status": "available",
"completed_at": "2026-06-16T13:10:00.000Z"
}Returns finalization status, then results and reports can be read from their GET endpoints.
- Even when immediate candidate result is enabled, close-and-generate remains the official finalization step for admin results, rankings, exports, reports, and audit-ready closure.
Webhook signing
Register webhook endpoints to receive signed eProctor events with HMAC signatures.
EProctor-Delivery-Id: delivery_uuid
EProctor-Event-Type: result.generated
EProctor-Signature: t=...,v1=...
EProctor-Webhook-Version: 2026-06-11{
"id": "evt_91af",
"type": "result.generated",
"created_at": "2026-06-16T13:11:00.000Z",
"data": {
"organization_id": "org_7c7b1a",
"exam_id": "exam_01hzy",
"assessment_id": "asmt_8ds21",
"session_id": "sess_32f8"
}
}Errors
Gateway returns errors in a stable external shape.
{
"error": {
"code": "insufficient_scope",
"message": "This token requires scope: sessions.write.",
"requestId": "req_..."
}
}Pagination
List endpoints support standard query parameters where available, such as limit and offset.
curl https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams?limit=100&offset=0 \
-H 'Authorization: Bearer epat_...'{
"object": "list",
"data": [
{ "object": "exam", "id": "exam_01hzy", "name": "Mock Exam" }
],
"limit": 100,
"offset": 0,
"has_more": false
}Idempotency
Send Idempotency-Key on write/bulk operations. It is required for candidate-list member bulk upsert. Reusing the same key with a different payload returns idempotency_conflict.
Idempotency-Key: pj-job-123-stage-eproctor-batch-001{
"error": {
"code": "idempotency_conflict",
"message": "This idempotency key was already used with a different request payload.",
"requestId": "req_..."
}
}Known limits and operational safeguards
Selected candidateIds are not supported for credential generation yet. Generate credentials for the full session target list/group until selected-candidate credential generation is available.
Organization permissions, subscription status, quota limits, delete/archive rules, credential disable/reset behavior, session target validation, evidence purge workflows, notification delivery, result generation, grading, reporting, audit logs, and candidate-session limits are enforced by eProctor.