space ocr

APIドキュメント

https://api.space-ocr.com

概要

space ocr API は、文書画像を名前付きフィールド・Markdown・プレーンテキストのいずれかとして読み取り、値ごとに読み取り位置の座標と検証フラグを返します。その結果を保存・閲覧するのが MySpace です。spocr_* で始まる API キー 1 本で、すべての REST エンドポイントとイベント webhook を利用できます。

RESTful、JSON、CORS 対応。可変長のバッチや非同期処理は Jobs / Webhooks セクションで案内します。

5分クイックスタート

キー発行 → curl をコピペ → JSON。初回呼び出しまで 5 分あれば十分です。無料枠は毎月 100 件。

① Developer → API Keys でキーを発行します(カード不要)。

② 右の curl をそのまま実行 — サンプル画像は実際にホスティングされているので、キーを差し替えるだけで動きます。

③ レスポンスの data.values の値と、data.cells の box / quad / verified、data.review.flagged(要確認リスト)を確認してください。

④ コードを書く前に試したいときは、MySpace コンソールがそのままプレイグラウンドになります。シートにファイルを置けば API と同じ結果が並び、セルをクリックすると元画像の座標まで確認できます。API からアップロードした文書も同じシートに現れるので、自動処理と目視確認を同じ場所で扱えます。

リクエスト
1
2
3
4
5
6
7
8
curl -X POST https://api.space-ocr.com/ocr/fields \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "https://space-ocr.com/samples/two-receipts.jpg",
    "imageType": "url",
    "fields": [{ "name": "store_name" }, { "name": "total" }]
  }'

認証

すべてのリクエストは Authorization ヘッダーで Bearer <APIキー> を送ります。キーは Developer → API Keys から発行・失効できます。

キー形式は spocr_ で始まる文字列です。漏洩した場合は即時に失効してください。

リクエスト
1
2
curl https://api.space-ocr.com/amount \
  -H "Authorization: Bearer YOUR_API_KEY"

Base URL

本番 base URL は単一です。バージョニングはキーとイベントペイロードの apiVersion で管理します。

1
2
3
4
5
# Production
https://api.space-ocr.com

# OpenAPI spec
https://api.space-ocr.com/openapi.json

Rate limits

60 req/min/key、600 req/min/uid。超過時は HTTP 429 と Retry-After ヘッダーで待機秒数を返します。

応答には常に X-Request-Id (req_xxx) と X-RateLimit-Remaining(その分に残る呼び出し数)が含まれます。サポート連絡時には X-Request-Id を添えてください。

/ocr/fields・/create・/upload は Idempotency-Key ヘッダーをサポートします。同一キーの再送は 24h キャッシュされ、X-Idempotent-Replay: true で示されます。

画像サイズと応答時間

応答時間はリクエストの画像サイズにほぼ比例します。観測分布は p50 7.2 秒 / p90 10.5 秒(SLA ではありません)。

JSON ボディは 2MB までなので、base64(ファイルの約 1.33 倍)では実質 ~1.5MB が上限です。それを超える場合は imageType: "url" で URL を渡すか、/upload(非同期・ファイルあたり 20MB)+ /jobs ポーリングまたは webhook をご利用ください。処理が 110 秒を超えると ocr_engine_timeout になります — その際は縮小するか非同期経路へ。

エラー

4xx / 5xx は共通エンベロープで返却されます。requestId はサポート連絡時の手がかりです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "error": {
    "code": "validation_failed",
    "message": "imageType is required",
    "requestId": "req_xxx"
  },
  "details": {
    /* optional, endpoint-specific context (e.g. /upload returns processable count) */
  }
}

// error.code: validation_failed | bad_request | invalid_image | invalid_api_key
//           | key_inactive | unauthorized | forbidden | not_found
//           | insufficient_balance | rate_limited | ocr_engine_error
//           | ocr_engine_timeout | storage_error | internal_error

HTTP ステータス

200
正常
400
リクエスト不正 / バリデーション失敗。画像 URL を取得できない・base64 が壊れている場合も同じ 400(code: invalid_image、課金されません)。再試行しても結果は変わりません
401
API キーが無効または欠落
402
残高不足。/upload は details.requested / processable / breakdown を含む
403
スコープ外のリソース(例: 他のキーが作成した job)
404
path 不存在 / api.space-ocr.com 以外でアクセス
413
ボディが 2MB 超 / ファイルが 20MB 超
429
レート制限。Retry-After に秒数
500
内部エラー
502
OCR エンジン側エラー(自動返金済み)。message に実際の理由が入ります。画像入力そのものの問題は 400 invalid_image に分かれるので、502 は再試行する価値があります
504
OCR エンジンが時間内に応答せず(自動返金済み)。画像を縮小して再試行
POST/ocr/fieldsBearer¥10

構造化 OCR

画像から名前付きフィールドを抽出します。fields で抽出スキーマを指定するか、autoFields で自動提案させます。

ボディパラメータ

imagestringrequired
Base64 文字列または画像 URL。base64 で JSON ボディが 2MB を超える場合は URL 指定か /upload をご利用ください。
imageType"base64" | "url"required
image の型を明示。旧名 image_type も後方互換で動作(非推奨)。
fieldsarray<FieldSpec>optional
抽出スキーマ配列。autoFields を使う場合は省略可。値は必ずページに印刷されたまま返ります — だから座標に結び付けて検証できます。
namestringrequired
レスポンス JSON のキーになります。
type"string" | "array" | "object" | "number" | "integer" | "date"optional
既定は string。number / integer / date を宣言しても values は印字されたまま返ります — 型がモデルに渡ることはありません(型を伝えると、その形の値を作ってしまいます)。宣言した型が生むのは normalized という第二の層で、同じ読みをその型に解釈した値が values と同じ形で並びます("¥13,220" → 13220、"令和8年8月16日" → "2026-08-16"、"3袋" → 3)。解釈は決定的で追加のモデル呼び出しはありません。解釈できなかった値は normalized で null になり、reason "type_mismatch" が付きます — 多くの場合それは誤読の合図です。
descriptionstringoptional
その値がどこにあるかのヒント(例: 「合計の右」)。
childrenarray<FieldSpec>optional
type が array / object のときの子フィールド。同じ FieldSpec が再帰的に入ります。
requiredbooleanoptional
true の項目が空で返るか、レスポンスから丸ごと欠けた場合は review.flagged に reason "missing" として記録されます — 返ってこなかった値には照合する相手が無いため、文字照合が原理的に見られない唯一のクラスです。モデルには渡らないので抽出の動きは変わりません(必須だと伝えると、印字されていない値を推測しないという指示と衝突します)。無くて当然の項目にまで付けると合図が埋もれるので、必ず印字される値だけに付けてください。
labelstring | string[]optional
値の横に印字されているラベル(例: "合計")。同じ値がページに複数回印字されているとき、座標をそのラベルの隣の出現にアンカーします。トップレベルの string フィールド専用(配列・オブジェクトの子は無視)で、ラベルがページに正確に 1 回だけ印字されているときのみ働き、見つからなければ通常の検索に静かに戻ります。required と同じくモデルには渡りません — 抽出テキストは変わらず、座標のアンカーだけが変わります。候補が複数あるときは配列で(例: ["発行日", "発行年月日"])。
patternstring | string[]optional
正規化後の値が満たすべき正規表現。JSON Schema と同じ部分一致なので、値全体を見るときは ^…$ を付けてください。配列を渡すと「どれか 1 つ満たせば通過」になります。string 型専用。照合は全角を半角に畳んだ値に対して行うので、ページが全角で印字されていても素の ASCII パターンが効きます(T12… は T12… として照合)。破ると reason "pattern_mismatch"。モデルには渡りません — 形を教えると、その形の値を作ってしまいます。
min / maxnumberoptional
number / integer 型の値の範囲(両端を含む)。正規化後の数値に対して判定し、外れると reason "out_of_range" が付きます。
enumstring[]optional
string 型で許可する値の集合。正規化後の値と照合します。両エンジンが同じ誤読で一致してしまうクラス(冊 を 申 と読むなど)に効く唯一の手立てです — 文字どうしの突き合わせは、両方が同じ間違いをしたときに構造的に何も言えません。破ると reason "pattern_mismatch"。
review"normal" | "off"optional
"off" にすると、そのフィールドについてエンジンが推定した検討理由(text_mismatch・low_ratio・ambiguous_occurrence など)を出しません。証跡はすべて残り、判定だけを控えます。品名や備考のような自由記述の列に付けておくと、登録番号や合計に立った印が読めるようになります。宣言したルール(required の missing、pattern・min/max・enum 違反)は消せません — 自分で書いた規則が、自分で書いた別のキーで取り消せてしまうのは危険だからです。
autoFieldsbooleanoptional
true で fields 不指定時に LLM がスキーマを自動提案。旧名 auto_fields も後方互換で動作(非推奨)。
promptstringoptional
自由記述の指示(任意)。

