API Reference
REST APIJSONOAuth 2.0API v1Signed webhooks

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.

Base URL
https://gateway.eproctor.app
Current version
/api/v1
Organization scoped
/organizations/{organizationId}
Use only public gateway paths

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.

Request
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"
  }'
Response
{
  "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.

1. User selects organization in gateway portal
Gateway portal step
portal session
2. Check API capabilities
GET /api/v1/organizations/{organizationId}/capabilities
organization.read
3. List or create proctoring centers
GET/POST /api/v1/organizations/{organizationId}/proctoring-centers
centers.read / centers.write
4. List or create exams
GET/POST /api/v1/organizations/{organizationId}/exams
exams.read / exams.write
5. Select an exam
GET /api/v1/organizations/{organizationId}/exams/{examId}
exams.read
6. List/create assessments and candidate lists
GET/POST /api/v1/organizations/{organizationId}/exams/{examId}/assessments
assessments.read / assessments.write
7. Bulk upsert candidate list members for large imports
POST /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/bulk
candidate_lists.write
8. Optionally create candidate groups
POST /api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups
candidate_lists.write
9. Select an assessment
GET /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}
assessments.read
10. Add schedules
POST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/schedule
schedules.write
11. Get/update settings and grading
GET/PUT /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/settings
settings.read/write + grading.read/write
12. Fetch session-options
GET /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/session-options
sessions.read
13. Create session using schedule, paper variant, centers, and candidate target
POST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions
sessions.write
14. Optionally bulk-add candidates into the selected session target
POST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/candidates/bulk
candidates.write
15. Generate credentials
POST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/credentials/bulk
credentials.write
16. Finalize session and read results/reports
POST /api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/close-and-generate
sessions.close
17. Before any delete/archive/cleanup action, check impact
GET /api/v1/organizations/{organizationId}/delete-impact?module=session&recordId={sessionId}&examId={examId}&assessmentId={assessmentId}&sessionId={sessionId}
deletions.read

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.

MethodPathScopeStatus
GET/api/v1/organizations/{organizationId}/capabilitiesorganization.readStable for integration capability checks.
GET/api/v1/organizations/{organizationId}/examsexams.readStable for listing exams available to the API client.
GET/api/v1/organizations/{organizationId}/exams/{examId}/candidate-listscandidate_lists.readStable for listing exam candidate lists.
POST/api/v1/organizations/{organizationId}/exams/{examId}/candidate-listscandidate_lists.writeStable for creating candidate lists.
POST/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/bulkcandidate_lists.writeStable for high-volume candidate member upserts.
High-volume candidate sync

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

Read organization profile and API capabilities.

deletions.read

Preview delete/archive, cleanup, and evidence purge impact for child resources.

deletions.write

Start controlled cleanup or evidence purge workflows for child resources when allowed.

centers.read

List and retrieve proctoring centers.

centers.write

Create, update, and delete proctoring centers.

exams.read

List and retrieve exams.

exams.write

Create, update, and delete exams.

assessments.read

List and retrieve assessments and assessment type options.

assessments.write

Create, update, and delete assessments.

settings.read

Read assessment settings.

settings.write

Update assessment settings.

grading.read

Read assessment grading configuration.

grading.write

Update pass marks and grade bands.

schedules.read

Read assessment schedules.

schedules.write

Create, update, and delete assessment schedules.

sessions.read

List sessions and read session creation options.

sessions.write

Create, update, and delete sessions.

sessions.close

Finalize a session and generate official results/reports.

candidate_lists.read

Read candidate lists, groups, and memberships.

candidate_lists.write

Create/update candidate lists, groups, and memberships.

candidates.read

Read candidates attached to a session target.

candidates.write

Bulk add candidates into a session target list or group.

credentials.read

Read credential generation status/list.

credentials.write

Generate credentials through eProctor credential services.

results.read

Read assessment/session results.

reports.read

Read assessment/session reports.

webhooks.read

List webhook endpoints.

webhooks.write

