ガイド

請求書OCR API/納品書OCRでCSVへ ── 請求書データ抽出APIの実装ガイド

請求書・納品書を手入力やExcel文字化けから解放する開発者向けガイド。POST /ocr/fields に画像を投げると、取引先・日付・合計・明細が構造化データで返り、各値に元画像の座標(bbox)とmatch_ratioが付く。curl・Pythonコード、CSV出力、Webhook、料金まで。

9 分で読了· 2026-06-25

請求書や納品書を、いまだに手で Excel に打ち込んでいませんか。日付、取引先、税抜・税込、そして明細の一行一行 ── 月末になると山積みの紙とにらめっこして、数字を1セルずつ転記する。途中で一桁ずれて、合計が合わなくて、また最初から照合する。あの時間を、なくしたい。

スキャンした PDF をコピーしようとしたら文字が選択できない。OCR にかけたら、明細がぜんぶ1つのセルに潰れて改行も列も失われる。CSV を Excel で開いたら文字化けして品名が読めない。会計ソフトに取り込みたいだけなのに、その手前で毎回つまずく ── これは、書類を扱う現場の「あるある」です。

この記事は、その作業を API 1本 に置き換えるための開発者向けガイドです。POST /ocr/fields に請求書・納品書の画像を投げると、取引先・日付・合計といった項目と、明細の各行が型のついた構造化データで返ってきます。しかも返ってくるすべての値に、元画像のどこから読み取ったかの座標(bbox)が付くので、抽出結果を鵜呑みにせず原本と突き合わせて検証できます。curl と Python のコード付きで、最短経路から本番運用までひと通り見ていきます。

まずは触ってみる ── アップロード不要、10秒で体験

コードを書く前に、実際の出力を見てください。下は本物のレシートを解析した結果です。項目にカーソルを合わせると、その値が画像のどこから読み取られたかがハイライトされ、各項目の**マッチ率(match_ratio)**も確認できます。請求書・納品書もまったく同じ挙動です ── 抽出した1つ1つの値が、読み取り元のピクセルに紐づきます。

Source receipts with extracted-field bounding boxes
Verified fields
KINSHO · 合計 2,045
ライフ · 合計 4,286

Every value carries a verified on-page location — bbox + 4-point vertices + 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.

Demo抽出された値はすべて、<b>bbox(座標)</b>・回転対応の vertices・<b>マッチ率</b>を伴って返ります ── 描画も引用もできる「出どころ」付きのデータ。
抽出された値はすべて、bbox(座標)・回転対応の vertices・マッチ率を伴って返ります ── 描画も引用もできる「出どころ」付きのデータ。

「元画像 → 抽出シート → 該当箇所の強調 → CSV出力」の流れ

space ocr の使い方は、突きつめると4ステップです。(1) 領収書・請求書・納品書の画像を投げる → (2) 列の決まったシートに1枚=1行で抽出される → (3) 値をクリックすると元画像の該当箇所が点灯して原本照合できる → (4) そのまま CSV で書き出して会計ソフトに取り込む。まずは1枚を投げて項目が埋まる様子から。

Demo請求書を1枚ドロップすると、型のついた項目が自動で埋まる ── <b>API</b> が返すのと同じデータが、UI 上で。
請求書を1枚ドロップすると、型のついた項目が自動で埋まる ── API が返すのと同じデータが、UI 上で。

認証とベース URL

公開 API のベースは https://api.space-ocr.com の1つだけ ── /v1 のようなパスバージョニングはありません。各リクエストは、spocr_ で始まるキーを使った HTTP Bearer トークンで認証します。

Authorization: Bearer spocr_xxxxxxxxxxxxxxxx

ヘッダが欠落・不正なら 401、未登録のキーなら 403 が返ります。すべてのレスポンスに X-Request-Id(形式 req_xxx)ヘッダが付くので、サポート問い合わせ用にログへ残しておくと安心です。クライアントを自動生成したい場合は、GET /openapi.json に OpenAPI 3.1 の仕様が公開されています。

最短経路 ── ビルトインの請求書・納品書テンプレート

一番速いのは、templateId に組み込みテンプレートを指定する方法です。請求書なら templateId: "invoice"、納品書なら templateId: "delivery"。「請求書とはどんな項目を持つか」をエンジン側が知っているので、こちらで項目を1つずつ定義する必要はありません。画像は URL でも純粋な base64 でも渡せます(imageTypehttp(s):// プレフィックスの有無から自動判定されます)。

POST /ocr/fields ── 納品書テンプレートで叩く
1
2
3
4
5
6
7
8
curl -X POST https://api.space-ocr.com/ocr/fields \
  -H "Authorization: Bearer spocr_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "https://example.com/docs/delivery-0831.jpg",
    "imageType": "url",
    "templateId": "delivery"
  }'