レスポンスフィールド

status"success"
成功時は常に "success"。エラーは HTTP 4xx/5xx と共通エラー envelope(Errors 参照)で返り、このボディにはなりません。
data.valuesobject
リクエストのスキーマそのままの純粋なユーザーデータ。予約キーが混ざらないので、そのまま DB に保存できます。値は必ずページに印刷されたまま返ります。
data.cellsmap<path, Cell>
パスをキーにしたフラットな座標・検証マップ。キーは review.flagged[].path と同じ文法(items[0].price)なので、flagged のパスでそのまま O(1) 参照できます。items[0] のような行パスは行全体のユニオンボックスです。
box{ xmin, ymin, xmax, ymax }
軸平行の矩形。0〜1000 正規化です(data.image でピクセルに戻せます)。
quad[{ x, y } × 4]
傾いたスキャンに追従する 4 点。box と常に両方付きます。
verifiedboolean | null
その座標が指す OCR 原文と値が正規化後に一致したか(2 つの独立エンジンの合意)。false はモデルが文字を変えた可能性。null は検証対象外(行ユニオンなど幾何のみの項目)。
review{ reason, reasons } | null
null なら通過、値が入っていれば人の確認を推奨。reason: type_mismatch | out_of_range | pattern_mismatch | nobox | text_mismatch | crop_mismatch | low_ratio | weak_source | low_ocr_confidence | ambiguous_occurrence | overwide_box | missing。前の 3 つは呼び出し側が宣言したルール違反なので、エンジンの推定より上位にランクされます。reason は常にその 1 位ひとつ、reasons は破られたルール全部の配列で、長さ 1 でも必ず入っています(reasons[0] は必ず reason と同じ)。
evidenceobject
判定の生データ — source(座標の出どころ: vision_symbol_match / token_id …)/ match_ratio(文字照合の一致率)/ ocr_confidence(一致グリフに対する OCR 自身の信頼度の最小値、無ければキー無し)/ crop_verified(切り出し再読の結果、実行時のみ)。
normalized{ value, type, method, error? }
スカラー型(number / integer / date、あるいは pattern・enum を付けた string)を宣言したフィールドにだけ付きます。data.normalized のその葉が null だった理由がここにあります — error は not_numeric / not_an_integer / not_a_date / no_year。method は現在つねに "deterministic"(追加のモデル呼び出しはありません)。
data.reviewobject
文書 1 枚分の検証サマリー。フィールドごとの判定は cells 側、ここは集計と要確認リストです。
unit"field"
集計単位。
declaredinteger
空の値・返ってこなかった required も数えた全スロット(固定分母)。
returnedinteger
空でない値の数。
boxedinteger
座標が付いたセルの数。
verifiedinteger
verified: true のセルの数。
flagged[{ path, reason, reasons }]
要確認リスト。件数はこの配列の長さそのもの(別カウンタなし)、path は cells のキーと同じ文法。値はあるのに座標が無いフィールド(nobox)と、返ってこなかった required(missing)はセルが無く、ここにだけ現れます。reason は順位 1 位ひとつ、reasons は破られたルール全部です。
by_reasonobject
理由別の内訳(例: { "pattern_mismatch": 1, "text_mismatch": 1 })。1 つのセルが宣言したルールとエンジンの疑いの両方に触れることがあるため、reasons に載った理由を すべて 数えます。したがって合計は flagged の件数以上になります(検討の 件数 は flagged.length のままです)。
notesarray
スカラー型(number / integer / date)を宣言したときに付きます — 値は印字されたまま返し、宣言した型は normalized 側で使ったというお知らせです(path / declared_type / applied_type / description)。
data.normalizedobject
スカラー型(number / integer / date、あるいは pattern・enum を付けた string)を宣言したフィールドがあるときだけ付きます。values と まったく同じ形 のツリーで、葉だけがその型に解釈された値です(normalized.items[0].qty が values.items[0].qty の隣に並びます)。宣言した葉だけの 疎な ツリーで、解釈できなかった葉は null — 理由は cells[path].normalized.error にあります。解釈は決定的なので、同じページなら毎回同じ値です。values 側は印字されたまま不変で、座標と検証が付いているのはそちらです。
data.image{ width, height }
元画像のピクセルサイズ。0〜1000 の正規化座標をピクセルに戻すのに使います(pixel_x = box.xmin / 1000 × width)。
リクエスト
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
26
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": "店舗名" },
      { "name": "date",       "type": "string",
        "description": "取引日" },
      { "name": "invoice_no", "type": "string", "required": true,
        "description": "伝票番号" },
      { "name": "items",      "type": "array",
        "description": "購入品目",
        "children": [
          { "name": "name",  "type": "string" },
          { "name": "qty",   "type": "string" },
          { "name": "price", "type": "string" }
        ]
      },
      { "name": "total",      "type": "number", "required": true,
        "label": "合計",
        "description": "合計" }
    ]
  }'
レスポンス
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
{
  "status": "success",
  "data": {
    "values": {
      "store_name": "スーパー ABC",
      "date": "2025-04-10",
      "invoice_no": "",
      "items": [
        { "name": "牛乳", "qty": "1", "price": "¥198" }
      ],
      "total": "¥548"
    },
    "cells": {
      "store_name":     { "box": { "xmin": 14, "ymin": 36, "xmax": 210, "ymax": 58 },
                          "quad": [{"x":14,"y":36},{"x":210,"y":36},{"x":210,"y":58},{"x":14,"y":58}],
                          "verified": true, "review": null,
                          "evidence": { "source": "vision_symbol_match", "match_ratio": 0.98, "ocr_confidence": 0.96 } },
      "date":           { "box": { "xmin": 14, "ymin": 80, "xmax": 180, "ymax": 102 },
                          "quad": [{"x":14,"y":80},{"x":180,"y":80},{"x":180,"y":102},{"x":14,"y":102}],
                          "verified": true, "review": null,
                          "evidence": { "source": "token_id", "match_ratio": 1.0, "ocr_confidence": 0.99 } },
      "items[0]":       { "box": { "xmin": 263, "ymin": 460, "xmax": 738, "ymax": 523 },
                          "quad": [{"x":263,"y":460},{"x":738,"y":460},{"x":738,"y":523},{"x":263,"y":523}],
                          "verified": null, "review": null,
                          "evidence": { "source": "vision_symbol_match", "match_ratio": 1.0 } },
      "items[0].name":  { "box": { "xmin": 263, "ymin": 460, "xmax": 503, "ymax": 492 },
                          "quad": [{"x":263,"y":460},{"x":503,"y":460},{"x":503,"y":492},{"x":263,"y":492}],
                          "verified": true, "review": null,
                          "evidence": { "source": "token_id", "match_ratio": 1.0, "ocr_confidence": 0.97 } },
      "items[0].qty":   { "box": { "xmin": 333, "ymin": 460, "xmax": 338, "ymax": 490 },
                          "quad": [{"x":333,"y":460},{"x":338,"y":460},{"x":338,"y":490},{"x":333,"y":490}],
                          "verified": true, "review": null,
                          "evidence": { "source": "vision_symbol_match", "match_ratio": 1.0, "ocr_confidence": 0.94 } },
      "items[0].price": { "box": { "xmin": 693, "ymin": 460, "xmax": 738, "ymax": 488 },
                          "quad": [{"x":693,"y":460},{"x":738,"y":460},{"x":738,"y":488},{"x":693,"y":488}],
                          "verified": false,
                          "review": { "reason": "text_mismatch", "reasons": ["text_mismatch"] },
                          "evidence": { "source": "vision_symbol_match", "match_ratio": 1.0, "ocr_confidence": 0.88 } },
      "total":          { "box": { "xmin": 380, "ymin": 720, "xmax": 530, "ymax": 742 },
                          "quad": [{"x":380,"y":720},{"x":530,"y":720},{"x":530,"y":742},{"x":380,"y":742}],
                          "verified": true, "review": null,
                          "evidence": { "source": "vision_symbol_match", "match_ratio": 1.0, "ocr_confidence": 0.98 },
                          "normalized": { "value": 548, "type": "number", "method": "deterministic" } }
    },
    "review": {
      "unit": "field",
      "declared": 7,
      "returned": 6,
      "boxed": 6,
      "verified": 5,
      "flagged": [
        { "path": "items[0].price", "reason": "text_mismatch", "reasons": ["text_mismatch"] },
        { "path": "invoice_no", "reason": "missing", "reasons": ["missing"] }
      ],
      "by_reason": { "text_mismatch": 1, "missing": 1 },
      "notes": [
        { "path": "total", "declared_type": "number", "applied_type": "string",
          "description": "\"total\" was declared as number and read as string. Values are returned exactly as printed on the page so the text can be matched to coordinates and verified; the declared type was kept as an extraction hint, not applied as formatting." }
      ]
    },
    // 宣言した型は values を書き換えず、この層に出ます
    "normalized": { "total": 548 },
    "image": { "width": 1654, "height": 2339 }
  }
}
POST/ocr/markdownBearer¥10