Create/update webhook endpoints.

01 endpoint

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.

MethodPathScope
GET/api/v1/organizations/{organizationId}/capabilities

Returns public API availability and supported resource groups.

organization.read
Response
{
  "data": {
    "status": "available",
    "apiVersion": "v1",
    "resources": [
      "organization",
      "deletionImpact",
      "options",
      "centers",
      "exams",
      "assessments",
      "sessions",
      "sessionCandidatesAndCredentials",
      "finalizeAndResults"
    ]
  }
}
Returns

Returns public feature availability for the requested organization.

0a12 endpoints

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.

MethodPathScope
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-impact

Preview complete cleanup impact for an exam.

deletions.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/cleanup

Start 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-impact

Preview complete cleanup impact for an assessment.

deletions.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/cleanup

Start 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-impact

Preview complete cleanup impact for a session.

deletions.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/cleanup

Start 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-impact

Preview evidence/media purge impact for a session.

deletions.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/purge-evidence

Start the dedicated session evidence purge flow when storage must be freed.

deletions.write
Parameters
NameTypeRequiredDescription
modulestringrequiredChild resource type: exam, assessment, session, schedule, candidate_list, candidate_member, candidate_group, candidate_group_member, or center.
recordIdstringrequiredID of the child record being reviewed.
examIdstringoptionalExam ID when the resource belongs to an exam.
assessmentIdstringoptionalAssessment ID when the resource belongs to an assessment.
sessionIdstringoptionalSession ID for session delete/archive/evidence checks.
Request
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'
Response
{
  "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
      }
    ]
  }
}
Update response
{
  "ok": true,
  "queued": true,
  "impact": {
    "scopeType": "exam",
    "recordId": "exam_01hzy"
  },
  "job": {
    "id": "cleanup_job_01",
    "status": "queued",
    "progressPercent": 0
  }
}
Returns

Returns the recommended safe action before delete/archive operations or starts a controlled cleanup job.

Notes
  • 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.
11 endpoint

Organization

Read the organization selected by the API client. Tokens are organization-scoped, so a token issued for one organization cannot access another organization.

MethodPathScope
GET/api/v1/organizations/{organizationId}

Retrieve organization profile visible to this integration.

organization.read
Response
{
  "object": "organization",
  "id": "org_7c7b1a",
  "name": "Publish Jobs",
  "status": "active",
  "subscription_status": "active",
  "created_at": "2026-06-16T09:00:00.000Z"
}
Returns

Returns the Organization object for the organization in the URL.

26 endpoints

Proctoring centers

Manage physical or logical proctoring centers that can be selected when creating assessment sessions.

MethodPathScope
GET/api/v1/organizations/{organizationId}/proctoring-centers

List centers.

centers.read
POST/api/v1/organizations/{organizationId}/proctoring-centers

Create 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}/centers

Alias for /proctoring-centers.

centers.read
Parameters
NameTypeRequiredDescription
titlestringrequiredDisplay title of the center.
descriptionstringoptionalOptional notes for administrators or API operators.
statusstringoptionalCenter status, such as active or inactive.
Request
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"
}'
Response
{
  "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"
}
Update request
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"
}'
Update response
{
  "data": {
    "id": "center_9b1f23",
    "title": "Islamabad Center - Lab A",
    "description": "Updated center description",
    "status": "active",
    "updated_at": "2026-06-16T10:15:00.000Z"
  }
}
Returns

Creates or returns a Proctoring Center object.

Notes
  • The /centers path is also supported as a short alias. Prefer /proctoring-centers for clarity.
31 endpoint

Assessment type options

Read supported assessment types before creating assessments.

MethodPathScope
GET/api/v1/organizations/{organizationId}/assessment-type-options

List available assessment types.

