Introduction
The space ocr API combines structured OCR (extract typed fields from images) with MySpace (store and query the results). One spocr_* API key unlocks every REST endpoint and event webhook.
RESTful, JSON, and CORS-enabled. For batch and async flows, see Jobs / Webhooks.
Authentication
Every request must send Authorization: Bearer <API_KEY>. Issue and revoke keys in Developer → API Keys.
Keys are prefixed with spocr_. Revoke immediately if leaked.
curl https://api.space-ocr.com/amount \
-H "Authorization: Bearer YOUR_API_KEY"Base URL
There is a single production base URL. Versioning is signalled via keys and event apiVersion.
# Production
https://api.space-ocr.com
# OpenAPI spec
https://api.space-ocr.com/openapi.jsonRate limits
60 req/min/key, 600 req/min/uid. Exceeded requests return HTTP 429 with a Retry-After header (seconds).
All responses include an X-Request-Id (req_xxx) header — include it when contacting support.
/create and /upload support an Idempotency-Key header. Repeated requests return the cached response for 24h with X-Idempotent-Replay: true.
Errors
4xx / 5xx errors share a common envelope. requestId helps support trace the issue.
{
"error": {
"code": "invalid_request",
"message": "image is required",
"requestId": "req_xxx"
},
"details": {
/* optional, endpoint-specific context (e.g. /upload returns processable count) */
}
}HTTP status
Structured OCR
Extract typed fields from an image. Use templateId for built-in formats or fields for a custom schema.
Body parameters
curl -X POST https://api.space-ocr.com/ocr/fields \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image": "https://example.com/receipt.jpg",
"imageType": "url",
"fields": [
{ "name": "store_name", "type": "string",
"description": "Store name" },
{ "name": "date", "type": "string",
"description": "Date" },
{ "name": "items", "type": "array",
"description": "Items",
"children": [
{ "name": "name", "type": "string" },
{ "name": "qty", "type": "string" },
{ "name": "price", "type": "string" }
]
},
{ "name": "total", "type": "string",
"description": "Total" }
]
}'{
"status": "success",
"data": {
"store_name": "Supermarket ABC",
"date": "2025-04-10",
"items": [
{
"name": "Milk",
"qty": "1",
"price": "$1.99",
"bbox": { "xmin": 263, "ymin": 460, "xmax": 738, "ymax": 523 },
"vertices": [{"x":263,"y":460},{"x":738,"y":460},{"x":738,"y":523},{"x":263,"y":523}],
"match_ratio": 1.0,
"bbox_source": "vision_symbol_match",
"field_bboxes": {
"name": { "bbox": { "xmin": 263, "ymin": 460, "xmax": 503, "ymax": 492 }, "match_ratio": 1.0 },
"qty": { "bbox": { "xmin": 333, "ymin": 460, "xmax": 338, "ymax": 490 }, "match_ratio": 1.0 },
"price": { "bbox": { "xmin": 693, "ymin": 460, "xmax": 738, "ymax": 488 }, "match_ratio": 1.0 }
}
}
],
"total": "$4.94",
"bbox": { "xmin": 12, "ymin": 34, "xmax": 532, "ymax": 774 },
"vertices": [{"x":12,"y":34},{"x":532,"y":34},{"x":532,"y":774},{"x":12,"y":774}],
"match_ratio": 0.97,
"bbox_source": "vision_symbol_match",
"field_bboxes": {
"store_name": { "bbox": { "xmin": 14, "ymin": 36, "xmax": 210, "ymax": 58 }, "match_ratio": 0.98 },
"date": { "bbox": { "xmin": 14, "ymin": 80, "xmax": 180, "ymax": 102 }, "match_ratio": 1.0 },
"total": { "bbox": { "xmin": 380, "ymin": 720, "xmax": 530, "ymax": 742 }, "match_ratio": 1.0 }
}
}
}List tree
List folders / sheets / memos in MySpace. Scope with path and depth.
Query parameters
curl https://api.space-ocr.com/space?path=/&depth=1 \
-H "Authorization: Bearer YOUR_API_KEY"{
"path": "/",
"depth": 1,
"items": [
{ "path": "/invoices", "name": "invoices", "type": "folder" },
{ "path": "/memo_2024", "name": "memo", "type": "memo", "uniqueKey": "..." }
]
}View item contents
Returns folder / sheet / memo / image contents. Sheets support free server-side where / sort / limit / offset / select.
Query parameters
# Multiple where (AND) + sort + projection + pagination
curl "https://api.space-ocr.com/view?path=/invoices/sheet1\
&where=total>=10000\
&where=vendor~ABC\
&sort=-invoice_date\
&select=vendor,total,invoice_date\
&limit=20&offset=0" \
-H "Authorization: Bearer YOUR_API_KEY"// type=sheet
{
"type": "sheet",
"path": "/invoices/sheet1",
"name": "sheet1",
"columns": [ /* ... */ ],
"total": 128, // total rows in the sheet
"matched": 12, // rows that passed where
"offset": 0,
"limit": 20,
"nextOffset": 20, // next page / null when exhausted
"rows": [
{
"rowKey": "img_abc",
"name": "invoice_2025_04_10.jpg",
"imageUrl": "https://...",
"ocrStatus": "done",
"values": { "vendor": "ABC Corp", "total": "12000", "invoice_date": "2025-04-10" }
}
]
}
// type=memo
{ "type": "memo", "path": "...", "name": "todo", "text": "..." }
// type=img
{ "type": "img", "path": "...", "name": "...", "imageUrl": "...", "ocrStatus": "done" }Create folder / sheet / memo
Create a folder, sheet, or memo under the parent path. Sheets can carry an OCR schema (columns) and prompt.
Body parameters
# sheet
curl -X POST https://api.space-ocr.com/create \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"path": "/invoices",
"type": "sheet",
"name": "sheet1",
"columns": [
{ "id": "amount", "name": "amount", "type": "string" },
{ "id": "date", "name": "date", "type": "string" }
],
"prompt": "Extract amount and date from invoice"
}'// sheet/memo は uniqueKey が path に組み込まれて返却される
{ "path": "/invoices/Kvho45OXMKw…", "type": "sheet", "uniqueKey": "Kvho45OXMKw…" }Upload images
Upload one or more images into a sheet. multipart/form-data. Async by default (returns jobs, completion via webhook).
Form fields (multipart)
curl -X POST https://api.space-ocr.com/upload \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "path=/invoices/sheet1" \
-F "files=@invoice1.jpg" \
-F "files=@invoice2.jpg"// async (default)
{
"path": "/invoices/sheet1",
"jobs": [
{ "uniqueKey": "...", "originalName": "invoice1.jpg", "jobId": "job_...", "status": "pending" },
{ "uniqueKey": "...", "originalName": "invoice2.jpg", "jobId": "job_...", "status": "pending" }
]
}
// 402 — insufficient balance
{
"error": { "code": "insufficient_balance", "message": "...", "requestId": "req_..." },
"details": { "requested": 5, "processable": 3, "breakdown": [...] }
}Edit sheet cell or memo
Update a sheet cell value or memo body. anyOf: (path, row, column, value) or (path, text).
Body parameters
# sheet
curl -X POST https://api.space-ocr.com/edit \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"path":"/invoices/sheet1","row":"img_abc","column":"amount","value":"12000"}'
# memo
curl -X POST https://api.space-ocr.com/edit \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"path":"/todo","text":"new body"}'{ "ok": true, "patched": { "row": "img_abc", "column": "amount", "value": "12000" } }Delete (cascade)
Delete a folder / sheet / memo / image. Folder deletes cascade through metadata, flat entries, and Storage.
Body parameters
curl -X POST https://api.space-ocr.com/remove \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"path":"/invoices/2024"}'{ "ok": true }Poll OCR job status
Check the status of a jobId returned by POST /upload (async). Use this if you don't consume webhooks.
Path parameters
curl https://api.space-ocr.com/jobs/job_xxx \
-H "Authorization: Bearer YOUR_API_KEY"{
"jobId": "job_xxx",
"status": "done",
"uniqueKey": "img_abc",
"path": "/invoices/sheet1/img_abc",
"result": { "amount": "12000", "date": "2025-04-10" }
}Account balance and quota
Returns the current balance and available quota.
curl https://api.space-ocr.com/amount \
-H "Authorization: Bearer YOUR_API_KEY"{
"balance": 1240,
"currency": "JPY",
"freeScansRemaining": 0
}Service health
Public health check (no auth required).
curl https://api.space-ocr.com/health{ "status": "ok", "version": "v1", "time": 1716700000000 }Overview
Register one space-wide Webhook URL and every event is delivered with an HMAC signature. Configure via Developer → Webhooks or the management endpoints below.
Events
All events share the same envelope: event / deliveryId / occurredAt / apiVersion / data.
Payload example — ocr.completed
{
"event": "ocr.completed",
"deliveryId": "dlv_xxx",
"occurredAt": 1716700000000,
"apiVersion": "v1",
"data": {
"uid": "...",
"path": "/invoices/sheet1/img_abc",
"parentPath": "/invoices/sheet1",
"uniqueKey": "img_abc",
"sheetRef": "sht_xxx",
"mode": "sheet",
"result": { "amount": "12000", "date": "2025-04-10", "field_bboxes": { /* ... */ } }
}
}Delivery headers
Receivers see the headers below. Signature and Timestamp are needed for verification.
X-Spaceocr-Signature: t=<unix_ms>,v1=<hex>
X-Spaceocr-Timestamp: <unix_ms>
X-Spaceocr-Event: ocr.completed
X-Spaceocr-Delivery: dlv_<id>
Content-Type: application/jsonSignature verification
X-Spaceocr-Signature is `t=<unix_ms>,v1=<hex>`. Canonical string: `${t}.${rawBody}`. Algorithm: HMAC-SHA256. Reject if timestamp drifts more than 5 minutes.
import crypto from "crypto";
export function verify(secret, headers, rawBody) {
const sig = headers["x-spaceocr-signature"] || "";
const m = sig.match(/^t=(\d+),v1=([a-f0-9]+)$/);
if (!m) return false;
const [, t, v1] = m;
if (Math.abs(Date.now() - Number(t)) > 5 * 60 * 1000) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(v1, "hex"),
);
}Retry policy
Non-2xx triggers exponential backoff (1m → 5m → 30m → 2h → 6h), max 5 attempts. 5xx / 408 / 429 / timeout retry; other 4xx are dead. Delivery logs retained 30 days.
Get webhook configuration
Returns the currently configured space-wide webhook URL and state.
curl https://api.space-ocr.com/webhook \
-H "Authorization: Bearer YOUR_API_KEY"{
"url": "https://example.com/hooks/space-ocr",
"active": true,
"createdAt": 1716700000000,
"updatedAt": 1716700000000
}Create or update webhook
Register or update the space-wide webhook URL. Use rotateSecret to re-issue the signing secret.
Body parameters
curl -X PUT https://api.space-ocr.com/webhook \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/hooks/space-ocr","active":true}'{
"url": "https://example.com/hooks/space-ocr",
"active": true,
"secret": "whsec_..." // rotateSecret 일 때만 평문으로 한 번만 받아요
}Remove webhook
Remove the configured webhook. No further events will be delivered.
curl -X DELETE https://api.space-ocr.com/webhook \
-H "Authorization: Bearer YOUR_API_KEY"{ "ok": true }Send a test event
Immediately send a webhook.test event to the configured URL. Useful for verifying the receiver.
curl -X POST https://api.space-ocr.com/webhook/test \
-H "Authorization: Bearer YOUR_API_KEY"{ "ok": true, "deliveryId": "dlv_xxx" }List recent deliveries
Returns recent webhook delivery logs. Useful for debugging.
curl https://api.space-ocr.com/webhooks/deliveries \
-H "Authorization: Bearer YOUR_API_KEY"{
"deliveries": [
{
"deliveryId": "dlv_xxx",
"event": "ocr.completed",
"occurredAt": 1716700000000,
"status": "delivered",
"responseStatus": 200,
"attempts": 1
}
]
}Get delivery detail
Returns the full payload and attempt history for a delivery.
Path parameters
curl https://api.space-ocr.com/webhooks/deliveries/dlv_xxx \
-H "Authorization: Bearer YOUR_API_KEY"{
"deliveryId": "dlv_xxx",
"event": "ocr.completed",
"occurredAt": 1716700000000,
"payload": { /* full event body */ },
"attempts": [
{ "at": 1716700000000, "responseStatus": 200, "ok": true }
]
}Manually redeliver
Manually redeliver a failed webhook.
Path parameters
curl -X POST https://api.space-ocr.com/webhooks/deliveries/dlv_xxx/redeliver \
-H "Authorization: Bearer YOUR_API_KEY"{ "ok": true, "newDeliveryId": "dlv_yyy" }Built-in templates
13 built-in templates are available. Pass any of these IDs as templateId on POST /ocr/fields and the schema and prompt are applied automatically.