API Reference¶
要約 (summary): REST API の全エンドポイント仕様。programs / exclusions / meta / billing の各メソッドについて params, response, 認証要否, rate limit を記載。
ベース URL¶
バージョニングポリシー (Versioning policy)¶
エンドポイントは 2 種類に分かれる。契約の強さが異なるので、統合時に意識する。
/v1/* — 安定契約 (stable contract):
- /v1/programs/*, /v1/exclusions, /v1/billing/* など、/v1/ prefix を持つ全エンドポイント
- response schema の破壊的変更はしない
- マイナー改訂は 追加のみ (additive): 新しい任意フィールド、新しい optional query parameter、新しいエンドポイントの追加
- 破壊的変更が必要になった場合は /v2/* を新設し、/v1/* は最低 6 ヶ月並走させてから deprecate
- deprecation は response の Sunset / Deprecation header と docs 更新で 90 日以上前に告知
/healthz, /meta, /v1 prefix を持たない utility 系 — ライフサイクル扱い (lifecycle, unversioned):
- /healthz は liveness probe のみで、schema は空 object に変わる可能性あり
- /meta は aggregate stats (total_programs, last_updated 等) を返すが、field 追加・削除・意味変更が発生しうる
- /v1/billing/webhook は Stripe 側の event schema に追従する (Stripe 仕様に引きずられる)
- これらの shape 変更は 30 日前に docs/api-reference.md と changelog で告知 するが、/v2 昇格は行わない
統合する client 側の注意: /v1/* 以外のレスポンスを business logic の入力に使わない。監視・運用系 (dashboard, health check) に限定する。
認証 (Authentication)¶
すべての認証付きエンドポイントは下記いずれかのヘッダーで API key を渡す:
API key を送らない場合は free tier 扱い (100 requests/day, 一部エンドポイントは利用可)。key が無効 / 取り消し済みの場合は 401 Unauthorized を返す。
匿名呼び出しの IP レート制限 (Anonymous per-IP limit)¶
認証ヘッダー (X-API-Key / Authorization: Bearer) を付けない呼び出しは、IP アドレス単位で 1 日 100 req / IPv4 (/32) / IPv6 (/64) に制限される。これは discoverability 系エンドポイント (/meta, /v1/ping, /v1/programs/*, /v1/exclusions/*, /v1/feedback) にのみ適用され、/healthz, /v1/billing/webhook, /v1/subscribers/unsubscribe, dashboard 系 (/v1/me/*, /v1/session) はカウントしない。
認証済み呼び出し (有効な API key 付き) はこの IP 制限を完全にバイパスし、tier ごとの quota だけが適用される。
上限超過時:
HTTP/1.1 429 Too Many Requests
Retry-After: 43200
Content-Type: application/json
{"detail": "anon rate limit exceeded", "limit": 100, "resets_at": "2026-04-24T00:00:00+09:00"}
リセットは JST midnight (sliding window ではなく暦日)。Retry-After は次の JST 00:00 までの秒数。IP は raw のまま保存されず、HMAC-SHA256(ip, api_key_salt) で hash 化される。
Rate limit (tier)¶
| Tier | Daily limit | 計測 |
|---|---|---|
| free | 100 | key 無し / free key 共通 |
| paid | metered (Stripe 従量) | 上限なし、¥0.5/req 税別で請求 |
注: 価格と計測方法の最新値は pricing.md を参照。
free 上限超過時は 429 Too Many Requests, body に {"detail": "daily limit of 100 exceeded for tier=free"}。レスポンスに Retry-After: <seconds to UTC midnight> header を含む。paid は cap なし (スパイクでも 429 は返らない)。
Programs¶
GET /v1/programs/search¶
自由記述 + 構造化フィルタで制度を検索。
認証: 任意 (未認証は free tier)
Query parameters:
| name | type | required | description |
|---|---|---|---|
q |
string | no | 自由記述検索。3 文字以上で FTS5 trigram、2 文字以下は substring 一致 |
tier |
string (repeat) | no | S / A / B / C / X。複数指定で OR |
prefecture |
string | no | 都道府県名 (完全一致, 例: 青森県) |
authority_level |
string | no | 正本 (英語): national / prefecture / municipality / financial。日本語別名 (国 / 都道府県 / 市区町村 / 公庫) も API 側で正規化して受け付ける |
funding_purpose |
string (repeat) | no | 資金用途 (例: 設備投資) |
target_type |
string (repeat) | no | 対象者種別 (例: 認定新規就農者) |
amount_min |
number | no | 助成上限の下限 (万円) |
amount_max |
number | no | 助成上限の上限 (万円) |
include_excluded |
bool | no | true で tier=X も含める (default false) |
limit |
int | no | 1〜100 (default 20) |
offset |
int | no | ページング (default 0) |
fields |
enum | no | minimal / default / full。レスポンスサイズ切替 (default default) |
fields 選択肢:
| 値 | results[] の中身 |
目安サイズ (1 row) | 用途 |
|---|---|---|---|
minimal |
unified_id / primary_name / tier / prefecture / authority_name / amount_max_man_yen / official_url の 7 キーのみ |
~150-300 B | リスト表示、クイックフィルタ、MCP tool の中間結果 |
default (省略時) |
Program 全フィールド (今までと完全互換) |
~500-800 B | 通常の統合 |
full |
Program + enriched (A-J 全次元) + source_mentions + lineage (source_url / source_fetched_at / source_checksum)。enriched / source_mentions は null でもキーが必ず存在 |
~3-50 KB (enriched 次第) | 単一制度の深い読み込み、エージェントのリサーチ |
minimal / full は追加扱い。default のスキーマは破壊的変更せずに維持する。
Response (SearchResponse):
{
"total": 153,
"limit": 20,
"offset": 0,
"results": [
{
"unified_id": "string",
"primary_name": "string",
"aliases": ["string"],
"authority_level": "national",
"authority_name": "経済産業省",
"prefecture": null,
"municipality": null,
"program_kind": "補助金",
"official_url": "https://...",
"amount_max_man_yen": 450,
"amount_min_man_yen": 30,
"subsidy_rate": 0.5,
"trust_level": "high",
"tier": "A",
"coverage_score": 0.82,
"gap_to_tier_s": ["J_statistics"],
"a_to_j_coverage": {"A_basics": true, "B_target": true},
"excluded": false,
"exclusion_reason": null,
"crop_categories": [],
"equipment_category": null,
"target_types": ["中小企業"],
"funding_purpose": ["設備投資"],
"amount_band": "100-500",
"application_window": {"start": "2026-04-01", "end": "2026-06-30"}
}
]
}
Response example at fields=minimal:
{
"total": 153,
"limit": 20,
"offset": 0,
"results": [
{
"unified_id": "UNI-keiei-kaishi-shikin",
"primary_name": "経営開始資金",
"tier": "S",
"prefecture": null,
"authority_name": "農林水産省",
"amount_max_man_yen": 1500,
"official_url": "https://www.maff.go.jp/j/new_farmer/..."
}
]
}
Response example at fields=full: default と同じ results[i] に加え、各 row に enriched (A-J 次元) / source_mentions (list of {url, fetched_at}) / source_url / source_fetched_at / source_checksum が必ず入る (値が null でもキーは存在)。
Example:
# default shape
curl -H "X-API-Key: jpintel_..." \
"https://api.autonomath.ai/v1/programs/search?q=IT導入&tier=S&tier=A&limit=5"
# minimal — list rendering / quick filter
curl -H "X-API-Key: jpintel_..." \
"https://api.autonomath.ai/v1/programs/search?q=IT導入&limit=20&fields=minimal"
ソート: FTS を使った場合は rank 順、それ以外は tier (S→A→B→C→X) → primary_name。
GET /v1/programs/{unified_id}¶
単一制度の詳細取得。enriched (A-J 次元の詳細) と source_mentions を含む。
認証: 任意
Path parameters:
| name | type | required | description |
|---|---|---|---|
unified_id |
string | yes | 制度 ID |
Query parameters:
| name | type | required | description |
|---|---|---|---|
fields |
enum | no | minimal / default / full。レスポンスサイズ切替 (default default) |
fields 選択肢 (/v1/programs/{unified_id}):
| 値 | 中身 | 備考 |
|---|---|---|
minimal |
7-key whitelist (unified_id / primary_name / tier / prefecture / authority_name / amount_max_man_yen / official_url) |
詳細画面では通常使わないが、埋め込み UI の軽量表示に |
default (省略時) |
ProgramDetail (Program + enriched + source_mentions + lineage) — 従来と完全互換 |
通常の統合 |
full |
同上。ただし enriched / source_mentions / lineage 3 キーは null でも必ず key が存在する契約に揃う |
「null = 調査済で空」「key なし = 旧サーバー」を区別する必要がある AI agent 向け |
Response (ProgramDetail): SearchResponse.results[] と同じ構造 + 以下:
{
"...Program fields...": "...",
"enriched": {
"A_basics": {"...": "..."},
"B_target": {"...": "..."},
"J_statistics": null
},
"source_mentions": [
{"url": "https://...", "fetched_at": "2026-04-15T10:00:00Z", "confidence": 0.9}
]
}
Example:
# default (current behavior, unchanged)
curl -H "X-API-Key: jpintel_..." \
"https://api.autonomath.ai/v1/programs/keiei-kaishi-shikin"
# minimal — just the headline fields
curl -H "X-API-Key: jpintel_..." \
"https://api.autonomath.ai/v1/programs/keiei-kaishi-shikin?fields=minimal"
# full — enriched / source_mentions / lineage keys guaranteed present
curl -H "X-API-Key: jpintel_..." \
"https://api.autonomath.ai/v1/programs/keiei-kaishi-shikin?fields=full"
エラー: 存在しない ID は 404 Not Found。
POST /v1/programs/batch¶
最大 50 件の unified_id をまとめて解決する。GET /v1/programs/{unified_id} を N 回叩く代わりに 1 リクエストで済ませる用途 (agent が search_programs の 20 件候補を全件 enrich したい等)。
認証: 任意 (未認証は free tier)
Request body (BatchGetProgramsRequest):
| field | type | required | description |
|---|---|---|---|
unified_ids |
string[] | yes | 1〜50 件の制度 ID。重複は自動 dedupe (最初の出現順を保持) |
バリデーション:
unified_idsが空配列 →422 Unprocessable Entity- 50 件超 →
422 Unprocessable Entity unified_idsの cap は 50 件 (paging は提供しない。50 超の caller は client 側で chunk する)
Response (BatchGetProgramsResponse):
{
"results": [
{
"unified_id": "UNI-keiei-kaishi-shikin",
"primary_name": "経営開始資金",
"tier": "S",
"enriched": {"A_basics": {"...": "..."}},
"source_mentions": [{"url": "https://...", "fetched_at": "2026-04-15T..."}],
"source_url": "https://...",
"source_fetched_at": "2026-04-22T...",
"source_checksum": "638865704e10041c",
"...": "..."
}
],
"not_found": ["UNI-typo-1"]
}
| field | type | description |
|---|---|---|
results |
ProgramDetail[] |
各要素は GET /v1/programs/{id}?fields=full と同じ shape。enriched / source_mentions / lineage 3 キーは null でも必ず存在。dedupe 後の入力 unified_ids 順を保存 |
not_found |
string[] | DB に該当行がなかった ID。部分成功扱いなので 404 ではなく 200 で not_found[] に入る |
重要な契約:
- 順序保証:
results[i].unified_idは dedupe 後のunified_ids[i]と一致する。 - 部分成功: 50 件のうち 3 件が存在しなくても 200 が返り、3 件は
not_found[]に入る。全件無しでも{"results": [], "not_found": [...]}で 200。 - 例外は 500:
not_foundは「DB に存在しない」ケースだけ。JSON decode 失敗等の例外は batch 全体が500で落ちる (部分成功を暗黙に隠さない方針)。 - paging なし: 50-cap がそのまま paging。50 超の ID リストは client 側で
chunk(ids, 50)してループする。
Rate limit: 現在は batch 全体で 1 request 扱い (free: 100/day のうち 1 消費、paid: metered で 1 req 分 ¥0.5 を usage report)。将来的に N 件 × N 単位の課金に移行予定 (launch 後、src/jpintel_mcp/api/programs.py の batch_get_programs TODO 参照)。
Example:
curl -X POST https://api.autonomath.ai/v1/programs/batch \
-H "X-API-Key: jpintel_..." \
-H "Content-Type: application/json" \
-d '{"unified_ids":["UNI-keiei-kaishi-shikin","UNI-koyo-shuno-shikin"]}'
# SDK パターン: search -> batch で 20 件 enrich
import httpx
with httpx.Client(
base_url="https://api.autonomath.ai",
headers={"X-API-Key": "jpintel_..."},
) as client:
search = client.get(
"/v1/programs/search",
params={"q": "IT導入", "fields": "minimal", "limit": 20},
).json()
ids = [row["unified_id"] for row in search["results"]]
detail = client.post(
"/v1/programs/batch",
json={"unified_ids": ids},
).json()
for row in detail["results"]:
print(row["unified_id"], row["primary_name"], row.get("enriched"))
if detail["not_found"]:
print("missing:", detail["not_found"])
Exclusions¶
制度の排他ルール関連。概念は exclusions.md。
GET /v1/exclusions/rules¶
排他ルール全件を返す (現在 35 件: 農業核心 22 + 非農業 IT導入・持続化・M&A 等 13)。
認証: 任意
Response (list[ExclusionRule]):
[
{
"rule_id": "agri-001",
"kind": "mutex",
"severity": "absolute",
"program_a": "keiei-kaishi-shikin",
"program_b": "koyo-shuno-shikin",
"program_b_group": [],
"description": "経営開始資金と雇用就農資金は同時受給不可",
"source_notes": "MAFF 要綱 第3条",
"source_urls": ["https://www.maff.go.jp/..."],
"extra": {}
}
]
フィールド:
| field | type | description |
|---|---|---|
rule_id |
string | ルール一意 ID |
kind |
string | mutex / prerequisite / conditional_reduction など |
severity |
string | null | absolute / conditional など |
program_a |
string | null | 片側の制度 ID |
program_b |
string | null | もう片側の制度 ID (または group を使用) |
program_b_group |
string[] | 複数制度が相手の場合のグループ |
description |
string | null | 人間可読な説明 |
source_notes |
string | null | 出典の簡易メモ |
source_urls |
string[] | 一次資料 URL |
extra |
object | 追加メタ |
POST /v1/exclusions/check¶
候補制度セットに対して排他ルールが triggered するか判定する。
認証: 任意
Request body (ExclusionCheckRequest):
| field | type | required | description |
|---|---|---|---|
program_ids |
string[] | yes (1 件以上) | 制度 ID 配列。重複は自動 dedup |
Response (ExclusionCheckResponse):
{
"program_ids": ["keiei-kaishi-shikin", "koyo-shuno-shikin"],
"hits": [
{
"rule_id": "agri-001",
"kind": "mutex",
"severity": "absolute",
"programs_involved": ["keiei-kaishi-shikin", "koyo-shuno-shikin"],
"description": "同時受給不可",
"source_urls": ["https://www.maff.go.jp/..."]
}
],
"checked_rules": 35
}
判定ロジック:
kind == "mutex"は 2 件以上 selected に含まれると hitkind == "prerequisite"は 1 件でも含まれば hit (順序違反候補としてレポート)
エラー: program_ids が空なら 400 Bad Request。
Example:
curl -X POST -H "X-API-Key: jpintel_..." \
-H "Content-Type: application/json" \
-d '{"program_ids":["keiei-kaishi-shikin","koyo-shuno-shikin"]}' \
https://api.autonomath.ai/v1/exclusions/check
Meta¶
GET /meta¶
データセット全体の統計。ダッシュボード表示や health check 用途。
認証: 任意
Response (Meta):
{
"total_programs": 6771,
"tier_counts": {"S": 59, "A": 525, "B": 3297, "C": 2421, "X": 469},
"prefecture_counts": {"青森県": 42, "_none": 4311, "...": "..."},
"exclusion_rules_count": 35,
"last_ingested_at": "2026-04-22T09:00:00Z",
"data_as_of": "2026-04-21"
}
prefecture_countsの_noneは prefecture=null (全国制度または未ラベル) のバケットlast_ingested_atは DB の最終 ingest 時刻,data_as_ofは元データの基準日
Example:
GET /healthz¶
Liveness probe。DB 接続のみ確認。
認証: 不要
Response:
GET /v1/ping¶
認証付き probe。/healthz は liveness (DB ping のみ) で key 検証をしないため、
「今この key で API に届くか + tier は何か」を 1 本で確認したい時に使う。
認証: 任意 (未認証は free 扱い)
Response:
{
"ok": true,
"authenticated": true,
"tier": "paid",
"server_time_utc": "2026-04-23T14:00:00Z",
"server_version": "0.1.0",
"rate_limit_remaining": null
}
| field | type | description |
|---|---|---|
ok |
bool | 常に true (到達できた時点で) |
authenticated |
bool | 有効な key が提示されたか |
tier |
string | free / paid |
server_time_utc |
string | サーバー時刻 (UTC, YYYY-MM-DDTHH:MM:SSZ) |
server_version |
string | AutonoMath version |
rate_limit_remaining |
int | null | 本日の残り呼び出し数。paid (metered) は null (hard cap なし) |
使用量への影響: /v1/ping は認証付き呼び出しのみ usage_events にカウントされる
(heartbeat で無限に叩かれる濫用を抑止するため)。未認証呼び出しはカウントしない
(per-IP の記録を持たないため)。頻繁に heartbeat したい用途では /healthz を推奨。
匿名時の rate_limit_remaining: 未認証時は free tier の上限値そのものが返る
(per-IP 使用量を記録していないため、正確な残量を返せない)。
Example:
Billing¶
Stripe 経由のサブスクリプション管理。詳細フローは getting-started.md。
POST /v1/billing/checkout¶
Stripe Checkout セッションを作成して URL を返す。
認証: 不要
Request body:
| field | type | required | description |
|---|---|---|---|
success_url |
string | yes | 決済後のリダイレクト先 (session_id を受け取るページ) |
cancel_url |
string | yes | キャンセル時のリダイレクト先 |
customer_email |
string | no | Stripe に事前に渡すメールアドレス |
tier フィールドは存在しない (pure metered、Price は 1 本: STRIPE_PRICE_PER_REQUEST 環境変数で指定)。
Response:
エラー: Stripe 未設定時は 503。
POST /v1/billing/portal¶
Stripe Customer Portal URL を返す (サブスク変更・キャンセル・カード変更用)。
認証: 不要 (customer_id を body に渡す)
Request body:
Response:
POST /v1/billing/keys/from-checkout¶
Checkout 成功後に API key を発行する。1 session につき 1 回のみ。
認証: 不要 (Stripe session 検証で認証)
Request body:
Response:
エラー:
402 Payment Required— session が paid になっていない409 Conflict— 同 subscription で既に key 発行済み (rotation は/v1/billing/portal経由)
POST /v1/billing/webhook¶
Stripe webhook 受け口。以下のイベントを処理:
customer.subscription.created— 初回サブスク時に API key を自動発行 (主経路)invoice.paid— safety net として同じく key 発行 (subscription.created を取りこぼした場合)customer.subscription.updated— 状態同期customer.subscription.deleted— key の revoke (Free tier に戻る)invoice.payment_failed— 支払い失敗の記録
認証: Stripe 署名 (stripe-signature header) で検証
Response: {"status": "received"}
エンドユーザーが直接叩くものではない。
Feedback¶
POST /v1/feedback¶
開発者向けの feedback 受け口。変なレスポンスを見つけた時・命名案がある時に、 GitHub issue を開く前に 1 POST で送れる軽量窓口。
認証: 任意 (未認証でも OK)。key を付ければ customer_id + tier が紐付く。
Request body (FeedbackRequest):
{
"message": "search で 認定新規就農者 が Hit しない件",
"rating": 3,
"endpoint": "/v1/programs/search",
"request_id": "abcd1234"
}
| field | type | required | description |
|---|---|---|---|
message |
string | yes | 1〜4000 文字。自由記述 |
rating |
int | no | 1〜5 (満足度) |
endpoint |
string | no | 関連エンドポイント (例: /v1/programs/search) |
request_id |
string | no | x-request-id header の値など |
Response (FeedbackResponse):
Rate limit: 1 日あたり 10 件 per API key (認証時) または per IP hash (未認証時)。
超過時は 429 Too Many Requests。
保存される情報:
message,rating,endpoint,request_id(上記入力)- 認証時:
key_hash,customer_id,tier ip_hash(raw IP は保存しない / HMAC-SHA256 with salt)created_at(UTC ISO)
Example:
curl -X POST https://api.autonomath.ai/v1/feedback \
-H "X-API-Key: jpintel_..." \
-H "Content-Type: application/json" \
-d '{"message":"tier=X の理由が見えづらい","rating":4}'
エラー形式 (Error format)¶
FastAPI 標準:
| code | 意味 |
|---|---|
| 400 | リクエスト不正 (params / body) |
| 401 | 認証失敗 / revoked key |
| 402 | Stripe 決済未完了 |
| 404 | リソース無し |
| 409 | 重複操作 (key 発行済み等) |
| 429 | rate limit 超過 |
| 503 | Stripe 未設定など運用外状態 |
Admin (internal)¶
運営者向けの funnel / cohort / error endpoint 群 (/v1/admin/*) は非公開。別 key (ADMIN_API_KEY) で認証し、OpenAPI export (docs/openapi/v1.json, SDK 生成) には含めない (include_in_schema=False)。SLA / versioning policy の対象外で、/v1/* 安定契約の一部ではない。
仕様: 内部 docs/_internal/admin_api.md 参照 (non-public、repo-only)。
関連¶
- mcp-tools.md — 同じ機能を MCP tool として叩く
- exclusions.md — 排他ルールの概念
- pricing.md — tier 別制限
docs/_internal/admin_api.md— 内部用 admin endpoint (non-public、repo-only)- サンプル集 — 8 本の runnable サンプル (Python 4 + TypeScript 4, 各ファイル 50-150 行)