space ocr
GuidesArticlesPricingDocs
OCR API

An OCR API that returns data you can verify

One REST call returns structured JSON where every value carries a box, a quad and a verification verdict. Bearer auth, declared fields or autoFields, async jobs, signed webhooks.

Most OCR APIs hand you a wall of text and a confidence number for the whole page. You still have to find the invoice total, parse it, and hope it landed in the right place. The OCR API in space-ocr does the structuring for you: one POST with an image and the fields you want — or autoFields when you would rather have the API propose the schema — and you get back named values as JSON.

The part that matters for production is what rides along with each value. data.cells is keyed by the same paths as the schema you declared, and each entry holds the box the value was read from, the four corners of that box, a verified verdict and the reasons behind it. So your pipeline doesn't have to trust a model's word — it can check each value against where it actually sits on the document, and work through data.review.flagged for the ones that didn't line up.

A real response you can inspect

Hover any field below — the box on the invoice is where that value was read. This is a real parsed result: the billing name ソジュハンザン海物語様, the amount due ¥84,263, the total ¥46,752, each line item, all returned with their own box and the evidence behind the cross-check. Nothing here is mocked.

Invoice with extracted-field bounding boxes
Verified fields
Invoice

Each value with a box carries a verified on-page location — in data.cells[path], that is box + 4-point quad + evidence.match_ratio — on a 0–1000 normalized grid (0,0 top-left → 1000,1000 bottom-right), the same shape the live API returns. Hover a field to trace it back to the pixels it came from.

Three shapes, one contract
Take the page as named fields, as layout-preserving Markdown (POST /ocr/markdown), or as plain text in true reading order (POST /ocr/text). Whichever you pick, the response is the same values / cells / review / image shape, so every unit carries the coordinates it was read from and a verification verdict.
One call, JSON with boxes
POST /ocr/fields with one image and get named values back. Every path in data.cells carries its box, so you skip the second pass of finding where things are.
box, quad, review
Every cell returns xmin/ymin/xmax/ymax on a 0–1000 grid, a quad of four points that follows the page tilt, a verified verdict, and an evidence object with the supporting detail behind it.
Declare the fields you want
Send fields with a name and a type per value, plus required, pattern, min/max, enum, label or near where a rule applies — line items are an array field with children. Set autoFields instead and the API proposes the schema from the page.
Async jobs + signed webhooks
POST /upload to queue images, get a job per file, and receive an HMAC-SHA256 signed webhook on completion — or poll GET /jobs/{jobId}.
CSV and JSON exports
JSON over REST, plus CSV with a UTF-8 BOM (Excel- and CJK-safe) where line items unfold into sub-rows for a stored sheet.
Languages on autopilot
Japanese, Korean, Chinese, and English in one engine — no language hint to set, mixed scripts and full-width characters handled.

How the OCR API works in space-ocr

Authenticate with a Bearer token — your key is prefixed spocr_ — against the base URL https://api.space-ocr.com. Send one raster image to POST /ocr/fields as a URL or base64 (the public API takes images — JPEG, PNG, GIF, BMP, TIFF, WebP — so for a PDF you send page images). Declare your own fields, or set autoFields and let the API propose them, and you get back { status: 'success', data: { values, cells, review, image } }.

The coordinates aren't invented by the model. An OCR pass is the only source of geometry; the model returns values, and a character matcher then aligns each value against the symbols actually detected on the page. What comes out of that lands in data.cells[path]: box and quad for the location, verified as the verdict, review with the reasons when something didn't line up, and evidence — text_match, match_ratio, printed_text — as the supporting detail. Coordinates are evidence of where a value came from, not proof that it is right: two engines can still agree on the same misread, so keep your own business checks. All coordinates are normalized to a 0–1000 grid, and data.image gives the width and height to convert them to pixels. Every response also carries an X-Request-Id header, and errors come back as { error: { code, message, requestId } }.

extract fields from an image
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
curl -s https://api.space-ocr.com/ocr/fields \
  -H "Authorization: Bearer $SPACE_OCR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "https://example.com/invoice.png",
    "imageType": "url",
    "fields": [
      { "name": "vendor", "type": "string", "required": true },
      { "name": "invoice_date", "type": "date", "required": true },
      { "name": "total", "type": "number", "required": true, "min": 0 },
      { "name": "items", "type": "array", "children": [
        { "name": "description", "type": "string" },
        { "name": "amount", "type": "number" }
      ] }
    ]
  }'
the same call in Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os, requests

