Skip to content
API documentation
View as MarkdownOpen in Claude

Students

Follow a batch of students you sent

GET
/v1/student/import/{importId}

Returns one of your imports and one page of its rows, in the order you sent them.

status is queued until a server picks the batch up, running while it registers, then succeeded or failed. Poll every few seconds; a batch of a thousand takes seconds, not minutes, once it starts.

On succeeded every row is registered and carries the student’s _id: keep them, and use them with getStudent, createSigninLink and createApplication. On anything else no student of this batch was registered, every row is skipped, and failure says why; the rows that explain it carry an error.

An import stops being readable 30 days after it finishes, and then answers 404 exactly like one that never existed. The students stay registered. An import another account sent answers the same way.

Parameters

Path parameters

NameTypeDescription
importIdrequiredstring

The import’s _id, as createStudentImport returned it.

Query parameters

NameTypeDescription
pageoptionalnumber

Page number. Defaults to 1.

Example 1

limitoptionalnumber

Items per page. Defaults to 20, max 100.

Example 20

Responses

200 OK

Success: message is "Import fetched successfully.".

Body

  • successbooleanrequired

    Always true on a success.

    one oftrue

  • messagestringrequired

    exampleImport fetched successfully.

  • paginationobject · PaginationMetarequired

    Where one page sits in the whole list.

    4 fields of pagination
    • pagenumberrequired

      The page returned, counting from 1.

      min1example1

    • limitnumberrequired

      Items per page: the limit you sent, 20 if you sent none, and never more than 100.

      min1max100example20

    • totalnumberrequired

      Items across every page.

      min0example57

    • totalPagesnumberrequired

      Pages at this limit: total / limit, rounded up.

      min0example3

  • dataobject · StudentImportResponserequired

    A batch of students you asked to register, and what has happened to it.

    11 fields of data
    • _idstringrequired

      The import’s _id. Read it with getStudentImport.

      example65f0c2a1d3e4f5a6b7c8d901

    • statusstringrequired

      queued until a server picks it up, running while it registers, then succeeded or failed. cancelled means an operator stopped it. There is no partial import: on anything but succeeded no student of this batch was registered.

      one ofqueuedrunningsucceededfailedcancelled

      examplequeued

    • totalnumberrequired

      How many rows you sent.

      example250

    • registerednumberrequired

      How many students were registered: total once the import has succeeded, and 0 until then and for ever after a failure.

      example250

    • clientReferencestring

      The clientReference you sent, if you sent one.

      exampleyear-10-autumn-2026

    • failureobject · StudentImportFailureResponse

      Set once the import has failed or been cancelled.

      2 fields of failure
      • codestringrequired

        A stable machine code. rows_rejected: a row stopped being registrable between the check and the write, most often because its address was registered in between; the rows say which. forbidden: the account may no longer register students. cancelled: an operator stopped it. internal_error: something failed on our side.

        examplerows_rejected

      • messagestringrequired

        Written for a person, and may change: never branch on it.

        exampleTwo rows could no longer be registered. Nothing was registered.

    • studentsarray of StudentImportRowResponserequired

      One page of the rows, in the order you sent them. Page it with page and limit; pagination.total counts every row. Absent from the answer to createStudentImport, which has nothing to report yet.

      6 fields of each item
      • rownumberrequired

        The row’s position in the students you sent, counting from 0.

        example0

      • emailstringrequired

        The address you sent for this row, in lower case.

        formatemailexamplejane.doe@example.com

      • externalRefstring

        The externalRef you sent for this row, if you sent one.

        exampleroster-2026-114

      • statusstringrequired

        pending until the import runs, then registered for every row when it succeeds, or skipped for every row when it does not. An import registers all of its students or none of them.

        one ofpendingregisteredskipped

        exampleregistered

      • studentIdstring

        The student’s _id, on a registered row. Use it with getStudent, createSigninLink and createApplication.

        example6650a1b2c3d4e5f6a7b8c9d0

      • errorobject · StudentImportRowErrorResponse

        Why this row could not be registered, when it could not.

        4 fields of error
        • codestringrequired

          A stable machine code: branch on this. invalid_field and unexpected_field are the row’s own rules; unknown_reference is a country, grade, city or school that matches nothing; duplicate_in_request is the same address twice in your own body; email_taken_by_your_student is one of your students; email_unavailable is an address that cannot be registered, and the answer never says who holds it.

          one ofinvalid_fieldunexpected_fieldunknown_referenceduplicate_in_requestemail_taken_by_your_studentemail_unavailable

          exampleemail_taken_by_your_student

        • messagestringrequired

          Written for a person, and may change: never branch on it.

          exampleOne of your students already has this email address.

        • studentIdstring

          On email_taken_by_your_student: the _id of the student of yours who has the address, so you can update them instead.

          example6650a1b2c3d4e5f6a7b8c9d0

        • duplicateOfnumber

          On duplicate_in_request: the earlier row in your own body with the same address.

          example12

    • createdAtstringrequired

      When you sent it.

      formatdate-timeexample2026-10-06T08:15:00.000Z

    • startedAtstring

      When a server picked it up.

      formatdate-timeexample2026-10-06T08:15:04.000Z

    • finishedAtstring

      When it ended, whichever way it ended.

      formatdate-timeexample2026-10-06T08:15:09.000Z

    • expiresAtstringrequired

      When this import stops being readable. After it, getStudentImport answers 404, exactly as it does for an import that never existed. The students stay registered.

      formatdate-timeexample2026-11-05T08:15:09.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": "Import fetched successfully.",
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 57,
    "totalPages": 3
  },
  "data": {
    "_id": "65f0c2a1d3e4f5a6b7c8d901",
    "status": "queued",
    "total": 250,
    "registered": 250,
    "clientReference": "year-10-autumn-2026",
    "failure": {
      "code": "rows_rejected",
      "message": "Two rows could no longer be registered. Nothing was registered."
    },
    "students": [
      {
        "row": 0,
        "email": "jane.doe@example.com",
        "externalRef": "roster-2026-114",
        "status": "registered",
        "studentId": "6650a1b2c3d4e5f6a7b8c9d0",
        "error": {
          "code": "email_taken_by_your_student",
          "message": "One of your students already has this email address.",
          "studentId": "6650a1b2c3d4e5f6a7b8c9d0",
          "duplicateOf": 12
        }
      }
    ],
    "createdAt": "2026-10-06T08:15:00.000Z",
    "startedAt": "2026-10-06T08:15:04.000Z",
    "finishedAt": "2026-10-06T08:15:09.000Z",
    "expiresAt": "2026-11-05T08:15:09.000Z"
  }
}

Example request

# $TOKEN: a short-lived token you minted with your API key and secret
curl -sS 'https://api.main-team.org/v1/student/import/<importId>?page=1&limit=20' \
  -H "Authorization: Bearer $TOKEN"

Search the API documentation

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