Why it matters

パラメータはキャメルケースが正式名です。 imageType / templateId / autoFields を使ってください。旧来のスネークケース(image_type / template_id / auto_fields)も動きますが非推奨です。新しいコードではキャメルケースを優先してください。なお請求書なら templateId: "invoice"、納品書なら templateId: "delivery" です。

レスポンスの形 ── 値ごとに「出どころ」が付く

成功すると { status: "success", data: { ... } } が返ります。抽出された各値はそれぞれ出どころ情報を持ち、field_bboxes マップに項目ごとの座標がまとまっています。

  • bbox ── { xmin, ymin, xmax, ymax } の軸並行矩形。0〜1000 に正規化されたグリッド上の整数座標です(0,0 が左上、1000,1000 が右下)。画像のピクセルサイズには依存しません。ピクセル変換は pixel_x = bbox_x / 1000 × image_width
  • vertices ── 左上 → 右上 → 右下 → 左下の順に並んだ4点 {x, y}。書類の傾きに沿う**回転対応(oriented)**の矩形なので、斜めに撮ったスマホ写真でもきれいに囲めます。
  • match_ratio ── その値の文字のうち、実際にページ上で見つかった割合(0〜1)。0.85 以上で確信マッチとして扱われ、1.0 は全文字がページ上で見つかったことを意味します。
  • bbox_source ── 座標の導出方法のラベル。vision_symbol_match(文字マッチが 0.85 以上で着地した通常経路 ── 実際の match_ratio を伴う)、token_id / token_id_hybrid(LLM が返したワードトークンのヒントで Vision の語トークンを引いた経路)、low_confidence(文字マッチが 0.85 未満 ── 要確認)、shared_value(結合セルからの伝播)。
POST /ocr/fields → レスポンス(抜粋)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
  "status": "success",
  "data": {
    "total": "2,045",
    "field_bboxes": {
      "total": {
        "bbox": { "xmin": 595, "ymin": 974, "xmax": 781, "ymax": 1000 },
        "vertices": [
          { "x": 594, "y": 975 }, { "x": 781, "y": 972 },
          { "x": 781, "y": 998 }, { "x": 595, "y": 1000 }
        ],
        "match_ratio": 0.93,
        "bbox_source": "vision_symbol_match"
      }
    }
  }
}
✓ Verified

座標は AI の言い分を鵜呑みにしていません。 言語モデルが返すのは各値のテキストと、使ったワードトークンのヒント(wid)だけで、座標そのものは返しません。エンジンはまずそのテキストを、Vision OCR がページ上で実際に検出したシンボルと1文字ずつ照合します ── だから矩形は、その文字が本当に見つかったピクセルに着地し、各値には「どれだけ一致したか」を示す match_ratio が付きます。LLM がワードトークンのヒントを返したときは、そのトークンの座標で一部の項目を上書きすることもありますが、このヒントはノイズを含むことがあり(繰り返し行で隣の行と取り違える、いわゆる stochastic な揺れ)、盲信せず列・行の整合性で検証・補正してから採用します。要点は「AI が間違えない」ではなく、どの値もページ側に照合し直され、どれだけ一致したかのスコアが残ること。詳しくはバウンディングボックスで OCR を監査可能にする仕組みを参照してください。

テンプレートで足りないとき ── カスタム項目

実務の請求書には、汎用テンプレートが名前を持たない項目があります ── 発注番号、支払条件コード、プロジェクトタグなど。そんなときは templateId の代わりに(または併用して)、FieldSpec の配列 fields を渡します。各 FieldSpec は { name, type, description?, children? }fieldstemplateId を両方送った場合は fields が優先されます。

description がモデルを誘導する場所です ── 何をどう拾うかを日本語の指示文で書けます。そして type: "array"children の組み合わせが、繰り返す明細行を引き出す方法です。子スキーマを1つ定義すれば、行が何本でも返ります。

カスタム FieldSpec ── 明細をネストして抽出(納品書 CSV 化)
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
import requests, base64, csv

