Upload one or more scanned/photographed answer sheets. Processing runs locally on this server — nothing is sent anywhere else.
Use this to integrate the reader into other systems (grading tools, student portals, scripts, etc.) without the browser UI.
POST /api/process
Send your API key either as a header (preferred for scripts/servers) or a form field (used by this page's browser upload):
X-API-Key: <your-secret>
— or —
Content-Type: multipart/form-data api_key=<your-secret>
multipart/form-data with one or more files under the field name files. Multiple files can be sent in a single request.
curl -X POST https://ocr.srv1586461.hstgr.cloud/api/process \
-H "X-API-Key: your-secret-key" \
-F "files=@sheet1.jpg" \
-F "files=@sheet2.jpg"
const form = new FormData();
form.append('files', fileInput.files[0]);
const res = await fetch('https://ocr.srv1586461.hstgr.cloud/api/process', {
method: 'POST',
headers: { 'X-API-Key': 'your-secret-key' },
body: form
});
const data = await res.json();
import requests
resp = requests.post(
"https://ocr.srv1586461.hstgr.cloud/api/process",
headers={"X-API-Key": "your-secret-key"},
files=[("files", open("sheet1.jpg", "rb")),
("files", open("sheet2.jpg", "rb"))],
)
data = resp.json()
200 OK — one result object per uploaded file, in the same order:
{
"results": [
{
"source_file": "sheet1.jpg",
"header_ocr_raw": {
"name": "...", "student_id": "...", "program": "...",
"cnic": "...", "date": "..."
},
"header_note": "Handwritten fields are OCR-best-effort only; verify manually.",
"total_questions": 100,
"bubbles_detected": 399,
"answers": { "1": "A", "2": "B", "3": null, "...": "..." },
"unanswered_or_undetected": [28, 61, 93],
"flags": { "86": " ambiguous/multiple marks" }
}
]
}
answers maps question number (string) to the detected option ("A"–"D") or null if unanswered/undetected.
Always check unanswered_or_undetected and flags before treating a sheet as fully graded.
401 Unauthorized { "detail": "Invalid or missing API key" }
400 Bad Request { "detail": "No files uploaded" }
Per-file processing errors (e.g. an unreadable image) don't fail the whole batch — that file's
result object will contain an "error" field instead of answers.
GET /health → { "status": "ok" }