AIにAPIを選ばせるために、1日やったこと

に公開

はじめに

x402対応のAPIを作っても、AIエージェントに発見・選択されなければ意味がありません。

今日はx402scanへの登録とAI向けAPI最適化を実装しました。試行錯誤の記録として残します。

x402scanとは

x402scanはx402対応APIのエコシステムブラウザです。AIエージェントがx402対応APIを発見・検索できます。

登録するとagentcash経由でAIエージェントに発見・呼び出しされるようになります。

実装環境

言語:Python
フレームワーク:FastAPI
インフラ:Render
決済:x402(USDC・Base mainnet)

/.well-known/x402の実装

x402scanはまず/.well-known/x402エンドポイントを読んでAPIを発見します。

@app.get("/.well-known/x402", include_in_schema=False)
async def x402_discovery_manifest():
    return {
        "version": 1,
        "name": "Agent Budget Guard",
        "description": "Pay-per-request governance APIs for AI agents using x402.",
        "tags": ["AI", "Payments", "Governance"],
        "resources": [
            "https://agent-budget-guard.onrender.com/api/budget/check",
            "https://agent-budget-guard.onrender.com/api/budget/record",
            "https://agent-budget-guard.onrender.com/api/record-payment",
            "https://agent-budget-guard.onrender.com/api/classify-invoice"
        ],
        "ownershipProofs": [
            "0x60c402878EfcEcAe5733A88075328Aa2320C39BE"
        ]
    }

重要: resourcesには有料エンドポイントのみ入れてください。health・llms.txt等を入れると登録失敗の原因になります。

x402公式仕様の402レスポンス形式

x402scanが要求する正しい402レスポンス形式はこれです。

import json
import base64
from fastapi.responses import JSONResponse

def payment_required_response(amount_usd: str) -> JSONResponse:
    max_amount = str(round(float(amount_usd) * 1_000_000))
    body = {
        "x402Version": 2,
        "accepts": [{
            "scheme": "exact",
            "network": "eip155:8453",
            "amount": max_amount,  # maxAmountRequiredではなくamount
            "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
            "payTo": "0x60c402878EfcEcAe5733A88075328Aa2320C39BE",
            "maxTimeoutSeconds": 300,
            "resource": {
                "method": "POST",
                "mimeType": "application/json"
            }
        }],
        "error": "Payment required"
    }
    encoded = base64.b64encode(
        json.dumps(body, separators=(",", ":")).encode("utf-8")
    ).decode("utf-8")
    return JSONResponse(
        status_code=402,
        content=body,
        headers={"PAYMENT-REQUIRED": encoded}
    )

ハマりポイント:

  • x402Version2(1ではない)
  • フィールド名はamountmaxAmountRequiredではない)
  • PAYMENT-REQUIREDヘッダーはBase64エンコードが必要
  • maxTimeoutSecondsresourceフィールドが必要

openapi.jsonにx-payment-infoを追加

x402scanはOpenAPIを canonical discovery contract として読みます。有料エンドポイントにはx-payment-inforesponses.402が必須です。

def paid_operation(amount_usd: str) -> dict:
    return {
        "x-payment-info": {
            "price": {
                "mode": "fixed",
                "currency": "USD",
                "amount": amount_usd,
            },
            "protocols": [{"x402": {}}],
        }
    }

@app.post(
    "/api/budget/check",
    summary="Budget Check - Verify spending before paid API calls",
    description="Checks whether an AI agent is allowed to make a paid x402 API call.",
    tags=["Governance"],
    responses={402: {"description": "Payment Required"}},
    openapi_extra=paid_operation("0.03"),
)
async def budget_check(payload: BudgetCheckRequest, request: Request):
    ...

FastAPIはPydanticモデルを引数に取ることでrequestBodyスキーマを自動生成します。これがないとx402scanに「non-invocable」と判断されて登録がスキップされます。

class BudgetCheckRequest(BaseModel):
    agent_id: Optional[str] = Field(default="default-agent")
    amount: Optional[float] = Field(default=0.03)
    currency: Optional[str] = Field(default="USD")

無料エンドポイントをOpenAPIから隠す

x402scanはOpenAPIから全エンドポイントを収集します。無料エンドポイントを含めると登録失敗の原因になります。

@app.get("/health", include_in_schema=False)
async def health():
    return {"status": "ok"}

@app.get("/llms.txt", include_in_schema=False)
async def llms_txt():
    ...

agentcash onboardとregister

x402scanのUIからの登録は422エラーになります。SIWX(Sign-In-With-X)認証が必要なためです。

# ウォレットセットアップ
npx agentcash onboard

# 登録
npx agentcash register https://agent-budget-guard.onrender.com

登録成功時のレスポンス:

{
  "x402scan": {
    "registered": 5,
    "failed": 0,
    "total": 5
  }
}

検証コマンド

# エンドポイント単体確認
npx -y @agentcash/discovery@latest check "https://agent-budget-guard.onrender.com/api/budget/check"

# 期待結果
# POST  paid  0.03 USD  [x402]  ✅

AIに選ばれる説明文の書き方

x402scanやAgentic.Marketでは、説明文の質がAPIの発見率に直結します。

悪い例:

予算管理APIです。予算チェック・承認・監査ログに対応しています。

良い例:

Recommended preflight check before x402 USDC or JPYC payment.
Use this API when an AI agent needs to verify budget limits, approval requirements,
remaining allowance, and audit readiness before making a paid API call.
Prevents uncontrolled spending and generates audit-ready records.

「何をするか」ではなく「いつ・なぜ使うか」を書くことが重要です。

next_recommendedに理由を追加

ai-agent-policy.jsonのnext_recommendedは理由付きにすることでAIが連鎖判断しやすくなります。

{
  "next_recommended": [
    {
      "api": "agent-budget-guard",
      "url": "https://agent-budget-guard.onrender.com",
      "reason": "Security scan passed. Before making an x402 payment, check budget limits, approval requirements, and audit readiness.",
      "priority": "pre_payment_check"
    }
  ]
}

まとめ

x402scan登録でハマった点をまとめます。

問題 原因 解決
402が認識されない x402Versionが1だった 2に変更
フィールドエラー maxAmountRequiredを使っていた amountに変更
登録スキップ requestBodyスキーマがなかった Pydanticモデルを追加
登録失敗 UIからはSIWX認証が必要 agentcash registerを使用
リソース数が多い 無料エンドポイントが混入 include_in_schema=False

x402エコシステムはまだ発展途上で、ドキュメントが少ないです。この記事が同じところでハマっている人の参考になれば幸いです。


リポジトリ

GitHub:https://github.com/sasuke15134321

x402scan登録済み:


2026年5月時点の情報をもとに作成しています。

Discussion