Skip to main content
Examino uses a two-step upload flow: you first register a file with the API to receive a presigned storage URL, then you push the file bytes directly to that URL. The Examino API never sees your file content, which is what makes bulk imports of hundreds of copies fast and reliable. Once a file is uploaded, you attach it to one or more copies via the Copies API.

Step 1 - Register a file

Call POST /api/v1/uploads to register the file metadata. The API returns a presigned PUT URL, method, headers, and an expiry. You use all of these in Step 2. Required scope: copies:write
string
required
MIME type of the file, e.g. application/pdf or image/png. Between 1 and 200 characters.
integer
required
Exact byte size of the file. This value is signed into the presigned URL, a request body of any other size will be rejected by storage.
string
Original filename, e.g. copie-dupont.pdf. Maximum 500 characters. Used for display in the web app.
integer
Page count, if known. Must be strictly positive. Providing this value can speed up processing.
Request
Response 201

Response fields

string
UUID that identifies this registered file. Save it, you’ll pass it to POST /exams/{examId}/copies to attach the file to a student copy.
string | null
The filename you provided, echoed back.
string
The MIME type you provided, echoed back.
string
HTTP method to use for the upload request. Always PUT.
string
Presigned storage URL. Use this as the request URL in Step 2. The URL contains authentication and is single-use.
object
Headers you must include on the PUT request. Typically includes content-type and content-length. You must send all of them exactly as returned.
integer
Seconds until the presigned URL expires. Always 3600 (one hour).

Step 2 - Push the file

Use the method, url, and headers from the Step 1 response to push the file bytes directly to storage. Do not add extra headers or modify the ones provided.
Request
A successful upload returns an empty 200 OK response from the storage provider. There is no Examino API call for this step.
The presigned URL expires one hour after it is issued. If you don’t complete the upload within that window, call POST /api/v1/uploads again to get a new URL. The old fileId is invalidated and cannot be used to attach a copy.
A fileId is unattached until you call POST /exams/{examId}/copies. An unattached file is not visible in the web app and is not processed until it is linked to a copy.
For bulk imports, register and upload all files in parallel before making a single batched POST /copies call. This is the fastest way to import a large class set.

Accepted formats and limits

Supported file types

Size and page limits


Error reference

The 400 invalid_request is returned at registration time, before any data is transferred, you don’t need to attempt the upload to discover whether a format is supported.
Errors from the presigned PUT come directly from the storage provider, not from the Examino API. Common causes:
  • URL expired, the one-hour window passed. Re-register the file.
  • Wrong content-length, the byte count does not match what was signed into the URL. Re-register with the correct fileSize.
  • Wrong content-type, the header does not match the registered fileType. Re-register with the correct fileType.