Markdown 変換

レイアウトを保ったまま画像を Markdown に変換します。見出し・段落・リスト・表が要素として返り、要素ごとに座標が付きます。

ボディパラメータ

imagestringrequired
Base64 文字列または画像 URL。base64 で JSON ボディが 2MB を超える場合は URL 指定か /upload をご利用ください。
imageType"base64" | "url"required
image の型を明示。旧名 image_type も後方互換で動作(非推奨)。
promptstringoptional
レイアウト解釈への自由記述の追加指示(任意)。
includeElementsbooleanoptional
既定 true — values.elements(内容)と cells(要素ごとの座標・検証)を返します。false にすると組み立て済みの Markdown 文字列のみ。

レスポンスフィールド

status"success"
成功時は常に "success"。エラーは HTTP 4xx/5xx と共通エラー envelope(Errors 参照)で返り、このボディにはなりません。
data.values.markdownstring
組み立て済みの Markdown 文字列。
data.values.elementsarray<Element>
内容だけの要素配列。座標と検証フラグは cells 側に分離されています。どの要素も請求しなかった OCR トークンは paragraph(evidence.source: unclaimed_tokens)として末尾に回収され、落ちた段落が消えません。
type"heading" | "paragraph" | "list_item" | "blockquote" | "code_block" | "thematic_break" | "table"
要素の種類。
textstring
要素の本文(table 以外)。
levelinteger
heading の見出しレベル。
rowsinteger
table の行数。
colsinteger
table の列数。
cells[{ row, col, header, text }]
table のセル配列。
data.cellsmap<path, Cell>
パスをキーにしたフラットな座標・検証マップ — elements[3] が要素、elements[2].cells[1] が表のセル。review.flagged[].path と同じ文法なので flagged からそのまま引けます。includeElements: false のときは付きません。
box{ xmin, ymin, xmax, ymax }
軸平行の矩形。0〜1000 正規化です(data.image でピクセルに戻せます)。
quad[{ x, y } × 4]
傾いたスキャンに追従する 4 点。box と常に両方付きます。
verifiedboolean | null
その座標が指す OCR 原文と値が正規化後に一致したか(2 つの独立エンジンの合意)。false はモデルが文字を変えた可能性。null は検証対象外(表要素そのもの — セル各々は検証されます)。
review{ reason, reasons } | null
null なら通過、値が入っていれば人の確認を推奨。reason: type_mismatch | out_of_range | pattern_mismatch | nobox | text_mismatch | crop_mismatch | low_ratio | weak_source | low_ocr_confidence | ambiguous_occurrence | overwide_box | missing。前の 3 つは呼び出し側が宣言したルール違反なので、エンジンの推定より上位にランクされます。reason は常にその 1 位ひとつ、reasons は破られたルール全部の配列で、長さ 1 でも必ず入っています(reasons[0] は必ず reason と同じ)。
evidenceobject
判定の生データ — source(座標の出どころ: token_id / char_matcher_fallback / unclaimed_tokens)/ match_ratio(文字照合の一致率)/ ocr_confidence(一致グリフに対する OCR 自身の信頼度の最小値、無ければキー無し)/ crop_verified(切り出し再読の結果、実行時のみ)。
data.reviewobject
文書 1 枚分の検証サマリー。要素ごとの判定は cells 側、ここは集計と要確認リストです。
unit"element"
集計単位。
totalinteger
セル単位の総数(表はセル各々を数えます)。
boxedinteger
座標が付いたセルの数。
verifiedinteger
verified: true のセルの数。
flagged[{ path, reason, reasons }]
要確認リスト。件数はこの配列の長さそのもの(別カウンタはありません)。path は cells のキーと同じ文法なのでそのまま引けます。reason は順位 1 位ひとつ、reasons は破られたルール全部(長さ 1 でも必ず入ります)。
by_reasonobject
理由別の内訳(例: { "pattern_mismatch": 1, "text_mismatch": 1 })。1 つのセルが宣言したルールとエンジンの疑いの両方に触れることがあるため、reasons に載った理由を すべて 数えます。したがって合計は flagged の件数以上になります(検討の 件数 は flagged.length のままです)。
coverageobject
recovered_blocks / vision_tokens / tokens_claimed / token_coverage — ページをどれだけ拾えたか。
data.image{ width, height }
元画像のピクセルサイズ。0〜1000 の正規化座標をピクセルに戻すのに使います(pixel_x = box.xmin / 1000 × width)。
リクエスト
1
2
3
4
5
6
7
curl -X POST https://api.space-ocr.com/ocr/markdown \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "https://example.com/report.jpg",
    "imageType": "url"
  }'
レスポンス
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
  "status": "success",
  "data": {
    "values": {
      "markdown": "# 四半期レポート\n\n売上は前年同期比で増加した。\n\n| 項目 | 金額 |\n| --- | --- |\n| 売上 | 12,000 |",
      "elements": [
        { "type": "heading", "level": 1, "text": "四半期レポート" },
        { "type": "paragraph", "text": "売上は前年同期比で増加した。" },
        { "type": "table", "rows": 2, "cols": 2, "cells": [
          { "row": 0, "col": 0, "header": true,  "text": "項目" },
          { "row": 0, "col": 1, "header": true,  "text": "金額" },
          { "row": 1, "col": 0, "header": false, "text": "売上" },
          { "row": 1, "col": 1, "header": false, "text": "12,000" }
        ] }
      ]
    },
    "cells": {
      "elements[0]": { "box": { "xmin": 60, "ymin": 48, "xmax": 520, "ymax": 92 },
                       "quad": [{"x":60,"y":48},{"x":520,"y":48},{"x":520,"y":92},{"x":60,"y":92}],
                       "verified": true, "review": null,
                       "evidence": { "source": "token_id", "ocr_confidence": 0.98 } },
      "elements[1]": { "box": { "xmin": 60, "ymin": 120, "xmax": 900, "ymax": 160 },
                       "quad": [{"x":60,"y":120},{"x":900,"y":120},{"x":900,"y":160},{"x":60,"y":160}],
                       "verified": true, "review": null,
                       "evidence": { "source": "token_id" } },
      "elements[2]": { "box": { "xmin": 60, "ymin": 200, "xmax": 640, "ymax": 320 },
                       "quad": [{"x":60,"y":200},{"x":640,"y":200},{"x":640,"y":320},{"x":60,"y":320}],
                       "verified": null, "review": null, "evidence": {} },
      "elements[2].cells[0]": { "box": { "xmin": 60,  "ymin": 200, "xmax": 350, "ymax": 260 },
                                "quad": [{"x":60,"y":200},{"x":350,"y":200},{"x":350,"y":260},{"x":60,"y":260}],
                                "verified": true, "review": null, "evidence": { "source": "token_id" } },
      "elements[2].cells[1]": { "box": { "xmin": 350, "ymin": 200, "xmax": 640, "ymax": 260 },
                                "quad": [{"x":350,"y":200},{"x":640,"y":200},{"x":640,"y":260},{"x":350,"y":260}],
                                "verified": false,
                                "review": { "reason": "text_mismatch" },
                                "evidence": { "source": "token_id", "ocr_confidence": 0.71 } },
      "elements[2].cells[2]": { "box": { "xmin": 60,  "ymin": 260, "xmax": 350, "ymax": 320 },
                                "quad": [{"x":60,"y":260},{"x":350,"y":260},{"x":350,"y":320},{"x":60,"y":320}],
                                "verified": true, "review": null, "evidence": { "source": "token_id" } },
      "elements[2].cells[3]": { "box": { "xmin": 350, "ymin": 260, "xmax": 640, "ymax": 320 },
                                "quad": [{"x":350,"y":260},{"x":640,"y":260},{"x":640,"y":320},{"x":350,"y":320}],
                                "verified": true, "review": null, "evidence": { "source": "token_id" } }
    },
    "review": {
      "unit": "element",
      "total": 6,
      "boxed": 6,
      "verified": 5,
      "flagged": [{ "path": "elements[2].cells[1]", "reason": "text_mismatch" }],
      "by_reason": { "text_mismatch": 1 },
      "coverage": { "recovered_blocks": 0, "vision_tokens": 40, "tokens_claimed": 40, "token_coverage": 1.0 }
    },
    "image": { "width": 1654, "height": 2339 }
  }
}
POST/ocr/textBearer¥10

