For developers

Add exam marking to your product with one API call

The evaleasy AI grading API is a REST API: send a student's paper as a multipart request or a link to the file, with your key in the api-key header, and get back JSON with marks, answers and reasons for every question. Results arrive by signed webhook or polling, server-sent events give live status, and every score is computed in code. It costs 1 credit per page, and the full reference is at /docs.

Updated

What does a request to the AI grading API look like?

A request is a multipart POST to /v1/submissions, and only the paper is required. Create your key in the dashboard, where it's shown once, and send it in the api-key header. Authorization and X-API-Key headers get a 401. Then:

curl https://YOUR_API_HOST/v1/submissions -H "api-key: $EVALEASY_API_KEY" -H "Idempotency-Key: unit-3:asha-rao" -F [email protected] -F [email protected] -F [email protected] -F student_name="Asha Rao" -F strictness=hard

It returns 202 with id, status, stage, display_name, page_count and credits_charged. Other fields:

  • files: PDF, JPEG, PNG, WebP, .docx or plain text, up to 20 MB each and 30 pages per paper. Several files are pages of one paper, in order.
  • question_paper and answer_key: your files, sent separately, so the marker knows which questions to expect and which answers are right. references still takes any other file.
  • paper_type: mixed (the default), mcq, fill_blank, descriptive or question_answer. It's a strong hint for the reader.
  • marking_guide: free text up to 20,000 characters: a key, a rubric or negative marking.
  • strictness: normal (lenient), medium (the default) or hard (strict).

How do batches and idempotency keys behave?

A batch fixes the marking settings for all its papers, and an idempotency key makes a retry free. POST /v1/batches returns 201 and an id, then you send each paper to /v1/submissions with batch_id, one student per request.

  • The answer key is read once, and every paper in the batch is marked against that reading.
  • Sending marking_guide, rubric, rubric_id, question_paper, answer_key or references alongside batch_id returns 400.
  • GET /v1/batches/:id returns progress: counts by status, needs_review, average_score, highest_score and lowest_score.
  • GET /v1/batches/:id/plagiarism compares the batch's papers with each other and lists pairs for a person to check. It costs no credits, doesn't search the web, doesn't detect AI writing and doesn't change marks.
  • Retrying with the same Idempotency-Key returns 200 with the original paper and charges nothing.
  • Without the header, a repeat is a new paper and is charged again, though identical work reuses its cached reading.
  • POST /v1/submissions/:id/redo marks a finished paper again from scratch, for what it cost the first time, and returns a new submission that replaces it.

Should you use webhooks, server-sent events or polling?

Use webhooks for back-end work, server-sent events for a live progress view, and polling for simple scripts.

MethodEndpointWhat you getWhat to watch
WebhookPOST /v1/webhook-endpointssubmission.completed or submission.failed, with the full report in dataReply 2xx within 15 seconds; failures retry for about two days; de-duplicate on webhook-id
Server-sent eventsGET /v1/eventsA submission event on each status or stage change, with score and needs_reviewRefresh on ready, because missed events aren't replayed
PollingGET /v1/submissions/:idStatus, then the full reportFollow the Retry-After header while the paper is in progress

How do you verify a webhook?

Use any Standard Webhooks library with your whsec_ secret, because signatures follow that spec. By hand, it's HMAC-SHA256 over webhook-id, webhook-timestamp and the raw body, and you should reject timestamps older than 5 minutes. POST /v1/webhook-endpoints/:id/test sends a webhook.test event.

What's in the JSON result?

The result holds the paper's score and marks, plus a record for every question. At the top level are score (always out of 100), marks, student_name, feedback, consistency and grader. Each item in questions has:

  • number, type (mcq, true_false, fill_blank, numerical, short_answer, long_answer) and verdict (correct, partial, incorrect, unanswered, unclear, not_marked)
  • marks_awarded, max_marks, student_answer, correct_answer and blanks
  • answer_source (key, worked_out, none) and marked_by (code or model)
  • rationale, confidence and needs_review

Which marks come from code and which from a model?

Anything that compares exactly with your key is marked in code, and written answers are marked by a model limited to the allowed marks. Numbers compare by value (12.0 = 12, 1/2 = 0.5), and non-exact answers go to the model under the strictness setting. Written answers take 2 or 3 independent passes, and the median counts.

By default marks are final and needs_review stays false. Send mark_everything=false to get flags, then route papers with needs_review to a person before their marks go further. consistency.review_reasons says why, and grader.answer_key says whose answers the marks rest on.

How are credits charged?

Each paper costs 1 credit per page, charged when it's accepted and refunded if it can't be marked. Typed text counts one page per 3,000 characters, so a 7,000-character text field is 3 credits. A low balance returns 402 insufficient_credits with required_credits and credit_balance.

Common questions

Is there a sandbox or test mode?
No. Every key is live and new accounts start with no credits, so your first paper needs a top-up. Webhook test events cost nothing.
Can I send a class scanned into one PDF in one request?
No. Each request is one student's paper, and the server never splits a file, so split the PDF first and send each student in their own request.
How do I match results to records in my system?
Send external_id and metadata, a JSON object. Both come back with the result, and GET /v1/submissions?external_id=... finds the paper later.
How do I delete a student's data?
DELETE /v1/submissions/:id removes the paper, report and files, and DELETE /v1/batches/:id does it for a batch. Nothing is deleted by age. Papers also go to AI model providers through OpenRouter to be marked, so tell your users.

Your next stack of papers doesn't have to be your problem.

Signing up is free. Marking uses credits, at 1 credit per page.

Get started