API利用前にワークフローを検証
まずワークステーションで、確認済みの出力がワークフローに合っていることを確認してから、繰り返しの抽出実行にAPIを使用してください。
Base: https://pdf2text.ai/api/v1
認証
すべてのAPIリクエストには、AuthorizationヘッダーにBearerトークンが必要です。繰り返し使えるワークフローを検証した後、アカウント設定からキーを生成してください。
APIキーを管理認証
# Set your API key
export P2T_API_KEY="your_api_key_here"
# Include in all requests
curl -H "Authorization: Bearer $P2T_API_KEY" ...
import requests
import os
API_KEY = os.environ["P2T_API_KEY"]
headers = {"Authorization": f"Bearer {API_KEY}"}
const API_KEY = process.env.P2T_API_KEY;
const headers = {
'Authorization': `Bearer ${API_KEY}`
};
利用制限
Firmプランには、確認を伴うワークステーションのワークフローと検証済みのAPI抽出実行のために、毎月1500ページが含まれます。処理されたページごとに、その枠から1ページが使用されます。
利用量はAPI呼び出し回数ではなく、処理されたページ数で計測されます。ファイルのアップロードや結果・エクスポートのダウンロードではページは使用されませんが、抽出を再実行するとそのページが再度処理され、ページが再び使用されます。
対応しているアップロード形式はPDF、PNG、JPEG、WebPで、1ファイルあたり最大50 MiBです。現在の環境では、すべてのファイルとフォームのオーバーヘッドを含むマルチパートリクエスト全体も100 MiBに制限されています。アップロードは、1リクエストあたり20ファイル、1グループあたり100ファイル、1ドキュメントまたは1実行あたり500ページ、1グループあたり保存ページ数1,000ページに制限されています。画像はいずれの辺も最大20,000ピクセル、40メガピクセルまでです。OCRのレンダリング解像度でこれらのラスター上限を超えるPDFページは拒否されます。
API呼び出しに個別の上限はありません。抽出の実行は非同期で処理キューに入るため、完了までの時間はドキュメントのサイズやシステムの負荷によって異なります。
フェアユースのリクエスト制限は、デフォルトで1アカウントあたり1時間に30回のアップロード、60回の実行開始、600回の読み取りまたはエクスポートです。429レスポンスにはRetry-Afterが含まれます。再試行する前に、その間隔だけ待ってください。
API自動化に頼る前に、ワークステーションを使ってドキュメントのレイアウト、確認ルール、エクスポート形式を検証してください。
プランを比較ドキュメントをアップロード
1つ以上のPDF、PNG、JPEG、WebPファイルをアップロードして、ドキュメントグループを作成します。ファイルのバイト、ページ数、画像のサイズは、保存前に検証されます。アップロードに成功すると、すべてのドキュメントについて検証済みのpage_countを含む201 Createdが返されます。
エンドポイント
POST /api/v1/documents/upload/
パラメータ
file / files
binary
PDF、PNG、JPEG、またはWebP(必須。複数アップロードする場合はfilesを繰り返します)
grouping_id
uuid
任意。既存のAPIグループのいずれかに追加します。匿名のワークスペースはUUIDで引き継ぐことはできません。また、実行中のグループは完了するまで変更できません。
document_type
string
任意。分類のヒント。
password
string
任意。このリクエストでパスワード付きPDFを開きます。ファイルを開くためだけに使われ、保存されません。指定しない場合、そのPDFはencrypted_pdfを返します。誤ったパスワードはpdf_password_incorrectを返し、同じファイルで誤りが続くと429を返します。
ドキュメントをアップロード
# Upload a PDF file
curl -X POST https://pdf2text.ai/api/v1/documents/upload/ \
-H "Authorization: Bearer $P2T_API_KEY" \
-F "file=@invoice.pdf"
# Add to existing group
curl -X POST https://pdf2text.ai/api/v1/documents/upload/ \
-H "Authorization: Bearer $P2T_API_KEY" \
-F "file=@invoice2.pdf" \
-F "grouping_id=a1b2c3d4-..."
import requests
url = "https://pdf2text.ai/api/v1/documents/upload/"
# Upload single file
with open("invoice.pdf", "rb") as f:
response = requests.post(
url,
headers=headers,
files={"file": f}
)
data = response.json()
group_id = data["group_id"]
const { readFile } = require('node:fs/promises');
const form = new FormData();
form.append(
'file',
new Blob([await readFile('invoice.pdf')], { type: 'application/pdf' }),
'invoice.pdf'
);
const response = await fetch(
'https://pdf2text.ai/api/v1/documents/upload/',
{
method: 'POST',
headers,
body: form
}
);
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
const { group_id } = await response.json();
{
"status": "success",
"group_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"documents": [
{
"doc_id": 42,
"uid": "1847f600-...",
"grouping_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"original_filename": "invoice.pdf",
"file_type": "pdf",
"page_count": 3,
"status": "pending"
}
]
}
グループにファイルを追加できるのは、最初の実行前のみです。後から追加する請求書には新しいグループを作成してください。そうしないと、フィルターなしの実行でそのグループ内の既存のドキュメントがすべて処理されます。
抽出処理を開始
ドキュメントグループの非同期処理を開始します。抽出前にPDF2TEXTでドキュメントを分類する場合は、自動ルーティングを使用してください。
すべての開始リクエストでIdempotency-Keyヘッダーを送信してください。同じキーと本文を繰り返すと同じ実行が返されます。異なるリクエストにキーを再利用すると409が返されます。最終的な失敗の後は、新しいキーを使って意図的に代わりの実行を作成してください。新たにキューに入った実行には202 Acceptedが返されます。1つのグループで同時に実行できるのは1つだけで、実行中の処理は処理可能なアカウントのページを確保します。
202レスポンスは実行が受け付けられたことを示すものであり、要求されたすべてのページ分の残高があることを示すものではありません。アカウントの共有残高が実行に必要な量より少ない場合、APIは確保されたページを処理し、credit_limit_reached=trueのpartialとして完了します。インポートを完了として扱う前に、実行の最終ステータスを確認してください。
コールバックURLは公開されたHTTPSを使用する必要があり、別の宛先にリダイレクトすることはできません。配信は非同期で、リクエストのタイムアウトは10秒です。一時的な接続エラー、HTTP 429、HTTP 5xxのレスポンスに対しては、30秒、2分、10分のバックオフ間隔で最大4回再試行します。
callback_secretを指定した場合は、リクエスト本文そのものに対してHMAC-SHA256を計算し、sha256=の値と比較してX-PDF2TEXT-Signatureを検証してください。配信の重複排除には、X-PDF2TEXT-Run-IDまたはX-PDF2TEXT-Idempotency-Keyを使用してください。
The callback JSON body is {"event": "idp.run.completed", "run": {...}}; run uses the same full result shape as GET ?include=results. A signature header is sent only when callback_secret was included in the start request.
エンドポイント
POST /api/v1/groups/{group_id}/runs/
リクエストボディ
auto_route
boolean
自動分類(デフォルト:true)
extraction_mode
enum
auto、raw_text、financial_table、general_table、またはunified。カスタムスキーマにはtemplate_idまたはtemplate_slugを使用してください。
template_id / template_slug
uuid / string
特定のテンプレートを強制するには、いずれか1つだけを指定してください
selected_pages
array
{docUid, pageNumber}の空でないリスト(任意)。無効なページがあるとリクエスト全体が拒否されます
construction_project_id
uuid
APIアカウントが所有するプロジェクト(任意)
callback_url
string
Webhook URL
callback_secret
string
HMAC署名シークレット
抽出処理を開始
# Start extraction with auto-routing
curl -X POST https://pdf2text.ai/api/v1/groups/$GROUP_ID/runs/ \
-H "Authorization: Bearer $P2T_API_KEY" \
-H "Idempotency-Key: invoice-import-123" \
-H "Content-Type: application/json" \
-d '{"auto_route": true}'
# Start extraction run
url = f"https://pdf2text.ai/api/v1/groups/{group_id}/runs/"
response = requests.post(
url,
headers={**headers, "Idempotency-Key": "invoice-import-123"},
json={"auto_route": True}
)
run_data = response.json()
run_id = run_data["run_id"]
// Start extraction run
const response = await fetch(
`https://pdf2text.ai/api/v1/groups/${groupId}/runs/`,
{
method: 'POST',
headers: {
...headers,
'Idempotency-Key': 'invoice-import-123',
'Content-Type': 'application/json'
},
body: JSON.stringify({ auto_route: true })
}
);
const { run_id } = await response.json();
{
"status": "success",
"run_id": "b3143b91-...",
"job_id": "idp-run-b3143b91-...",
"group_name": "ocr_job_a1b2c3d4...",
"idempotent_replay": false,
"run": {
"id": "b3143b91-...",
"status": "queued",
"job_id": "idp-run-b3143b91-...",
"total_pages": 3,
"pages_processed": 0
}
}
結果を取得
runエンドポイントをポーリングするか、Webhookを使用して抽出結果を取得します。JSONまたはExcel形式でエクスポートできます。
デフォルトの実行レスポンスは頻繁なポーリング向けに軽量化されており、キャッシュされることはありません。ネストされたrunオブジェクト内のrun.statusを参照してください。最終ステータスはcomplete、partial、errorです。最終ステータスになった後、include=resultsを1回リクエストして、full_text、structured_output、documentsを取得してください。
credits_remainingは互換性のために残されており、その実行後の過去の残高を記録しています。credits_remaining_after_runは同じ過去の値を明示的に示すもので、account_credits_remainingはレスポンス生成時点のアカウントの現在の共有残高を示します。
エンドポイント一覧
GET /api/v1/runs/{run_id}/
GET /api/v1/runs/{run_id}/?include=results
GET /api/v1/runs/{run_id}/export.json
GET /api/v1/runs/{run_id}/export.xlsx
GET /api/v1/runs/{run_id}/export.xlsx?date_format=MM/DD/YYYY
銀行明細の場合、export.xlsxにはQuickBooks CSVとXero CSVのシートも含まれます。日付はアカウントに保存した形式、なければ明細の国の並びで書き出されます。date_format(DD/MM/YYYY、MM/DD/YYYY、YYYY/MM/DD、YYYY-MM-DD)を渡すと指定でき、ほかのシートはYYYY-MM-DDのままです。
レスポンスステータスコード
結果を取得
# Lightweight status poll
curl https://pdf2text.ai/api/v1/runs/$RUN_ID/ \
-H "Authorization: Bearer $P2T_API_KEY"
# Fetch completed results once, then export
curl "https://pdf2text.ai/api/v1/runs/$RUN_ID/?include=results" \
-H "Authorization: Bearer $P2T_API_KEY"
curl -o results.xlsx \
https://pdf2text.ai/api/v1/runs/$RUN_ID/export.xlsx \
-H "Authorization: Bearer $P2T_API_KEY"
import time
run_url = f"https://pdf2text.ai/api/v1/runs/{run_id}/"
terminal = {"complete", "partial", "error"}
delay = 2
# Poll lightweight state with bounded exponential backoff
while True:
response = requests.get(run_url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", delay))
time.sleep(retry_after)
delay = min(30, max(10, delay * 2))
continue
response.raise_for_status()
run = response.json()["run"]
if run["status"] in terminal:
break
time.sleep(delay)
delay = min(30, max(10, delay * 2))
if run["status"] == "error":
raise RuntimeError(run["error_message"])
results = requests.get(run_url, params={"include": "results"}, headers=headers).json()["run"]
excel = requests.get(
f"{run_url}export.xlsx",
headers=headers
)
with open("results.xlsx", "wb") as f:
f.write(excel.content)
// Poll lightweight state
const pollResults = async (runId) => {
const runUrl = `https://pdf2text.ai/api/v1/runs/${runId}/`;
const terminal = new Set(['complete', 'partial', 'error']);
let delay = 2000;
while (true) {
const response = await fetch(runUrl, { headers });
if (response.status === 429) {
const retryAfter = Number(response.headers.get('Retry-After') || delay / 1000);
await new Promise(r => setTimeout(r, retryAfter * 1000));
delay = Math.min(30000, Math.max(10000, delay * 2));
continue;
}
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const { run } = await response.json();
if (terminal.has(run.status)) {
if (run.status === 'error') throw new Error(run.error_message);
const resultResponse = await fetch(`${runUrl}?include=results`, { headers });
return (await resultResponse.json()).run;
}
await new Promise(r => setTimeout(r, delay));
delay = Math.min(30000, Math.max(10000, delay * 2));
}
};
const results = await pollResults(runId);
{
"status": "success",
"run": {
"id": "b3143b91-...",
"status": "complete",
"total_pages": 3,
"pages_processed": 3,
"credits_remaining_after_run": 497,
"account_credits_remaining": 497,
"full_text": "...",
"structured_output": { /* grouped output */ },
"documents": [
{
"doc_id": 42,
"document_name": "invoice.pdf",
"ocr_text": "...",
"structured_output": { /* document output */ }
}
]
}
}
テンプレート
利用可能な抽出テンプレートを一覧表示します。テンプレートIDを使用して特定の抽出スキーマを指定できます。
エンドポイント
GET /api/v1/templates/
テンプレート
# List available templates
curl https://pdf2text.ai/api/v1/templates/ \
-H "Authorization: Bearer $P2T_API_KEY"
# List available templates
response = requests.get(
"https://pdf2text.ai/api/v1/templates/",
headers=headers
)
templates = response.json()["templates"]
for t in templates:
print(f"{t['name']}: {t['id']}")
// List available templates
const response = await fetch(
'https://pdf2text.ai/api/v1/templates/',
{ headers }
);
const { templates } = await response.json();
templates.forEach(t => console.log(`${t.name}: ${t.id}`));
{
"status": "success",
"templates": [
{
"id": "198aa5be-ea8b-4d67-bdb5-625f5d7d29e8",
"slug": "invoice",
"name": "Invoice",
"description": "Standard invoice extraction",
"extraction_mode": "financial_table"
},
{
"id": "4317707a-f0da-4c2f-a1ec-d0119d96b55c",
"slug": "receipt",
"name": "Receipt",
"description": "Receipt and expense extraction",
"extraction_mode": "financial_table"
}
]
}
サポートが必要ですか?
確認キューを使って、抽出されたフィールドを確認し、確認の経緯を保持してください。
認証
# Set your API key
export P2T_API_KEY="your_api_key_here"
# Include in all requests
curl -H "Authorization: Bearer $P2T_API_KEY" ...
import requests
import os
API_KEY = os.environ["P2T_API_KEY"]
headers = {"Authorization": f"Bearer {API_KEY}"}
const API_KEY = process.env.P2T_API_KEY;
const headers = {
'Authorization': `Bearer ${API_KEY}`
};
ドキュメントをアップロード
# Upload a PDF file
curl -X POST https://pdf2text.ai/api/v1/documents/upload/ \
-H "Authorization: Bearer $P2T_API_KEY" \
-F "file=@invoice.pdf"
# Add to existing group
curl -X POST https://pdf2text.ai/api/v1/documents/upload/ \
-H "Authorization: Bearer $P2T_API_KEY" \
-F "file=@invoice2.pdf" \
-F "grouping_id=a1b2c3d4-..."
import requests
url = "https://pdf2text.ai/api/v1/documents/upload/"
# Upload single file
with open("invoice.pdf", "rb") as f:
response = requests.post(
url,
headers=headers,
files={"file": f}
)
data = response.json()
group_id = data["group_id"]
const { readFile } = require('node:fs/promises');
const form = new FormData();
form.append(
'file',
new Blob([await readFile('invoice.pdf')], { type: 'application/pdf' }),
'invoice.pdf'
);
const response = await fetch(
'https://pdf2text.ai/api/v1/documents/upload/',
{
method: 'POST',
headers,
body: form
}
);
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
const { group_id } = await response.json();
{
"status": "success",
"group_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"documents": [
{
"doc_id": 42,
"uid": "1847f600-...",
"grouping_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"original_filename": "invoice.pdf",
"file_type": "pdf",
"page_count": 3,
"status": "pending"
}
]
}
グループにファイルを追加できるのは、最初の実行前のみです。後から追加する請求書には新しいグループを作成してください。そうしないと、フィルターなしの実行でそのグループ内の既存のドキュメントがすべて処理されます。
抽出処理を開始
# Start extraction with auto-routing
curl -X POST https://pdf2text.ai/api/v1/groups/$GROUP_ID/runs/ \
-H "Authorization: Bearer $P2T_API_KEY" \
-H "Idempotency-Key: invoice-import-123" \
-H "Content-Type: application/json" \
-d '{"auto_route": true}'
# Start extraction run
url = f"https://pdf2text.ai/api/v1/groups/{group_id}/runs/"
response = requests.post(
url,
headers={**headers, "Idempotency-Key": "invoice-import-123"},
json={"auto_route": True}
)
run_data = response.json()
run_id = run_data["run_id"]
// Start extraction run
const response = await fetch(
`https://pdf2text.ai/api/v1/groups/${groupId}/runs/`,
{
method: 'POST',
headers: {
...headers,
'Idempotency-Key': 'invoice-import-123',
'Content-Type': 'application/json'
},
body: JSON.stringify({ auto_route: true })
}
);
const { run_id } = await response.json();
{
"status": "success",
"run_id": "b3143b91-...",
"job_id": "idp-run-b3143b91-...",
"group_name": "ocr_job_a1b2c3d4...",
"idempotent_replay": false,
"run": {
"id": "b3143b91-...",
"status": "queued",
"job_id": "idp-run-b3143b91-...",
"total_pages": 3,
"pages_processed": 0
}
}
結果を取得
# Lightweight status poll
curl https://pdf2text.ai/api/v1/runs/$RUN_ID/ \
-H "Authorization: Bearer $P2T_API_KEY"
# Fetch completed results once, then export
curl "https://pdf2text.ai/api/v1/runs/$RUN_ID/?include=results" \
-H "Authorization: Bearer $P2T_API_KEY"
curl -o results.xlsx \
https://pdf2text.ai/api/v1/runs/$RUN_ID/export.xlsx \
-H "Authorization: Bearer $P2T_API_KEY"
import time
run_url = f"https://pdf2text.ai/api/v1/runs/{run_id}/"
terminal = {"complete", "partial", "error"}
delay = 2
# Poll lightweight state with bounded exponential backoff
while True:
response = requests.get(run_url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", delay))
time.sleep(retry_after)
delay = min(30, max(10, delay * 2))
continue
response.raise_for_status()
run = response.json()["run"]
if run["status"] in terminal:
break
time.sleep(delay)
delay = min(30, max(10, delay * 2))
if run["status"] == "error":
raise RuntimeError(run["error_message"])
results = requests.get(run_url, params={"include": "results"}, headers=headers).json()["run"]
excel = requests.get(
f"{run_url}export.xlsx",
headers=headers
)
with open("results.xlsx", "wb") as f:
f.write(excel.content)
// Poll lightweight state
const pollResults = async (runId) => {
const runUrl = `https://pdf2text.ai/api/v1/runs/${runId}/`;
const terminal = new Set(['complete', 'partial', 'error']);
let delay = 2000;
while (true) {
const response = await fetch(runUrl, { headers });
if (response.status === 429) {
const retryAfter = Number(response.headers.get('Retry-After') || delay / 1000);
await new Promise(r => setTimeout(r, retryAfter * 1000));
delay = Math.min(30000, Math.max(10000, delay * 2));
continue;
}
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const { run } = await response.json();
if (terminal.has(run.status)) {
if (run.status === 'error') throw new Error(run.error_message);
const resultResponse = await fetch(`${runUrl}?include=results`, { headers });
return (await resultResponse.json()).run;
}
await new Promise(r => setTimeout(r, delay));
delay = Math.min(30000, Math.max(10000, delay * 2));
}
};
const results = await pollResults(runId);
{
"status": "success",
"run": {
"id": "b3143b91-...",
"status": "complete",
"total_pages": 3,
"pages_processed": 3,
"credits_remaining_after_run": 497,
"account_credits_remaining": 497,
"full_text": "...",
"structured_output": { /* grouped output */ },
"documents": [
{
"doc_id": 42,
"document_name": "invoice.pdf",
"ocr_text": "...",
"structured_output": { /* document output */ }
}
]
}
}
テンプレート
# List available templates
curl https://pdf2text.ai/api/v1/templates/ \
-H "Authorization: Bearer $P2T_API_KEY"
# List available templates
response = requests.get(
"https://pdf2text.ai/api/v1/templates/",
headers=headers
)
templates = response.json()["templates"]
for t in templates:
print(f"{t['name']}: {t['id']}")
// List available templates
const response = await fetch(
'https://pdf2text.ai/api/v1/templates/',
{ headers }
);
const { templates } = await response.json();
templates.forEach(t => console.log(`${t.name}: ${t.id}`));
{
"status": "success",
"templates": [
{
"id": "198aa5be-ea8b-4d67-bdb5-625f5d7d29e8",
"slug": "invoice",
"name": "Invoice",
"description": "Standard invoice extraction",
"extraction_mode": "financial_table"
},
{
"id": "4317707a-f0da-4c2f-a1ec-d0119d96b55c",
"slug": "receipt",
"name": "Receipt",
"description": "Receipt and expense extraction",
"extraction_mode": "financial_table"
}
]
}