プレーンテキスト OCR

スキーマも Markdown 文法もなしに、文書の文字だけを全部返します。モデルが画像を見て本当の読み順にブロックを並べ替えるので、多段組みや傾いたスキャンでも文が入り混じりません。

ボディパラメータ

imagestringrequired
Base64 文字列または画像 URL。base64 で JSON ボディが 2MB を超える場合は URL 指定か /upload をご利用ください。
imageType"base64" | "url"required
image の型を明示。旧名 image_type も後方互換で動作(非推奨)。
useLlmbooleanoptional
既定 true — 読み順の並べ替えと折り返し行の再結合を行います。false にすると Vision のみの転写(即時・LLM 費用ゼロ、ただし raw OCR 順)。
includeBlocksbooleanoptional
true で values.blocks(内容)と cells(ブロックごとの box / quad / verified / review)も返します。既定 false。
promptstringoptional
転写プロンプトの差し替え(任意)。

レスポンスフィールド

status"success"
成功時は常に "success"。エラーは HTTP 4xx/5xx と共通エラー envelope(Errors 参照)で返り、このボディにはなりません。
data.values.textstring
全文。ブロックを読み順に結合した文字列です。
data.values.blocks[{ text }]
内容だけのブロック配列(includeBlocks: true のとき)。座標と検証フラグは cells 側です。どのブロックも請求しなかった OCR トークンは回収ブロック(evidence.source: unclaimed_tokens)として末尾に付き、落ちた段落が静かに消えません。
data.cellsmap<path, Cell>
パスをキーにしたフラットな座標・検証マップ(blocks[7])。review.flagged[].path と同じ文法なので flagged からそのまま引けます。includeBlocks: true のとき付きます。
box{ xmin, ymin, xmax, ymax }
軸平行の矩形。0〜1000 正規化です(data.image でピクセルに戻せます)。
quad[{ x, y } × 4]
傾いたスキャンに追従する 4 点。box と常に両方付きます。
verifiedboolean | null
その座標が指す OCR 原文と値が正規化後に一致したか(2 つの独立エンジンの合意)。false はモデルが文字を変えた可能性。null は検証対象外(幾何のみの項目)。
review{ reason, reasons } | null
null なら通過、値が入っていれば人の確認を推奨。reason: type_mismatch | out_of_range | pattern_mismatch | nobox | text_mismatch | crop_mismatch | low_ratio | weak_source | low_ocr_confidence | ambiguous_occurrence | overwide_box | missing。前の 3 つは呼び出し側が宣言したルール違反なので、エンジンの推定より上位にランクされます。reason は常にその 1 位ひとつ、reasons は破られたルール全部の配列で、長さ 1 でも必ず入っています(reasons[0] は必ず reason と同じ)。
evidenceobject
判定の生データ — source(座標の出どころ: token_id / char_matcher_fallback / unclaimed_tokens / vision_paragraph)/ match_ratio(文字照合の一致率)/ ocr_confidence(一致グリフに対する OCR 自身の信頼度の最小値、無ければキー無し)/ crop_verified(切り出し再読の結果、実行時のみ)。
data.reviewobject
文書 1 枚分の検証サマリー。Vision 専用経路(useLlm: false)でも常に付きます。
unit"block"
集計単位。
totalinteger
ブロックの総数。
boxedinteger
座標が付いたセルの数。
verifiedinteger
verified: true のセルの数。
flagged[{ path, reason, reasons }]
要確認リスト。件数はこの配列の長さそのもの(別カウンタはありません)。path は cells のキーと同じ文法なのでそのまま引けます。reason は順位 1 位ひとつ、reasons は破られたルール全部(長さ 1 でも必ず入ります)。
by_reasonobject
理由別の内訳(例: { "pattern_mismatch": 1, "text_mismatch": 1 })。1 つのセルが宣言したルールとエンジンの疑いの両方に触れることがあるため、reasons に載った理由を すべて 数えます。したがって合計は flagged の件数以上になります(検討の 件数 は flagged.length のままです)。
coverageobject
recovered_blocks / vision_tokens / tokens_claimed / token_coverage — ページをどれだけ拾えたか(useLlm: true の LLM 経路のみ)。
data.image{ width, height }
元画像のピクセルサイズ。0〜1000 の正規化座標をピクセルに戻すのに使います(pixel_x = box.xmin / 1000 × width)。
data.source"llm" | "vision"
"llm" は読み順を並べ替えた経路、"vision" は LLM 失敗時の自動フォールバック(warning に理由が入ります)。
リクエスト
1
2
3
4
5
curl -X POST https://api.space-ocr.com/ocr/text   -H "Authorization: Bearer YOUR_API_KEY"   -H "Content-Type: application/json"   -d '{
    "image": "https://example.com/note.jpg",
    "imageType": "url",
    "includeBlocks": true
  }'
レスポンス
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
26
27
28
{
  "status": "success",
  "data": {
    "values": {
      "text": "株式会社サクラ商事\n請求書\n合計 1,451円",
      "blocks": [
        { "text": "株式会社サクラ商事" }
      ]
    },
    "cells": {
      "blocks[0]": { "box": { "xmin": 60, "ymin": 48, "xmax": 470, "ymax": 92 },
                     "quad": [{"x":60,"y":48},{"x":470,"y":48},{"x":470,"y":92},{"x":60,"y":92}],
                     "verified": true, "review": null,
                     "evidence": { "source": "token_id", "ocr_confidence": 0.98 } }
    },
    "review": {
      "unit": "block",
      "total": 12,
      "boxed": 12,
      "verified": 11,
      "flagged": [{ "path": "blocks[7]", "reason": "text_mismatch" }],
      "by_reason": { "text_mismatch": 1 },
      "coverage": { "recovered_blocks": 0, "vision_tokens": 96, "tokens_claimed": 96, "token_coverage": 1.0 }
    },
    "image": { "width": 1654, "height": 2339 },
    "source": "llm"
  }
}
GET/spaceBearer

ツリー閲覧

MySpace のフォルダ/シート/メモを一覧します。path と depth でスコープを絞れます。

クエリパラメータ

pathstringoptional
"/" 区切り。フォルダは名前、シートは名前 (親内で一意) または /create が返した uniqueKey。既定は "/"。
depthinteger 1..10optional
再帰深さ。既定 1。

レスポンスフィールド