assessments.read
Response
{
  "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

Returns a list of assessment type option objects.

45 endpoints

Exams

Create and manage exams. An exam can contain one or more assessments and candidate lists.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams

List exams.

exams.read
POST/api/v1/organizations/{organizationId}/exams

Create 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
Parameters
NameTypeRequiredDescription
namestringrequiredExam name shown in admin and integration responses.
descriptionstringoptionalOptional exam description.
statusstringoptionalExam status, such as active or draft.
Request
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"
}'
Response
{
  "object": "exam",
  "id": "exam_01hzy",
  "name": "Mock Exam",
  "description": "Optional description",
  "status": "active",
  "created_at": "2026-06-16T09:20:00.000Z"
}
Update request
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"
}'
Update response
{
  "data": {
    "id": "exam_01hzy",
    "name": "Exam By Postman",
    "description": "Optional description Update By Postman",
    "status": "active",
    "updated_at": "2026-06-16T10:20:00.000Z"
  }
}
Returns

Creates or returns an Exam object.

55 endpoints

Assessments under an exam

Create and manage assessments under an exam. Use assessment type options to select the assessment type.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments

List assessments under an exam.

assessments.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments

Create 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
Parameters
NameTypeRequiredDescription
namestringrequiredAssessment name.
assessment_type_option_idstringrequiredAssessment type option returned by the assessment type options API.
descriptionstringoptionalOptional assessment description.
statusstringoptionalAssessment status.
Request
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"
}'
Response
{
  "object": "assessment",
  "id": "asmt_8ds21",
  "exam_id": "exam_01hzy",
  "name": "Mock Assessment",
  "assessment_type_option_id": "atype_cbt",
  "status": "active"
}
Update request
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"
}'
Update response
{
  "data": {
    "id": "asmt_8ds21",
    "exam_id": "exam_01hzy",
    "name": "Updated Mock Assessment",
    "status": "active",
    "updated_at": "2026-06-16T10:25:00.000Z"
  }
}
Returns

Creates or returns an Assessment object.

65 endpoints

Candidate lists

Create and manage exam-scoped candidate lists. Sessions can target a complete list or a group from a list.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists

List candidate lists.

candidate_lists.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists

Create 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
Parameters
NameTypeRequiredDescription
namestringrequiredCandidate list name.
descriptionstringoptionalOptional notes.
statusstringoptionalList status.
Request
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"
}'
Response
{
  "object": "candidate_list",
  "id": "clist_4f91",
  "exam_id": "exam_01hzy",
  "name": "Mock Candidate List",
  "status": "active",
  "candidate_count": 0
}
Update request
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"
}'
Update response
{
  "data": {
    "id": "clist_4f91",
    "exam_id": "exam_01hzy",
    "name": "Updated Candidate List",
    "status": "active",
    "candidate_count": 0
  }
}
Returns

Creates or returns a Candidate List object.

75 endpoints

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.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members

List members.

candidate_lists.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members

Create a single member.

candidate_lists.write
POST/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/members/bulk

Bulk 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
Parameters
NameTypeRequiredDescription
modestringrequiredFor bulk imports, use upsert.
sourcestringoptionalOptional integration source label, such as publish_jobs.
candidatesarrayrequiredArray of 1–1000 candidates. Use 500 per request for large background sync jobs.
candidates[].namestringrequiredCandidate full name.
candidates[].emailstringoptionalCandidate email address. Used as fallback identity when external_candidate_id is absent.
candidates[].external_candidate_idstringoptionalYour system candidate identifier. Used first for upsert matching.
candidates[].metaobjectoptionalOptional metadata for your integration, such as job, stage, or source IDs.
Request
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"
      }
    }
  ]
}'
Response
{
  "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"
    }
  ]
}
Update request
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"
  }
}'
Update response
{
  "data": {
    "id": "cand_70ae",
    "name": "Candidate One Updated",
    "email": "candidate@example.com",
    "external_candidate_id": "pj_user_123",
    "status": "active"
  }
}
Returns

For bulk upsert, returns inserted, updated, skipped, and failed counts plus per-candidate errors for records that could not be imported.

Notes
  • 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.
88 endpoints

Candidate list groups

