Skip to content

ZeroExam API

One REST API serves every ZeroExam client. It publishes its own OpenAPI 3.1 specification, which is the authoritative contract.

ResourcePath
Interactive reference<base-url>/docs
OpenAPI 3.1 document<base-url>/openapi.json
Health check<base-url>/health

Read the specification rather than a hand-maintained endpoint list — the specification is generated from the running routes.

Terminal window
curl -s <base-url>/openapi.json | jq '.info, (.paths | keys)'

Most endpoints require an authenticated session. Sessions are cookie-based and issued under <base-url>/auth/*.

Requests are scoped to a workspace. A session that has no active workspace cannot read or write workspace-owned resources.

MethodPathPurpose
GET/healthService health
GET/api/public/catalogPublished, publicly visible plans and prices
POST/api/public/enterprise-leadsEnterprise contact form submission
GET/api/public/join/:tokenPreview an invitation before signing in
GET/api/exams/share/:tokenAn exam behind a share link
GET/api/exams/share/:token/questionsStudent-safe questions, correct answers removed
POST/api/exams/share/:token/submitSubmit answers and receive a score

Everything else requires a session.

Identifiers are opaque strings. Do not assume UUID format — user, session, and workspace identifiers are not UUIDs. Treat every identifier as a non-empty string.

  • Request and response bodies are JSON, except file exports, which stream as attachments.
  • Errors return a JSON body with an error field.
  • Long-running work — document processing, question generation — returns success as soon as the job is accepted. Poll the relevant status endpoint for the outcome.
  • traceparent and x-request-id are accepted on requests and echoed on responses; include them when reporting a problem.
Terminal window
# Fetch student-safe questions for a share link
curl -s "<base-url>/api/exams/share/<token>/questions"
Reading the specification for a specific area
Terminal window
# Every documents endpoint
curl -s <base-url>/openapi.json | jq '.paths | with_entries(select(.key | startswith("/api/documents")))'