pathstring
リクエストで指定した起点パス。
depthinteger
適用された再帰深さ。
itemsarray<Item>
配下のアイテム一覧。
pathstring
アイテムのフルパス。/view・/upload・/remove にそのまま渡せます。
namestring
表示名。
type"folder" | "sheet" | "doc" | "memo" | "img"
アイテムの種類。doc はドキュメント束(.md / .txt)です。
uniqueKeystring
名前と無関係な安定キー(folder 以外)。パスのセグメントとしても使えます。
createdAtinteger (epoch ms)
作成時刻。
extensionsobject | null
付加メタデータ(無ければ null、folder 以外)。
リクエスト
1
2
curl https://api.space-ocr.com/space?path=/&depth=1 \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
1
2
3
4
5
6
7
8
9
10
11
{
  "path": "/",
  "depth": 1,
  "items": [
    { "path": "/invoices", "name": "invoices", "type": "folder", "createdAt": 1716700000000 },
    { "path": "/memo_2024", "name": "メモ", "type": "memo",
      "uniqueKey": "...", "createdAt": 1716700000000, "extensions": null }
  ]
}

// type: folder | sheet | doc | memo | img。folder 以外は uniqueKey / extensions を持ちます。
GET/viewBearer

中身を見る

フォルダ/シート/ドキュメント束/メモ/画像、すべての種類の中身を返します。ドキュメント束は pages 配列、シートは rows 配列です。**クエリ(where / sort / select / limit / offset / boxes)はシート専用** — 他の種類では無視され、全件がそのまま返ります。 シートの行は **アップロード時刻(createdAt)の昇順**で返ります。これは POST /edit・POST /remove の `row: N` と同じ順番なので、レスポンスの N 番目の行がそのまま `row: N` です。

クエリパラメータ

pathstringrequired
対象パス。
wherestring | string[]optional
【シート専用】行フィルタ。例: total>=40000 / vendor~ABC。繰り返し可(AND)。演算子: = != > >= < <= ~(~ は部分一致)。シートのカラム + name / ocrStatus / createdAt を対象。値はページに印字されたままの文字列で保存されるため、比較の前に数値化を試みます: 全角を半角に正規化し、通貨記号(¥ ¥ $ ₩ € £ 円 元 원 など)・桁区切り・会計式のマイナス表記((1,200) / △1,200 / 末尾ハイフン)を取り除いて、純粋な十進数になれば数値比較。ならなければ文字列比較です(両辺が数値のときだけ数値比較)。日付・電話番号・12% などは数値扱いされません。
sortstring | string[]optional
【シート専用】並べ替え。例: total:desc / -invoice_date。繰り返しで tie-break。where と同じ規則で数値化を試み、両方が数値なら数値順、そうでなければ文字列順です。
selectstringoptional
【シート専用】カンマ区切りの返却カラム名。例: vendor,total。
limitinteger 1..500optional
【シート専用】返却行数の上限。ドキュメント束の pages には効きません。
offsetintegeroptional
【シート専用】ページング用スキップ数。レスポンスの nextOffset と組み合わせて使用。
boxes"0" | "1" | "true" | "false"optional
【シート専用】0 / false で行の cells(座標・検証マップ)を省略した軽量レスポンス。values / review / image は残ります。select= は values のキーと、先頭セグメントが一致する cells のパスに適用されます。

レスポンスフィールド

type"folder" | "sheet" | "doc" | "memo" | "img"
対象の種類。以下のフィールドは type によって付くものが変わります。
pathstring
対象パス。
namestring
表示名(folder 以外)。
columnsarray<ColumnSpec>
【シート】このシートのカラムスキーマ(POST /create と同じ形)。
totalinteger
【シート】シート全体の行数 /【doc】ページ数。
matchedinteger
【シート】where を通過した行数。
offset / limit / nextOffsetinteger | null
【シート】ページング状態。nextOffset を次の offset に渡します(終端は null)。
rowsarray<Row>
【シート】行の配列。createdAt 昇順 — POST /edit・POST /remove の row: N と同じ順番です。
rowKeystring
行の安定キー。POST /edit の row にそのまま渡せます。
namestring
元ファイル名。
createdAtinteger (epoch ms)
アップロード時刻 — 既定の行順の根拠。
imageUrlstring | null
元画像の URL。
ocrStatus"pending" | "done" | "failed"
OCR 状態。
valuesobject | null
抽出された値(カラム名がキー)。POST /ocr/fields の data.values と同じ純粋なユーザーデータです。OCR 前は null。
cellsmap<path, Cell>
POST /ocr/fields と同じ座標・検証マップ。boxes=0 なら省略されます。
reviewobject
POST /ocr/fields と同じ検証サマリー(unit: "field")。
image{ width, height }
元画像のピクセルサイズ。
mode"markdown" | "text"
【doc】束の変換モード。
pagesarray<Page>
【doc】ページの配列(アップロード順)。各ページは values(mode に応じて { markdown, elements } または { text, blocks })+ cells + review + image — POST /ocr/markdown・/ocr/text と同じ v2 構造です。OCR 前のページは values: null のみ。
pageKeystring
ページの安定キー。
namestring
元ファイル名。
imageUrlstring | null
元画像の URL。
ocrStatus"pending" | "done" | "failed"
OCR 状態。
valuesobject | null
mode=markdown なら { markdown, elements }、mode=text なら { text, blocks }。
cellsmap<path, Cell>
POST /ocr/markdown・/ocr/text と同じ座標・検証マップ(elements[3] / blocks[7] …)。
reviewobject
同エンドポイントと同じ検証サマリー(unit: "element" / "block")。
image{ width, height }
元画像のピクセルサイズ。
itemsarray
【folder】子アイテムの一覧({ path, name, type, uniqueKey? })。
textstring
【memo】メモの本文。
imageUrl / ocrStatusstring | null
【img】元画像の URL と OCR 状態。
リクエスト
1
2
3
4
5
6
7
8
# 複数 where (AND) + ソート + 投影 + ページネーション
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"
レスポンス
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// type=sheet
{
  "type": "sheet",
  "path": "/invoices/sheet1",
  "name": "sheet1",
  "columns": [ /* ... */ ],
  "total": 128,        // シート全体の行数
  "matched": 12,       // where 通過行数
  "offset": 0,
  "limit": 20,
  "nextOffset": 20,    // 次ページ用 / 終端は null
  "rows": [
    {
      "rowKey": "img_abc",
      "name": "invoice_2025_04_10.jpg",
      "createdAt": 1744243200000,   // アップロード時刻 / 既定の行順
      "imageUrl": "https://...",
      "ocrStatus": "done",
      "values": { "vendor": "ABC Corp", "total": "12000", "invoice_date": "2025-04-10" },
      "cells": { /* POST /ocr/fields と同じ box / quad / verified / review — boxes=0 で省略 */ },
      "review": { "unit": "field" /* ... */ },
      "image": { "width": 1654, "height": 2339 }
    }
  ]
}

// type=folder
{
  "type": "folder",
  "path": "/invoices",
  "items": [
    { "path": "/invoices/2024", "name": "2024", "type": "folder" },
    { "path": "/invoices/Kvho45OXMKw…", "name": "sheet1", "type": "sheet", "uniqueKey": "Kvho45OXMKw…" }
  ]
}

// type=doc — ページ全件がそのまま返ります(where / sort / limit / offset / select / boxes は無視)。
// type=doc (mode=markdown)
{
  "type": "doc",
  "path": "/reports/quarterly",
  "name": "quarterly",
  "mode": "markdown",
  "total": 2,
  "pages": [
    {
      "pageKey": "img_abc",
      "name": "page1.jpg",
      "imageUrl": "https://...",
      "ocrStatus": "done",
      "values": { "markdown": "# ...", "elements": [ /* ... */ ] },
      "cells": { /* POST /ocr/markdown と同じ box / quad / verified / review */ },
      "review": { "unit": "element" /* ... */ },
      "image": { "width": 1654, "height": 2339 }
    }
  ]
}

// type=doc (mode=text)
{
  "type": "doc",
  "path": "/notes/scan",
  "name": "scan",
  "mode": "text",
  "total": 1,
  "pages": [
    {
      "pageKey": "img_def",
      "name": "note.jpg",
      "imageUrl": "https://...",
      "ocrStatus": "done",
      "values": { "text": "...", "blocks": [ /* ... */ ] },
      "cells": { /* POST /ocr/text と同じ box / quad / verified / review */ },
      "review": { "unit": "block" /* ... */ },
      "image": { "width": 1654, "height": 2339 }
    }
  ]
}