Create groups inside a list and attach or remove members. A session can target one group instead of the complete list.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups

List groups.

candidate_lists.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups

Create 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}/members

List group members.

candidate_lists.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/candidate-lists/{listId}/groups/{groupId}/members

Attach 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
Parameters
NameTypeRequiredDescription
namestringrequiredGroup name.
descriptionstringoptionalOptional group notes.
member_idsarrayoptionalOptional array of candidate member IDs when attaching members.
Request
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"]
}'
Response
{
  "object": "candidate_group",
  "id": "cgrp_2ca4",
  "candidate_list_id": "clist_4f91",
  "name": "Batch A",
  "member_count": 1
}
Update request
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"
}'
Update response
{
  "data": {
    "id": "cgrp_2ca4",
    "candidate_list_id": "clist_4f91",
    "name": "Batch A Updated",
    "member_count": 1
  }
}
Returns

Creates or returns a Candidate Group object.

94 endpoints

Assessment schedules

Create and manage assessment schedules using timezone-aware datetimes.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/schedule

List schedules.

schedules.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/schedule

Create 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
Parameters
NameTypeRequiredDescription
titlestringrequiredSchedule title.
start_atdatetimerequiredStart datetime with timezone offset.
end_atdatetimerequiredEnd datetime with timezone offset.
duration_minutesintegerrequiredCandidate attempt duration.
buffer_minutesintegeroptionalOptional buffer window.
capacity_per_slotintegeroptionalOptional capacity setting.
statusstringoptionalSchedule status.
Request
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"
}'
Response
{
  "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"
}
Update request
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"
}'
Update response
{
  "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"
  }
}
Returns

Creates or returns an Assessment Schedule object.

10a2 endpoints

Assessment settings

Read or update assessment settings. Use setting keys for easier API integration.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/settings

Read settings.

settings.read
PUT/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/settings

Update settings.

settings.write
Parameters
NameTypeRequiredDescription
settingsarrayrequiredArray of setting updates.
settings[].keystringoptionalSetting key, such as show_immediate_result or delivery_mode.
settings[].enabledbooleanoptionalWhether this setting is enabled.
settings[].valuestringoptionalSetting value stored as a string for consistency.
Request
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" }
  ]
}'
Response
{
  "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

Returns the updated Assessment Settings object.

10b2 endpoints

Assessment grading

Read or update pass marks and grade bands. Band percentages are inclusive according to the configured range.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/grading

Read grading configuration.

grading.read
PUT/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/grading

Update grading configuration.

grading.write
Parameters
NameTypeRequiredDescription
pass_marks_enabledbooleanoptionalWhether pass marks are enforced.
pass_marksnumberoptionalMinimum marks or percentage threshold, depending on assessment configuration.
bandsarrayoptionalGrade band definitions.
bands[].gradestringoptionalGrade key, such as A+.
bands[].min_percentagenumberoptionalMinimum percentage for this band.
bands[].max_percentagenumberoptionalMaximum percentage for this band.
Request
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 }
  ]
}'
Response
{
  "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

Returns the updated Assessment Grading object.

112 endpoints

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.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/session-options

Read session creation choices.

sessions.read
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/options

Alias for /session-options.

sessions.read
Response
{
  "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

Returns a Session Options object used to build a valid Create Session request.

125 endpoints

Sessions

Create and manage assessment sessions using selected schedule, paper variant, proctoring centers, and candidate target.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions

List sessions.

sessions.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions

Create 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
Parameters
NameTypeRequiredDescription
titlestringoptionalOptional session title.
statusstringrequiredSession status, such as active.
schedule_idstringrequiredSchedule selected from session-options.
paper_idstringrequiredPaper selected from session-options.
paper_resolution_idstringrequiredLocked paper variant selected from session-options.
proctoring_center_idsarrayrequiredOne or more center IDs selected from session-options.
target_modestringrequiredlist or group.
candidate_list_idstringrequiredCandidate list selected as the session target.
candidate_list_group_idstringoptionalRequired when target_mode is group.
Request
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
}'
Response
{
  "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"
}
Update request
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"
}'
Update response
{
  "data": {
    "id": "sess_32f8",
    "title": "Morning Session Updated",
    "status": "active",
    "updated_at": "2026-06-16T10:30:00.000Z"
  }
}
Returns

