Examplary
  • Start for free
    Developer docs/Embed sessions

    Take exam (student) flow (pre-release)

    Pre-release feature

    The take-exam flow is not yet available in the production environment. It is currently available on staging only.

    Using the Examplary take exam flow, you can embed the full student-facing exam experience for an existing exam directly into your application. From within the embed, your students can take the exam and submit their answers.

    This flow is intended for a single exam session: the student takes the exam once, answers all questions, and submits. Each answer is persisted in real time.

    Presets

    KeyTypeDescription
    examIdstringThe ID of the exam that should be taken by the student. Must start with exam_. Required. The actor user must have access to take this exam.

    Example

    1. Create an Examplary user for your student

    Each student needs an Examplary user account in your workspace. This is how we attribute answers and sessions to the individual student.

    POST /users
    {
      "email": "my-student@example.com",
      "name": "My Student"
    }

    Store the returned user ID in your system — you'll use it as the actor for the student's embed sessions.

    2. Make sure an exam exists and the actor can take it

    The take exam flow operates on an existing exam. If you don't have one yet, create it first (API reference).

    The student user must be given the participant role on the exam — this is what allows them to take it and submit answers:

    POST /exams
    {
      "name": "Midterm Exam - Algebra",
      "subject": "Mathematics",
      "questions": [
        // ...
      ],
      "permissions": [
        {
          "actor": "ACTOR_USER_ID",
          "role": "participant"
        }
      ],
      "metadata": {
        "my_service_internal_id": "abc1234"
      }
    }

    3. Create an embed session

    Call the Examplary API to create a new embed session for the take-exam flow. The only required preset is examId — the ID of the exam to take.

    The actor field should contain the ID of the Examplary user account you created for the student.

    Specify an allowedOrigin if you want to listen for postMessage updates from the iframe.

    POST /embed-sessions
    {
      "flow": "take-exam",
      "actor": "user_423r9j3r0jeddJA...",
      "presets": {
        "examId": "exam_55S843D7HfNfs9RY48..."
      },
      "theme": {
        "primaryColor": "#4f46e5",
        "locale": "en"
      },
      "metadata": {
        "my_service_internal_id": "abc1234"
      },
      "allowedOrigin": "https://app.example.com"
    }

    This returns a response that looks like this:

    {
      "id": "embed_session_55S843D7HfNfs9RY48PoTprXnRcz2Vw8Crst64UYrBnz...",
      "status": "pending",
      "embedUrl": "https://app.examplary.ai/embeds/55S843D7HfNf...",
      "flow": "take-exam",
      "actor": "user_423r9j3r0jeddJA...",
      "enabledResponseModes": ["post_message"],
      "createdAt": "2025-12-09T16:52:52.120Z",
      "expiresAt": "2025-12-16T16:52:52.120Z",
      "presets": {
        "examId": "exam_55S843D7HfNfs9RY48..."
      },
      "outputs": {},
      "theme": {
        "primaryColor": "#4f46e5",
        "locale": "en"
      },
      "metadata": {
        "my_service_internal_id": "abc1234"
      }
    }

    4. Lead the student to the embed URL

    You can either redirect the student directly to the URL, or display it in an iframe. Embedding inside an iframe is usually preferable so the student stays inside your application.

    If you specified an allowedOrigin, you can listen for status updates via the postMessage API:

    const embedUrl = "https://app.examplary.ai/embeds/55S843D7HfNf...";
     
    iframe.src = embedUrl;
     
    window.addEventListener("message", (event) => {
      // Make sure the message is coming from a trusted origin
      if (event.origin !== new URL(embedUrl).origin) return;
     
      const { type, status } = event.data;
      if (type === "examplary:embed-status-update") {
        if (status === "started") {
          // Fired each time the student answers a question
          console.log("Question answered");
        } else if (status === "completed") {
          // The student handed in the exam or the session reached the time limit
          console.log("Exam completed");
        }
      }
    });

    The following status values are emitted during a take-exam session:

    StatusDescription
    startedFired each time the student answers a question
    completedThe student handed in the exam, or the session reached the time limit

    5. Cleanup

    The embed session will expire automatically after 7 days, but because it gives some limited access to your account, you might want to remove it manually:

    DELETE /embed-sessions/{embedSessionId}