with open("delivery.jpg", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

resp = requests.post(
    "https://api.space-ocr.com/ocr/fields",
    headers={"Authorization": "Bearer spocr_xxxxxxxxxxxxxxxx"},
    json={
        "image": b64,
        "imageType": "base64",
        "fields": [
            {"name": "vendor", "type": "string",
             "description": "納品元(取引先)の会社名"},
            {"name": "delivery_no", "type": "string",
             "description": "納品書番号。原文のまま"},
            {"name": "delivery_date", "type": "string",
             "description": "納品日。和暦・西暦は原文のまま保持"},
            {"name": "total", "type": "string",
             "description": "合計金額。カンマ区切りは保持"},
            {"name": "items", "type": "array",
             "description": "明細1行につき1要素",
             "children": [
                 {"name": "name", "type": "string", "description": "品名"},
                 {"name": "qty", "type": "number", "description": "数量"},
                 {"name": "unit_price", "type": "number", "description": "単価"},
             ]},
        ],
    },
    timeout=60,
)

data = resp.json()["data"]

# 明細を CSV へ。Excel と CJK のため UTF-8 BOM で書き出す
with open("delivery.csv", "w", encoding="utf-8-sig", newline="") as out:
    w = csv.writer(out)
    w.writerow(["品名", "数量", "単価"])
    for row in data.get("items", []):
        w.writerow([row["name"], row["qty"], row["unit_price"]])
Why it matters

値は原文のまま(verbatim)保持されます。 合計 7,855 は文字列 "7,855" として返り、カンマ区切り・小数点・全角文字もそのまま。description で明示的に頼んだときだけ正規化します。UI に見える ¥ は装飾で、値の一部ではありません。CSV の文字化け対策として、Excel で開く CSV は UTF-8 BOMutf-8-sig)で書き出すのがコツ ── 上のコードもそうしています。なお、明細が「1セルに潰れる」のを防ぐ鍵が type: "array" + children で、これにより1明細=1行に展開されます。

文字をクリックして、元の箇所へジャンプ

シートに蓄積した後は、値をクリックすると元画像の該当箇所が点灯します。これがバッチのスポットチェックで一番速い方法です ── 書類全体を見渡す代わりに、視線がそのまま該当箇所へ飛びます。match_ratio が低い項目だけを優先して確認する、といった運用もできます。

Demo抽出済みの請求書を横断検索し、ヒットしたセル ── と、その<b>元画像の該当箇所</b>へ一気にジャンプ。
抽出済みの請求書を横断検索し、ヒットしたセル ── と、その元画像の該当箇所へ一気にジャンプ。

非同期で大量に ── バッチアップロード・ジョブ・Webhook

POST /ocr/fields は同期で、リクエスト/レスポンスのループに置く1枚処理に最適です。請求書・納品書のフォルダをまとめて処理するなら、シートに対して POST /upload(multipart の files を繰り返し)で投げます。既定では即座にジョブ配列が返ります。

{ "path": "...", "jobs": [ { "uniqueKey": "...", "jobId": "...", "status": "pending" } ] }

結果の受け取り方は2通り。GET /jobs/{jobId} をポーリングするか、Webhook を登録します。Webhook はスペースごとに1 URL、すべてのイベントが X-Spaceocr-Signature ヘッダで HMAC-SHA256 署名されます。注目すべきイベントは upload.receiveditem.createdocr.completeddata.result に抽出結果)・ocr.failed。ペイロードを信頼する前に、必ず署名を検証してください。

冪等性・リクエスト追跡・レート制限

本番パイプラインを安全にリトライ可能にするための、いくつかのヘッダがあります。

ヘッダ役割
Idempotency-Key/upload/create で、同じキーの再送は 24 時間キャッシュ応答を再生(X-Idempotent-Replay: true)── 二重課金なしで安全にリトライ。
X-Request-Idすべてのレスポンスに付く(req_xxx)。サポート用にログへ。

レート制限はキーあたり 60 リクエスト/分uid あたり 600 リクエスト/分(固定 60 秒ウィンドウ)。超過すると 429error.code: "rate_limited" が返ります。待機秒数は JSON ボディの details.retryAfterSec に入ります ── Retry-After HTTP ヘッダではありません。バックオフはボディの値を見て行ってください。

429 レスポンスボディ
1
2
3
4
5
6
7
8
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded",
    "requestId": "req_8fa2c1"
  },
  "details": { "retryAfterSec": 12 }
}

抽出から、クエリできるシートへ

請求書をシートに抽出したら、読み戻すために OCR を再実行する必要はありません。GET /view が蓄積済みの行に対してサーバ側クエリ ── wheresortselectlimitoffset ── を実行します。OCR 再実行も課金もなし。座標は既定で一緒に返り、軽くしたいときだけ boxes=0 を付けます。例えば where=total>=40000 で高額の請求書だけ、sort=-invoice_date で新しい順に。そこから CSV で書き出せば(UTF-8 BOM なので Excel と CJK もきれいに開く)、会計ソフトへの取り込みに使えます ── 詳しくはスキャン書類を CSV にするレシートを CSV に変換するを参照してください。なお全エンドポイントの仕様は API ドキュメントにまとまっています。

Note