// type=memo
{ "type": "memo", "path": "...", "name": "todo", "text": "..." }

// type=img
{ "type": "img", "path": "...", "name": "...", "imageUrl": "...", "ocrStatus": "done" }
POST/createBearer

作成

親フォルダの下に folder / sheet / doc / memo を作成します。シートは OCR スキーマ (columns) と prompt を、doc(ドキュメント束)は mode を持ちます。

ボディパラメータ

pathstringrequired
親フォルダの path。
type"folder" | "sheet" | "doc" | "memo"required
作成するアイテムの種類。doc はドキュメント束(.md / .txt)です。
namestringrequired
表示名。
textstringoptional
memo の本文(type=memo の場合のみ)。
columnsarray<ColumnSpec>optional
シートの OCR スキーマ(type=sheet 用)。以後このシートへのアップロードは、毎回このスキーマで抽出されます。
idstringoptional
列の安定 ID。省略すると自動生成されます。
namestringrequired
列名。抽出された値はこの名前で行に入ります。
typestringrequired
値の形。単一の値は string、明細行のような繰り返しは array にして children で行の中身を宣言します。
descriptionstringoptional
その値がどこにあるかのヒント(例: 「合計の右」)。
childrenarray<ColumnSpec>optional
type が array の列の子フィールド。明細行の各セルになります。
requiredbooleanoptional
true の列は、その値が空で返るか読み取れなかったときに、その行の review.flagged に reason "missing" として現れます — アップロードのたびに適用され、抽出の動きは変わりません。必ず印字される値だけに付けてください。
labelstring | string[]optional
値の横に印字されているラベル(例: "合計")。同じ値がページに複数回印字されているとき、座標をそのラベルの隣の出現にアンカーします(v64)。string 列専用・ラベルがページに正確に 1 回のときだけ働き、モデルには渡りません — 抽出テキストは変わらず座標だけが変わります。
promptstringoptional
シートの抽出指示プロンプト(任意)。
mode"markdown" | "text"optional
doc 束の変換モード(type=doc 用、既定 markdown)。markdown はレイアウト保持、text は原文そのまま。

レスポンスフィールド

pathstring
作成されたアイテムのパス。sheet / doc / memo は uniqueKey がパスに組み込まれて返ります。
type"folder" | "sheet" | "doc" | "memo"
作成された種類。
uniqueKeystring
名前と無関係な安定キー(folder 以外)。以後 /view・/upload の path セグメントとしてそのまま使えます。
リクエスト
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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", "required": true },
      { "id": "date",   "name": "date",   "type": "string" }
    ],
    "prompt": "請求書から金額と日付を抽出"
  }'
レスポンス
1
2
3
4
5
6
7
8
// HTTP 201 Created
// sheet/memo は uniqueKey が path に組み込まれて返却される
{ "path": "/invoices/Kvho45OXMKw…", "type": "sheet", "uniqueKey": "Kvho45OXMKw…" }

// 作成と同時に item.created Webhook が発火します。Idempotency-Key ヘッダーを
// 付けると 24h 以内の再送は同じレスポンスをそのまま返します。
// required: true の列(上の amount)は、以後のアップロードで値が空だと
// その行の review.flagged に reason "missing" として現れます。
POST/uploadBearer¥10 × N

画像アップロード

シートまたはドキュメント束に画像を 1 枚以上アップロードします。multipart/form-data。既定は非同期 (jobs を返却 → webhook で完了通知)。

フォームフィールド (multipart)

pathstringrequired
アップロード先のシート/ドキュメント束の path。束のモード(markdown / text)で変換方法が決まります。
filesfile (repeatable)required
画像ファイル。複数枚は files を繰り返し送信。1 リクエスト最大 20 ファイル / 1 ファイル最大 20MB。
waitbooleanoptional
true で同期実行(1 枚あたり最大 30s 待機、超過分は status:"pending" で返却)。1 枚アップロード用。

レスポンスフィールド

pathstring
アップロード先のパス。
jobsarray<Job>
非同期(既定)のとき。1 ファイル 1 ジョブで、完了は ocr.completed Webhook か GET /jobs/{jobId} のポーリングで受け取ります。
uniqueKeystring
作成された行/ページの安定キー。
originalNamestring
元ファイル名。
jobIdstring
GET /jobs/{jobId} に渡すジョブ ID。
status"pending"
受付時点では常に pending。
resultsarray<Result>
wait=true のとき jobs の代わりに返ります。Job の属性に加えて、終わった分は mode と result を持ちます — result は GET /jobs と同じ v2 構造({ values, cells, review, image })。30s 以内に終わらなかった分は status: "pending" のままなので /jobs でポーリングしてください。
リクエスト
1
2
3
4
5
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"
レスポンス
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// async (default)
{
  "path": "/invoices/sheet1",
  "jobs": [
    { "uniqueKey": "...", "originalName": "invoice1.jpg", "jobId": "job_...", "status": "pending" },
    { "uniqueKey": "...", "originalName": "invoice2.jpg", "jobId": "job_...", "status": "pending" }
  ]
}

// ドキュメント束にアップロードした場合 — jobs の形は同じで、束の mode で変換方法が決まります
{
  "path": "/reports/quarterly",
  "jobs": [
    { "uniqueKey": "...", "originalName": "page1.jpg", "jobId": "job_...", "status": "pending" }
  ]
}

// wait=true — jobs ではなく results が返ります
{
  "path": "/invoices/sheet1",
  "results": [
    { "uniqueKey": "...", "originalName": "invoice1.jpg", "jobId": "job_...",
      "status": "done", "mode": "sheet",
      "result": { /* { values, cells, review, image } — GET /jobs と同じ v2 構造 */ } },
    { "uniqueKey": "...", "originalName": "invoice2.jpg", "jobId": "job_...",
      "status": "pending" }   // 30s 以内に終わらなかった分は /jobs でポーリング
  ]
}

// 402 — 残高不足
{
  "error": { "code": "insufficient_balance", "message": "...", "requestId": "req_..." },
  "details": {
    "requested": 5,
    "processable": 3,
    "breakdown": {
      "freeRemaining": 0,
      "flatfeeRemaining": 3,
      "balance": 0,
      "perCallCost": 1,
      "currency": "scans"
    }
  }
}
POST/editBearer

シート行/メモを編集

シートのセル値、またはメモの本文を上書きします。anyOf: (path, row, column, value) または (path, text)。**編集できるのはシートとメモだけ** — ドキュメント束(.md / .txt)は OCR 判読結果そのものなので 400 で拒否されます。

ボディパラメータ

pathstringrequired
対象シート/メモの path。
rowinteger | stringoptional
整数(インデックス、負数は末尾起算)または rowKey(文字列)。シート編集時に必須。
columninteger | stringoptional
整数(カラムインデックス)または カラム名/id。シート編集時に必須。
valueanyoptional
上書きする値。シート編集時に必須。
textstringoptional
メモ編集時の新しい本文。メモ編集時に必須。

レスポンスフィールド

okboolean
true なら反映済みです。
patchedobject
実際に適用された変更。シート編集なら { row, column, value }。
リクエスト
1
2
3
4
5
6
7
8
9
10
11
# 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":"新しい本文"}'
レスポンス
1
{ "ok": true, "patched": { "row": "img_abc", "column": "amount", "value": "12000" } }
POST/removeBearer

削除(cascade)

フォルダ/シート/メモ/画像を削除します。フォルダ削除は配下メタデータ・flat エントリ・Storage を全てカスケード。

ボディパラメータ

pathstringrequired
削除対象の path。

レスポンスフィールド

okboolean
true なら削除完了です(フォルダは配下までカスケード済み)。
リクエスト
1
2
3
4
curl -X POST https://api.space-ocr.com/remove \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"path":"/invoices/2024"}'
レスポンス
1
{ "ok": true }
GET/jobs/{jobId}Bearer

OCR ジョブのポーリング