Creates or returns an Assessment Session object.

132 endpoints

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.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/candidates

List candidates for the session target.

candidates.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/candidates/bulk

Bulk add candidates into the session target.

candidates.write
Parameters
NameTypeRequiredDescription
candidatesarrayrequiredCandidates to add to the session target.
candidates[].namestringrequiredCandidate name.
candidates[].emailstringrequiredCandidate email.
candidates[].external_candidate_idstringoptionalYour system candidate identifier.
candidates[].metaobjectoptionalOptional integration metadata.
Request
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" }
    }
  ]
}'
Response
{
  "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

Returns a bulk import summary and candidate objects created or attached.

142 endpoints

Generate credentials

Read credential status or generate credentials through eProctor credential services.

MethodPathScope
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/credentials

Read credential status/list.

credentials.read
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/credentials/bulk

Generate credentials for the session target.

credentials.write
Parameters
NameTypeRequiredDescription
asyncbooleanoptionalWhen true, credential generation can run asynchronously.
identifier_modestringoptionalIdentifier mode, such as email.
password_modestringoptionalPassword generation mode, such as random.
password_lengthintegeroptionalGenerated password length.
delivery.returnInResponsebooleanoptionalWhether generated credential values should be returned when allowed.
Request
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 }
}'
Response
{
  "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

Returns credential status or a credential generation job summary.

Notes
  • candidateIds are not supported yet. Generate credentials for the session target list/group until selected-candidate credential generation is available.
153 endpoints

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.

MethodPathScope
POST/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/sessions/{sessionId}/close-and-generate

Finalize a session and generate official outputs.

sessions.close
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/results

Read generated results.

results.read
GET/api/v1/organizations/{organizationId}/exams/{examId}/assessments/{assessmentId}/reports

Read generated reports.

reports.read
Request
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
}'
Response
{
  "object": "session_finalization",
  "session_id": "sess_32f8",
  "status": "closed",
  "results_status": "generated",
  "reports_status": "available",
  "completed_at": "2026-06-16T13:10:00.000Z"
}
Returns

Returns finalization status, then results and reports can be read from their GET endpoints.

Notes
  • 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.

Headers
EProctor-Delivery-Id: delivery_uuid
EProctor-Event-Type: result.generated
EProctor-Signature: t=...,v1=...
EProctor-Webhook-Version: 2026-06-11
Example event
{
  "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"
  }
}
Supported event types
exam.createdexam.updatedassessment.createdassessment.updatedsession.createdsession.updatedsession.startedsession.closedsession.completedcandidate.addedcredential.createdresult.generatedresult.updatedresult.publishedproctoring.violation.createdproctoring.media.ready

Errors

Gateway returns errors in a stable external shape.

{
  "error": {
    "code": "insufficient_scope",
    "message": "This token requires scope: sessions.write.",
    "requestId": "req_..."
  }
}
invalid_tokenexpired_tokeninsufficient_scopeorganization_mismatchsubscription_requiredvalidation_errorrate_limitedidempotency_conflictplatform_unavailable

Pagination

List endpoints support standard query parameters where available, such as limit and offset.

Request
curl https://gateway.eproctor.app/api/v1/organizations/{organizationId}/exams?limit=100&offset=0 \
  -H 'Authorization: Bearer epat_...'
Response
{
  "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.

Request header
Idempotency-Key: pj-job-123-stage-eproctor-batch-001
Conflict response
{
  "error": {
    "code": "idempotency_conflict",
    "message": "This idempotency key was already used with a different request payload.",
    "requestId": "req_..."
  }
}

Known limits and operational safeguards

Selected-candidate credential generation is not enabled yet

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.

eProctor enforces operational rules

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.