SAGEA LogoDocs & API
Studio

OCR guide

ARVA OCR extracts text, tables, and layout from PDFs and scans. This guide shows how to prepare inputs, pick outputs, ground answers with boxes, and triage by confidence.

In this guide

  • Prepare scans and respect format and size limits
  • Pick markdown, JSON, or text output for your task
  • Use bounding boxes and language hints for mixed documents
  • Triage by confidence and improve handwriting results

Prepare clean inputs

Quality in determines quality out. Scan at 300 DPI, keep pages upright, and avoid shadows on receipts or citizenship cards. Flatten multi-page PDFs before upload instead of sending phone photos page by page.

Supported inputs are PDF, PNG, JPG, TIFF, and WEBP up to 100 MB per request. Compress oversized PDFs by lowering image DPI or splitting into page ranges, not by photographing the screen.

# Check size before upload (must stay under 100 MB)
ls -lh invoice_npr24500.pdf
 
# Process first 5 pages only
curl -X POST https://api.sagea.space/v1/ocr/process \
  -H "Authorization: Bearer $SAGEA_API_KEY" \
  -F "model=arva-ocr" \
  -F "document=@invoice_npr24500.pdf" \
  -F "output_format=markdown" \
  -F "pages=1-5"

For schemas and auth, see OCR Process. For bulk backlogs, queue files with Batch.

Pick the right output format

Choose the output that matches the next step. Markdown preserves headings and tables for chat context, JSON preserves structure for databases, and text fits plain search indexes.

TaskFormatWhy
Document QnA with SAGEmarkdownTables stay readable as context
Invoice fields to databasejsonTyped blocks plus confidence
Full-text search indextextNo markup to strip
Expense table auditjson plus bboxCell positions for review UI
import os
import requests
 
def process(path, output_format, bbox="false", hint="en-US"):
    with open(path, "rb") as f:
        return requests.post(
            "https://api.sagea.space/v1/ocr/process",
            headers={"Authorization": f"Bearer {os.environ['SAGEA_API_KEY']}"},
            files={"document": f},
            data={"model": "arva-ocr", "output_format": output_format,
                  "bbox": bbox, "language_hint": hint},
            timeout=120,
        ).json()
 
md = process("contract.pdf", "markdown")
structured = process("invoice_npr24500.pdf", "json", bbox="true")

Pair markdown output with Document QnA and JSON output with Invoice extraction.

Use boxes and language hints

Set bbox to true for tables and forms so each block returns its page and coordinates. Render those boxes in a review UI where staff can click a row and see the source cell highlighted.

Set language_hint when a page mixes scripts. A Kathmandu invoice may mix Nepali, Hindi, and English on one page, and the hint helps ARVA pick the right segmentation.

DocumentHintTip
Nepali VAT invoicene-NPKeeps Devanagari digits stable
Hindi delivery challanhi-INBetter conjunct handling
English contracten-USDefault, fastest path
Mixed Kathmandu menune-NPThen post-fix Latin names
mixed = process("menu_np_en.pdf", "json", bbox="true", hint="ne-NP")
for block in mixed["blocks"]:
    if block["type"] == "table":
        print(block["page"], block["bbox"], round(block["confidence"], 3))

See Table extraction and Multilingual documents for full patterns.

Triage by confidence and fix handwriting

Treat confidence as a router. Auto-accept high scores, queue middle scores for human review, and re-scan low scores instead of shipping them downstream.

ConfidenceActionExample
0.9 and aboveAuto-acceptClean 300 DPI invoice total
0.7 to 0.9Human reviewFaded receipt, verify total
Below 0.7Re-scan and retryBlurry photo, recapture
def route(result):
    conf = result.get("confidence", 0)
    if conf >= 0.9:
        return "accept"
    if conf >= 0.7:
        return "review"
    return "rescan"
 
print(route(structured))

Handwriting needs extra care: use dark ink on plain paper, keep one line per row, and crop tightly to the form. Print anchor words like Name and Date so ARVA can align the layout. For dedicated tips see Handwriting and the ARVA model card.

Best practices

  • Scan at 300 DPI and keep files under 100 MB before upload.
  • Default to markdown for QnA and json for structured extraction.
  • Enable bbox whenever tables, forms, or audits need positions.
  • Set language_hint for Nepali and Hindi mixes instead of relying on default.
  • Route by confidence: auto-accept, review, or re-scan with clear cutoffs.
  • Re-capture poor handwriting rather than tuning prompts around noise.

What's next

On this page