POST /upload(非同期)が返した jobId の状態を確認します。webhook を使わない場合に使用。

パスパラメータ

jobIdstringrequired
/upload 応答内の jobs[].jobId。

レスポンスフィールド

jobIdstring
ジョブ ID。
status"pending" | "done" | "failed"
処理状態。failed は自動返金済みです。
uniqueKeystring
作成された行/ページの安定キー。
pathstring
アイテムのパス。
sheetRef / docRefstring | null
アップロード先がシートなら sheetRef、ドキュメント束なら docRef に uniqueKey が入ります(もう一方は null)。
mode"sheet" | "markdown" | "text"
アップロード先で決まる出力形式。
resultobject
status が done のときのみ。{ values, cells, review, image } — mode に関わらず OCR エンドポイント(/ocr/fields・/ocr/markdown・/ocr/text)と同じ v2 構造で、values の中身だけが mode に従います。ocr.completed Webhook の data.result も同じ形です。
リクエスト
1
2
curl https://api.space-ocr.com/jobs/job_xxx \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "jobId": "job_xxx",
  "status": "done",
  "uniqueKey": "img_abc",
  "path": "/invoices/sheet1/img_abc",
  "sheetRef": "Kvho45OXMKw…",
  "docRef": null,
  "mode": "sheet",
  "result": {
    "values": { "amount": "12000", "date": "2025-04-10" },
    "cells": { /* POST /ocr/fields と同じ box / quad / verified / review */ },
    "review": { "unit": "field" /* ... */ },
    "image": { "width": 1654, "height": 2339 }
  }
}
GET/amountBearer

残高・無料枠

現在の残高と利用可能な無料枠を返します。

レスポンスフィールド

freeobject
毎月の無料枠。
used / limit / remaininginteger
今サイクルの使用量・上限・残り。
cycleStartinteger (epoch ms)
サイクル開始時刻。
cycleEndinteger (epoch ms)
サイクル終了時刻(ここでリセット)。
flatfeeobject
定額プラン。未加入なら enabled: false で、他の属性は付きません。
enabledboolean
加入中かどうか。
used / limit / remaininginteger
今サイクルの使用量・上限・残り。
cycleStart / cycleEndinteger (epoch ms)
サイクルの期間。
nextBillingAtinteger (epoch ms)
次回請求時刻。
interval"monthly"
請求間隔。
renewalboolean
自動更新かどうか。
planstring
プラン名(例: "pro")。
balanceinteger
チャージ済み残高。単位は通貨ではなくスキャン数です。
currency"scans"
残高の単位。
perCallCostinteger
1 コールあたりの消費スキャン数(1)。
リクエスト
1
2
curl https://api.space-ocr.com/amount \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
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
26
27
{
  "free": {                    // 毎月の無料枠
    "used": 12,
    "limit": 100,
    "remaining": 88,
    "cycleStart": 1716700000000,
    "cycleEnd": 1719378400000
  },
  "flatfee": {                 // 定額プラン(未加入なら enabled:false)
    "enabled": true,
    "used": 340,
    "limit": 3000,
    "remaining": 2660,
    "cycleStart": 1716700000000,
    "cycleEnd": 1719378400000,
    "nextBillingAt": 1719378400000,
    "interval": "monthly",
    "renewal": true,
    "plan": "pro"
  },
  "balance": 1240,             // チャージ済み残高(スキャン数)
  "currency": "scans",         // 残高の単位は通貨ではなくスキャン数
  "perCallCost": 1             // 1 スキャン = 1 コール
}

// 処理可能枚数 = free.remaining + (flatfee.enabled ? flatfee.remaining : 0) + balance。
// この順で消費されます(無料枠 → 定額 → 残高)。
GET/health

ヘルスチェック

認証不要のヘルスチェック。

レスポンスフィールド

status"ok"
サービスが応答できていれば ok。
versionstring
API バージョン。
timeinteger (epoch ms)
サーバー時刻。
リクエスト
1
curl https://api.space-ocr.com/health
レスポンス
1
{ "status": "ok", "version": "v1", "time": 1716700000000 }

概要

スペース全体に 1 つの Webhook URL を登録すると、すべてのイベントが HMAC 署名付きで配信されます。設定は Developer → Webhooks か、後述の Webhook 管理エンドポイントから行います。

イベント

全イベントは同じ envelope(event / deliveryId / occurredAt / apiVersion / data)を持ちます。

item.createdeventoptional
/create で folder / sheet / memo が作成
upload.receivedeventoptional
/upload で画像が受信
ocr.completedeventoptional
OCR 完了。data.mode が出力形式(sheet / markdown / text)、data.result に結果
ocr.failedeventoptional
OCR 失敗(自動返金済み)
webhook.testeventoptional
/webhook/test による手動テスト

ペイロード例 — ocr.completed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "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",
    "docRef": null,
    "mode": "sheet",
    "result": {
      "values": { "amount": "12000", "date": "2025-04-10" },
      "cells": { /* box / quad / verified / review */ },
      "review": { "unit": "field" /* ... */ },
      "image": { "width": 1654, "height": 2339 }
    }
  }
}

mode はアップロード先で決まります — シートなら "sheet"、ドキュメント束なら "markdown" / "text"。result は GET /jobs と同じ { values, cells, review, image }(v2)で、values の中身だけが mode に従います(sheet: フィールド値 / markdown: { markdown, elements } / text: { text, blocks })。ドキュメント束の場合は sheetRef が null になり、docRef に束の uniqueKey が入ります。

配信ヘッダー

受信エンドポイントには下記ヘッダーが付きます。署名検証で必要なものは Signature / Timestamp。

1
2
3
4
5
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/json

署名検証

X-Spaceocr-Signature は t=<unix_ms>,v1=<hex> 形式です。canonical 文字列は `${t}.${rawBody}`、アルゴリズムは HMAC-SHA256。リプレイ攻撃を防ぐため timestamp が 5 分以上ずれている場合は拒否してください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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"),
  );
}

再送ポリシー

2xx 以外は exponential backoff (1m → 5m → 30m → 2h) で最大 5 回試行。5xx / 408 / 429 / timeout のみ retry 対象、その他 4xx は即 dead。配信ログは 30 日保存。

手動再送は POST /webhooks/deliveries/{deliveryId}/redeliver で。詳細は配信履歴セクション参照。
GET/webhookBearer

現在の Webhook 設定

スペース全体に登録されている webhook URL と状態を返します。

レスポンスフィールド

configuredboolean
登録があるかどうか。false のときは他のフィールドは付きません。
urlstring
配信先 URL。
activeboolean
配信が有効かどうか。
secretMaskedstring
署名鍵の末尾 4 桁だけを残したマスク表示。平文は登録・回転のその一度しか返りません。
createdAt / updatedAtinteger (epoch ms)
登録・更新時刻。
リクエスト
1
2
curl https://api.space-ocr.com/webhook \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
1
2
3
4
5
6
7
8
9
10
11
{
  "configured": true,
  "url": "https://example.com/hooks/space-ocr",
  "active": true,
  "secretMasked": "••••a1b2",
  "createdAt": 1716700000000,
  "updatedAt": 1716700000000
}

// 未設定のとき
{ "configured": false }
PUT/webhookBearer

Webhook 設定の作成・更新

スペース全体の webhook URL を登録または更新します。rotateSecret で署名鍵を再発行できます。

ボディパラメータ

urlstring (uri)required
配信先 URL。
activebooleanoptional
配信を有効化(既定 true)。
rotateSecretbooleanoptional
true で署名鍵を再発行し、新しい secret を返却。初回登録時は指定がなくても secret が発行され、そのときも平文で返ります。

レスポンスフィールド

configured / url / active / secretMasked / createdAt / updatedAt
GET /webhook と同じフィールドです。
secretstring
新規発行・rotateSecret のときだけ、この一度だけ平文で返ります。後から再取得はできないので、すぐ保管してください。
リクエスト
1
2
3
4
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}'
レスポンス
1
2
3
4
5
6
7
8
9
{
  "configured": true,
  "url": "https://example.com/hooks/space-ocr",
  "active": true,
  "secretMasked": "••••a1b2",
  "secret": "kJ8s…",   // 新規発行・回転時のみ、この一度だけ平文
  "createdAt": 1716700000000,
  "updatedAt": 1716700000000
}
DELETE/webhookBearer

