Skip to main content
Specialized OCR for the messy reality of legal documents. We handle what generic providers can’t: handwriting, poor scans, fax headers, and complex tables.

Quick example

curl -X POST https://api.case.dev/ocr/v1/process \
  -H "Authorization: Bearer $CASEDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
casedev ocr:v1 process \
  --document-url "https://storage.example.com/document.pdf"
import Casedev from 'casedev';

const client = new Casedev({ apiKey: process.env.CASEDEV_API_KEY });

// Submit your user's document for processing
const job = await client.ocr.v1.process({
  document_url: uploadedDocumentUrl
});

// Poll for completion
let result = await client.ocr.v1.retrieve(job.id);
while (result.status === 'pending' || result.status === 'processing') {
  await new Promise(r => setTimeout(r, 2000));
  result = await client.ocr.v1.retrieve(job.id);
}

// Return extracted text to your user
const text = await client.ocr.v1.download(job.id, 'text');
console.log(text);
import casedev
import time

client = casedev.Casedev(api_key=os.environ['CASEDEV_API_KEY'])

# Submit your user's document for processing
job = client.ocr.v1.process(
    document_url=uploaded_document_url
)

# Poll for completion
result = client.ocr.v1.retrieve(job.id)
while result.status in ['pending', 'processing']:
    time.sleep(2)
    result = client.ocr.v1.retrieve(job.id)

# Return extracted text to your user
text = client.ocr.v1.download(job.id, 'text')
print(text)
job, _ := client.Ocr.V1.Process(ctx, casedev.OcrV1ProcessParams{
	DocumentURL: casedev.F("https://storage.example.com/document.pdf"),
})
fmt.Println(job.ID)
FeatureWhy it matters for your app
Handwriting RecognitionExtract notes and annotations from uploaded documents
Table ReconstructionPreserve structure for financial statements and forms
Bates Stamp HandlingIdentify and index reference numbers separately
Searchable PDF (HOCR)Return documents with text layers your users can search

Engine Selection

Choose based on your users’ document types:
EngineBest forSpeed
doctrStandard documents. High speed, good accuracy for typed text.Fast
paddleocrTables and forms. Best-in-class table structure recognition.Slower

Output formats

FormatDescription
textPlain text extraction
jsonStructured output with coordinates, confidence scores
pdfSearchable PDF (original with text layer)

Endpoints

Process

POST /ocr/v1/process — Submit a document for OCR

Status

GET /ocr/v1/:id — Check processing status

Download

GET /ocr/v1/:id/download/:type — Download results

Common patterns

casedev ocr:v1 process \
  --document-url "$DOCUMENT_URL" \
  --callback-url "https://your-app.com/webhooks/ocr-complete"
const job = await client.ocr.v1.process({
  document_url: uploadedDocumentUrl,
  callback_url: 'https://your-app.com/webhooks/ocr-complete'
});
// We POST results to your callback when done
job = client.ocr.v1.process(
    document_url=uploaded_document_url,
    callback_url='https://your-app.com/webhooks/ocr-complete'
)
# We POST results to your callback when done
job, _ := client.Ocr.V1.Process(ctx, casedev.OcrV1ProcessParams{
	DocumentURL: casedev.F(uploadedDocumentURL),
	CallbackURL: casedev.F("https://your-app.com/webhooks/ocr-complete"),
})
// We POST results to your callback when done

From S3

casedev ocr:v1 process \
  --document-url "s3://your-bucket/documents/upload.pdf"
const job = await client.ocr.v1.process({
  document_url: 's3://your-bucket/documents/upload.pdf'
});
// We handle presigning automatically
job = client.ocr.v1.process(
    document_url='s3://your-bucket/documents/upload.pdf'
)
# We handle presigning automatically
job, _ := client.Ocr.V1.Process(ctx, casedev.OcrV1ProcessParams{
	DocumentURL: casedev.F("s3://your-bucket/documents/upload.pdf"),
})
// We handle presigning automatically

With table extraction

casedev ocr:v1 process \
  --document-url "$DOCUMENT_URL" \
  --engine paddleocr \
  --features.tables '{"format": "csv"}'
const job = await client.ocr.v1.process({
  document_url: uploadedDocumentUrl,
  engine: 'paddleocr',
  features: {
    tables: { format: 'csv' }
  }
});
job = client.ocr.v1.process(
    document_url=uploaded_document_url,
    engine='paddleocr',
    features={
        'tables': {'format': 'csv'}
    }
)
job, _ := client.Ocr.V1.Process(ctx, casedev.OcrV1ProcessParams{
	DocumentURL: casedev.F(uploadedDocumentURL),
	Engine:      casedev.F(casedev.OcrV1ProcessParamsEnginePaddleocr),
	Features: casedev.F(casedev.OcrV1ProcessParamsFeatures{
		Tables: casedev.F(casedev.OcrV1ProcessParamsFeaturesTables{Format: casedev.F("csv")}),
	}),
})

Vault

Store OCR’d documents and make them searchable with semantic search

LLMs

Analyze extracted text with AI—summarize, classify, and extract entities