PDF はページを画像に変換してから送ります。 OCR エンジンが直接解析するのはラスター画像(JPEG・PNG・GIF・BMP・TIFF・WebP)です。API を直接叩く場合は、PDF の各ページを PNG などにレンダリングしてから送ってください(Web アプリにドロップする場合は、ページの画像化をアプリが自動で行うので、そのまま PDF を投げられます)。freee・マネーフォワード・弥生・kintone への連携は公式 API 連携ではなく、書き出した CSV の取り込みで行う前提です。また、インボイス制度や電子帳簿保存法への対応可否は、各社の運用・要件にあわせてご確認ください(本サービスが法要件の充足を保証するものではありません)。

料金

POST /ocr/fields1コール ¥10POST /upload は ¥10 × N 枚です。失敗時は無課金 ── OCR が結果を返さなければ返金され、502 エンジンエラーや ocr.failed イベントは自動で返金されます。読み取り専用エンドポイント(GET /space/view/amount/health)は無料。無料枠はクレカ不要で 月 100 枚、Pro は $39/月、Business は問い合わせ(お見積り)です。

請求書・納品書を API で抽出する手順

  1. API キーを用意する
    ログインして spocr_ で始まる API キーを発行し、各リクエストに Authorization: Bearer spocr_... を付けます。ベース URL は https://api.space-ocr.com です。
  2. 画像を用意する(PDF はページを画像化)
    請求書・納品書を JPEG/PNG などのラスター画像として用意します。API を直接叩く場合、PDF は各ページを PNG にレンダリングしてから送ります(Web アプリにドロップする場合はアプリが自動で画像化します)。画像は URL または純粋な base64 で渡し、imageType を url / base64 で指定します。
  3. POST /ocr/fields を叩く
    請求書なら templateId: "invoice"、納品書なら templateId: "delivery" を指定します。テンプレートで足りない項目は fields[](FieldSpec {name,type,description,children})で定義し、明細は type:"array" + children で1行ずつ展開します。
  4. レスポンスを検証する
    返ってきた各値の bbox・vertices・match_ratio・bbox_source を確認します。match_ratio が 0.85 未満(low_confidence)の項目は原本と突き合わせて確認します。
  5. CSV にして会計ソフトへ
    抽出結果を UTF-8 BOM 付きの CSV に書き出し(明細は配列行として展開)、freee・マネーフォワード・弥生などの CSV 取り込みに渡します。蓄積後は GET /view で再 OCR・無課金のままクエリできます。
請求書・納品書 OCR API は日本語に対応していますか?
はい。言語は完全自動で、ヒントの指定は不要です。日本語・英語・中国語・韓国語を1つのエンジンで処理し、全角/半角、ハイフンの変種、括弧、CJK の空白、縦書きの漢字、複数スクリプトの混在も正規化します。和暦の日付や品名も、description で明示しない限り原文のまま(verbatim)返ります。
PDF の請求書・納品書には対応していますか?
対応しています。ただし OCR エンジンが直接解析するのはラスター画像(JPEG・PNG・GIF・BMP・TIFF・WebP)です。API を直接叩く場合は、PDF の各ページを PNG などにレンダリングしてから送ってください。Web アプリに PDF をドロップする場合は、ページの画像化をアプリが自動で行うため、そのまま PDF を投げて OCR できます。
抽出したデータを freee やマネーフォワード、弥生に取り込めますか?
CSV 経由で取り込めます。シートを CSV にエクスポートでき(Excel と CJK のために UTF-8 BOM 付き)、明細は配列行として展開されるので、各会計ソフトの CSV 取り込み機能に渡せます。これらは公式 API 連携ではなく、書き出した CSV の取り込みで運用する前提です。
抽出の精度はどう担保されますか? 結果を信用できますか?
値ごとに、元画像のどこから読み取ったかの bbox(0〜1000 正規化座標)と vertices、そして match_ratio が付きます。match_ratio は、その値の文字のうち実際にページ上で見つかった割合で、0.85 以上が確信マッチ、1.0 は全文字一致です。座標は AI が作るのではなく、抽出されたテキストを Vision OCR の実シンボルと1文字ずつ照合して導出します。LLM が返すワードトークンのヒントはノイズを含みうるため、列・行の整合性で検証してから採用します。だから低スコアの項目だけを優先して目視確認する、といった監査運用ができます。
個人情報やデータの取り扱い、失敗時の課金はどうなりますか?
失敗時は無課金です。OCR が結果を返さなければ返金され、502 エンジンエラーや ocr.failed イベントは自動で返金されます。Webhook はスペースごとに1 URL で、すべてのイベントが X-Spaceocr-Signature ヘッダで HMAC-SHA256 署名されるため、受信側で署名を検証してから処理できます。冪等キー(Idempotency-Key)でリトライ時の二重課金も防げます。

最初の請求書を、1コールで抽出

無料枠 ── 月 100 枚、クレジットカード不要。すべての値が、元画像のどこから読み取ったかの座標つきで返ります。

関連記事