Skip to content
API documentation
View as MarkdownOpen in Claude

Applications

Enter one of your students for an exam

POST
/v1/{organizationId}/application

Enters one of your students for one exam in this organization, and creates the payment record the application is paid through.

Before you call it: register the student (registerStudent), have them sign in to this organization once through a sign-in link (createSigninLink), which creates the organization’s own record of them, and pick the exam from listAvailableExams: a leaf’s matchedExam._id is the examId to send. An exam that list leaves out for this student is refused here too.

Checks, in order. The first that fails decides the answer.

  1. The student is yours (404). Your students are the ones your account registered; anyone else’s answers like an unknown id.
  2. The organization holds a record of the student (409).
  3. The exam exists in this organization (404).
  4. The exam is offered to this student: it is open, and it fits their grade (400 for a student with no grade), their country and has a language (409, naming the rule).
  5. The student already has this exact exam: 200 "Application already exists." with that application, and nothing is created.
  6. The student holds no other exam in the same category on the same sitting (409).

Side effects. A payment record for the exam’s price: paid with amount 0 for a free exam, pending otherwise. This API never takes or refunds money. An application for a make-up sitting is removed automatically 6 hours after it is made (see removeAfter).

Safe to retry for the same student and exam: a repeat answers 200 with the application already there. Only while the exam is still offered to the student, though, because check 4 runs first: once the sitting date has passed, a repeat answers 409 and leaves the existing application as it was.

data is the application as stored. exam, payment and user are ids, and user is the organization’s own id for the student, not your studentId; getApplication resolves them.

Parameters

Path parameters

NameTypeDescription
organizationIdrequiredstringpattern ^[0-9a-f]{24}$

The organization’s _id: 24 hexadecimal digits, as listOrganizations (GET /v1/organization) lists it.

Example 64b7f0c2a1d3e4f5a6b7c8d9

Request body

application/jsonrequired

  • examIdstringrequired

    The exam’s _id in this organization, 24 hexadecimal digits: a listAvailableExams leaf’s matchedExam._id, or an _id from listExams. It has to be an exam listAvailableExams offers this student.

    example6650a1b2c3d4e5f6a7b8c9e1

  • studentIdstringrequired

    The student’s _id, 24 hexadecimal digits: the id registerStudent returned. It has to be one of your students, the ones your account registered.

    example6650a1b2c3d4e5f6a7b8c9d0

Responses

200 OK

Nothing new had to be created: message is "Application already exists.".

Body

  • successbooleanrequired

    Always true on a success.

    one oftrue

  • messagestringrequired

    exampleApplication already exists.

  • dataobject · ApplicationRecordResponserequired

    An application as stored, with exam, user and payment as ids. Read the application to have them resolved.

    16 fields of data
    • _idstringrequired

      The application’s id: what applicationId takes.

      example6650a1b2c3d4e5f6a7b8c9e5

    • examstringrequired

      The id of the exam applied for.

      example6650a1b2c3d4e5f6a7b8c9e1

    • userstringrequired

      The organization’s own id for the student, not the id you registered them with. The application reads resolve it into a record carrying both.

      example6650a1b2c3d4e5f6a7b8c9e9

    • paymentstring

      The id of the application’s payment.

      example6650a1b2c3d4e5f6a7b8c9e6

    • partnersarray of ApplicationPartnerResponserequired

      On a team exam, the other members of the team. Empty for an exam sat alone.

      2 fields of each item
      • userstring

        The team member’s id in this organization. Not one of your students’ ids, and not resolved.

        example6650a1b2c3d4e5f6a7b8c9d6

      • acceptedboolean

        Whether they have accepted the invitation to the team.

        exampletrue

    • participatedbooleanrequired

      Whether the student has started the exam. A started application cannot be moved to another exam.

      examplefalse

    • examStartstring

      When the student started the exam; absent until then.

      formatdate-timeexample2026-11-14T10:04:12.000Z

    • examSubmittedboolean

      Whether the student has handed the exam in. A handed-in application cannot be moved to another exam.

      examplefalse

    • submitDatestring

      When the student handed the exam in; absent until then.

      formatdate-timeexample2026-11-14T11:12:40.000Z

    • simulationStartedbooleanrequired

      Whether the student has started the practice run.

      examplefalse

    • simulationStartstring

      When the student started the practice run; absent until then.

      formatdate-timeexample2026-11-07T10:00:00.000Z

    • simulationSubmittedbooleanrequired

      Whether the student has handed the practice run in.

      examplefalse

    • removeAfterstring

      Only on an application to an exam on a make-up sitting: when it will be removed, 6 hours after it was made.

      formatdate-timeexample2026-09-02T14:05:00.000Z

    • uuidstringrequired

      A short reference code for the application.

      examplea3f-09c-7e1

    • createdAtstringrequired

      When the application was made.

      formatdate-timeexample2026-09-01T09:30:00.000Z

    • updatedAtstringrequired

      When the application last changed.

      formatdate-timeexample2026-09-02T14:05:00.000Z

Headers

X-RateLimit-Limit integer

Requests your account may make to this operation per window (100).

X-RateLimit-Remaining integer

Requests left in the current window.

X-RateLimit-Reset integer

Seconds until the current window ends.

Example

{
  "success": true,
  "message": "Application already exists.",
  "data": {
    "_id": "6650a1b2c3d4e5f6a7b8c9e5",
    "exam": "6650a1b2c3d4e5f6a7b8c9e1",
    "user": "6650a1b2c3d4e5f6a7b8c9e9",
    "payment": "6650a1b2c3d4e5f6a7b8c9e6",
    "partners": [
      {
        "user": "6650a1b2c3d4e5f6a7b8c9d6",
        "accepted": true
      }
    ],
    "participated": false,
    "examStart": "2026-11-14T10:04:12.000Z",
    "examSubmitted": false,
    "submitDate": "2026-11-14T11:12:40.000Z",
    "simulationStarted": false,
    "simulationStart": "2026-11-07T10:00:00.000Z",
    "simulationSubmitted": false,
    "removeAfter": "2026-09-02T14:05:00.000Z",
    "uuid": "a3f-09c-7e1",
    "createdAt": "2026-09-01T09:30:00.000Z",
    "updatedAt": "2026-09-02T14:05:00.000Z"
  }
}

Example request

# $TOKEN: a short-lived token you minted with your API key and secret
curl -sS -X POST 'https://api.main-team.org/v1/<organizationId>/application' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  --data-binary @- <<'JSON'
{
  "examId": "6650a1b2c3d4e5f6a7b8c9e1",
  "studentId": "6650a1b2c3d4e5f6a7b8c9d0"
}
JSON

Search the API documentation

Guides, endpoints by name, path or permission, and error codes such as not_found.