Webhook 設定の削除

登録済みの webhook を削除します。以後イベントは配信されません。

レスポンスフィールド

okboolean
true なら削除済み。以後イベントは配信されません。
リクエスト
1
2
curl -X DELETE https://api.space-ocr.com/webhook \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
1
{ "ok": true }
POST/webhook/testBearer

テストイベントを送信

configured URL に webhook.test イベントを即時送信します。受信側の実装確認用。

レスポンスフィールド

okboolean
true なら送信キューに載りました。
deliveryIdstring
発行された配信 ID。/webhooks/deliveries/{deliveryId} で結果を追跡できます。
リクエスト
1
2
curl -X POST https://api.space-ocr.com/webhook/test \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
1
{ "ok": true, "deliveryId": "dlv_xxx" }
GET/webhooks/deliveriesBearer

最近の配信履歴

最新の webhook 配信ログを返します。debug 用。

クエリパラメータ

status"pending" | "success" | "dead"optional
配信状態でフィルタします。
limitinteger 1..200optional
返却件数の上限。既定 50。

レスポンスフィールド

itemsarray<Delivery>
新しい順の配信ログ。ログは 30 日保存されます。
deliveryIdstring
配信 ID。
eventstring
イベント名(ocr.completed など)。
urlstring
配信先 URL。
path / uniqueKeystring
対象アイテムのパスとキー(該当イベントのみ)。
status"pending" | "success" | "dead"
pending は再試行待ち、dead は全試行が尽きた状態。
attemptsinteger
試行回数。
lastAttemptobject
最後の試行の詳細 — { at, attemptIndex, responseStatus, error, durationMs, responsePreview }。
occurredAtinteger (epoch ms)
イベント発生時刻。
nextAttemptAtinteger | null
次の再試行予定。無ければ null。
completedAtinteger | null
成功時刻。
リクエスト
1
2
curl https://api.space-ocr.com/webhooks/deliveries \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "items": [
    {
      "deliveryId": "dlv_xxx",
      "event": "ocr.completed",
      "url": "https://example.com/hooks/space-ocr",
      "path": "/invoices/sheet1/img_abc",
      "uniqueKey": "img_abc",
      "status": "success",          // pending | success | dead
      "attempts": 1,                // 試行回数
      "lastAttempt": {
        "at": 1716700000000,
        "attemptIndex": 0,
        "responseStatus": 200,
        "error": null,
        "durationMs": 143,
        "responsePreview": "ok"
      },
      "occurredAt": 1716700000000,
      "nextAttemptAt": null,
      "completedAt": 1716700000143
    }
  ]
}
GET/webhooks/deliveries/{deliveryId}Bearer

配信の詳細

指定配信の完全なペイロードと配信試行履歴を返します。

パスパラメータ

deliveryIdstringrequired
/webhooks/deliveries の deliveryId。

レスポンスフィールド

deliveryIdstring
配信 ID。
eventstring
イベント名。
occurredAtinteger (epoch ms)
イベント発生時刻。
payloadobject
受信側に送られたイベント本文の全体(envelope の data まで含む)。
attempts[{ at, responseStatus, ok }]
試行履歴。
リクエスト
1
2
curl https://api.space-ocr.com/webhooks/deliveries/dlv_xxx \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
1
2
3
4
5
6
7
8
9
{
  "deliveryId": "dlv_xxx",
  "event": "ocr.completed",
  "occurredAt": 1716700000000,
  "payload": { /* full event body */ },
  "attempts": [
    { "at": 1716700000000, "responseStatus": 200, "ok": true }
  ]
}
POST/webhooks/deliveries/{deliveryId}/redeliverBearer

配信の手動再送

失敗した配信を手動で再送します。

パスパラメータ

deliveryIdstringrequired
再送する deliveryId。

レスポンスフィールド

okboolean
true なら再送キューに載りました。
deliveryIdstring
同じ ID をそのまま再利用します(新しい ID は発行されません)。配信ログの status は pending に戻り、attempts に試行が追記されます。
リクエスト
1
2
curl -X POST https://api.space-ocr.com/webhooks/deliveries/dlv_xxx/redeliver \
  -H "Authorization: Bearer YOUR_API_KEY"
レスポンス
1
2
3
4
{ "ok": true, "deliveryId": "dlv_xxx" }

// 同じ deliveryId を再利用します(新しい ID は発行されません)。配信ログの
// status は pending に戻り、attempts に試行が追記されます。

概要

MCP サーバーは、この API をそのまま AI エージェントのツールとして開きます。読み取り 3 種に加えて、フォルダやシートを作り、画像を上げ、溜まった行を条件付きで取り出すところまでエージェントが行えます。中身は同じ REST ルートで、課金も同じです。

接続

インストールは不要です。ヘッダーを設定できるクライアントは API キーをそのままベアラートークンとして送ってください。ヘッダーを設定できない Claude デスクトップ/モバイル/claude.ai では、URL をカスタムコネクタとして追加すると OAuth の同意画面が開き、どの API キーで動かすかを選べます。どちらの場合もキーはそのリクエストのみに使われ、サーバー側には保存されません。

1
2
3
# Claude Code
claude mcp add --transport http space-ocr https://mcp.space-ocr.com/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

Cursor / VS Code / Windsurf (mcp.json)

1
2
3
4
5
6
7
8
{
  "mcpServers": {
    "space-ocr": {
      "url": "https://mcp.space-ocr.com/mcp",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}
上記以外のクライアントでも、標準の Streamable HTTP エンドポイントなので同じ URL とヘッダーで接続できます。画像はサーバー側から取得できる https:// の URL か、base64 / data URI でお送りください。

ツール一覧

読み取り 3 つとワークスペース 8 つ。課金は対応する REST ルートと同じで、読み取りと画像アップロードだけがクレジットを消費します。

ocr_extract1 枚から名前付きフィールドを抽出。fields スキーマを指定するか autoFields で提案させます。1 クレジット
ocr_markdownレイアウトを保った Markdown。要素ごとに座標付き。1 クレジット
ocr_text読み順を復元したプレーンテキスト。ブロックごとに座標付き。1 クレジット
space_listツリーを閲覧 (GET /space)。無料
space_viewアイテムを読む。シートは where / sort / select / limit で問い合わせ (GET /view)。座標は boxes: true のときだけ返ります。無料
space_createフォルダ / シート / ドキュメント束 / メモを作成 (POST /create)。無料
space_uploadシートや束に画像を最大 20 枚アップロード (POST /upload)。1 クレジット/枚
space_job非同期アップロードのジョブを確認 (GET /jobs)。無料
space_editシートのセル値やメモ本文を修正 (POST /edit)。無料
space_balance残りの無料枠・プラン枠・残高 (GET /amount)。無料
space_deleteアイテムを削除 (POST /remove、フォルダは中身ごと)。2 段階です: confirm なしで呼ぶと何も削除せず、消える中身の件数と署名付きトークンだけを返します。ユーザーに見せて同意を得てから、そのトークンを付けて呼び直すと削除されます。ルートは拒否。無料

削除は 2 段階

space_delete を `confirm` なしで呼ぶと、何も削除せずに「消えるもの」だけが返ります: 対象、その下にあるフォルダー/シート/ドキュメント束/メモ/画像の件数、サンプル、そして `confirm` トークン。トークンは呼び出し側の API キーと対象パスに紐づく署名なのでモデル側で作れず、ユーザーに見せる段階を飛ばせません。同意を得たらそのトークンを付けて呼び直します。有効なのは 10〜20 分、ルートパスは常に拒否されます。
削除は元に戻せません。フォルダを消すと中の画像も一緒に消えます。
ツールのほかに、MCP のリソースとプロンプトも公開しています。リソース (space-ocr://guide/schemas · /verification · /queries · /workflows) は、スキーマの組み方・検証フラグの読み方・絞り込みの書き方・一括処理の進め方をまとめたもので、必要になったときだけ読み込まれます。プロンプト (file_documents · review_flagged · ask_documents) は定型の作業手順です。どちらも MCP の任意機能なので、対応はクライアントによります。