resp = requests.post(
    "https://api.space-ocr.com/ocr/fields",
    headers={"Authorization": f"Bearer {os.environ['SPACE_OCR_API_KEY']}"},
    json={
        "image": "https://example.com/invoice.png",
        "imageType": "url",
        "fields": [
            {"name": "vendor", "type": "string", "required": True},
            {"name": "invoice_date", "type": "date", "required": True},
            {"name": "total", "type": "number", "required": True, "min": 0},
        ],
    },
    timeout=60,
)
resp.raise_for_status()
data = resp.json()["data"]

print(data["values"])              # business data, in the schema you declared
print(data.get("normalized"))      # deterministic parse of the declared date and number

for item in data["review"]["flagged"]:
    cell = data["cells"].get(item["path"])   # a missing or nobox flag has no cell
    print(item["path"], item["reasons"], cell["box"] if cell else None)

How to call the OCR API

  1. Get an API key
    Sign in and create a key — it is prefixed spocr_. Send it as Authorization: Bearer <key> on every request to https://api.space-ocr.com.
  2. Send an image
    POST /ocr/fields with image (a URL or pure base64) and imageType. For a PDF, send the page images — the API takes raster formats (JPEG, PNG, GIF, BMP, TIFF, WebP).
  3. Declare the fields you want
    Send fields with a name and a type per value, adding required, pattern, min/max, enum, label or near where a rule applies — line-item tables are an array field with children. Set autoFields instead when you want the API to propose the schema.
  4. Read the structured result
    You get { status: 'success', data: { values, cells, review, image } }. values holds the business data, cells[path] its box, quad, verified verdict and evidence, and review.flagged lists the paths that need a second look with the reasons attached.
  5. Scale out and query
    Queue many images with POST /upload (job per file, signed webhooks or GET /jobs/{jobId}), then read a stored sheet with GET /view using where, sort, and select — no re-OCR, no extra charge.

Simple, predictable pricing

Pay $0.05 per image (¥10 / ₩100), with a free tier of 100 credits a month and no credit card. Reading a stored sheet back with GET /view doesn't re-OCR and isn't charged. Flat plans add monthly credits, more sheets, and storage.

Free
$0
  • 100 credits / month
  • 3 sheets
  • 1 GB storage
Free — no card
Starter
$19/mo
  • 500 credits / month
  • 15 sheets
  • 10 GB storage
Start free
Most popular
Pro
$39/mo
  • 1,100 credits / month
  • Unlimited sheets
  • 100 GB storage
Start free
How do I authenticate with the OCR API?
Send an HTTP Bearer token on every request — Authorization: Bearer <key>. Keys are prefixed spocr_. The base URL is https://api.space-ocr.com with no version path. A missing or invalid key returns 401, a request for a resource outside that key's scope returns 403, and every response carries an X-Request-Id header for support.
What does the OCR API return for each field?
Values arrive in data.values, in the schema you declared. data.cells is keyed by the same paths and holds box (xmin/ymin/xmax/ymax on a 0–1000 normalized grid, not pixels), quad (four corners that follow the document's tilt), verified (the verdict — false when anything was flagged, true when a check ran and nothing was, null when there was nothing to check), review with the reasons, and evidence such as text_match, match_ratio and printed_text. data.image gives the pixel size the coordinates are measured against.
Can the OCR API read a PDF?
The public API takes raster images — JPEG, PNG, GIF, BMP, TIFF, WebP — so for a PDF you send the page images. The web app accepts PDFs directly and renders each page to an image before OCR. The structured result is the same either way.
Does the OCR API handle large or batch jobs?
Yes. POST /upload accepts up to 20 images per request and returns a job per file with status 'pending'. Completion arrives as an HMAC-SHA256 signed webhook (X-Spaceocr-Signature), or you can poll GET /jobs/{jobId}. POST /ocr/fields stays synchronous for a single image.
Are there rate limits and error codes?
The limit is 60 requests per minute per key and 600 per minute per account. Over it you get 429 with code 'rate_limited' and a Retry-After header carrying the wait in seconds; the same value is repeated in the body at details.retryAfterSec. All errors share the envelope { error: { code, message, requestId } } across 400, 401, 402, 403, 404, 413, 429, 500, 502, and 504.
How much does the OCR API cost?
$0.05 per image (¥10 / ₩100 per call), with a free tier of 100 credits a month and no credit card. POST /ocr/fields and each image in POST /upload cost one credit; GET /space, /view, and /amount are free. Flat plans (Starter and Pro) add monthly credits, sheets, and storage — see the plans above.

Ship OCR that returns checkable data

Free tier — 100 credits a month, no credit card. Every field comes back with its box and a match score.

Related