mcpField
C
cryptorefills-x402

cryptorefills-x402

github.com/cryptorefillsその他094 回インストール9 週間前に更新
リポジトリ

cryptorefills-x402 について

cryptorefills-x402は、AIエージェントがアカウントやAPIキーなしで、USDCを使ってCryptorefillsの商品を購入するためのスキルです。BaseとSolanaの決済フローに対応し、支払い要件の検証と署名・支出の保護策を備えています。

主な機能

  1. 01ブランドと商品カタログの閲覧
  2. 02USDCによる注文
  3. 03BaseまたはSolana決済の選択
  4. 04署名付き支払い要件の検証
  5. 05注文の配送状況確認

活用シーン

  1. 01ギフトカードの自動購入
  2. 02旅行用eSIMの手配
  3. 03プログラムによる報酬の提供
  4. 04レジストリー経由のSolana決済

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cryptorefills/agents --skill cryptorefills-x402

インストール後、Claude Code で/cryptorefills-x402を入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
endpoints.md
protocol.md
troubleshooting.md

詳細

Cryptorefills x402 — 自律型エージェントコマース

暗号資産ウォレットを持つ AI エージェントによる、完全自律型の購入を実現します。アカウントも OAuth も API キーも不要です。必要なのはステーブルコインと署名キーだけです。

x402 プロトコルを基盤としています。HTTP 402 Payment Required を、マシン間決済の標準として利用します。決済レールは Base(Ethereum L2 上の USDC、デフォルト)と Solana(Solana メインネット上の USDC SPL、オプトイン)の 2 つに対応しています。

複数の決済方法で人間が購入をガイドする場合は、代わりに cryptorefills-buy に従ってください。 カタログを閲覧するだけの場合は、代わりに cryptorefills-catalog に従ってください。

決済レールを選択する

レールホストPhase-1 ヘッダーウォレット資産ネイティブガス
Base(デフォルト)x402.cryptorefills.comなし、または X-Preferred-Network: baseEVM、EIP-712 対応USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913、チェーン 8453不要 — Cryptorefills が中継
Solanax402.cryptorefills.comX-Preferred-Network: solanaSolana キーペアUSDC SPL ミント EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v不要 — CDP ファシリテーターが SOL を支払います
Solana(ホスト固定)solana.x402.cryptorefills.com省略、または solana のみSolana キーペア同上不要

デフォルトレールの推奨。 エージェントが両方のレールでウォレットを持ち、外部の制約がない場合は、Base を使用してください。EIP-712 ツールの選択肢がより広く、決済期限が長く(Solana の約 60 秒に対して約 15 分)、v1.0 以降、EVM のみを使用するエージェントが利用してきたものとバイト単位で同一のコントラクトを使用できます。エージェントがすでに Solana を利用している場合、SOL の使用回避が重要な場合、またはレジストリ/マーケットプレイス(例:pay-skills)がデフォルトで Solana メインネットの 402 チャレンジを要求する場合は、Solana を使用してください。その場合は solana.x402.cryptorefills.com ホストを使用すると、レールがホストに固定され、曖昧さがなくなります。

有効化する場合

  • エージェントが Base(USDC、EIP-712)または Solana(USDC SPL、v0 トランザクションの部分署名が可能)にウォレットを持っている
  • 人間による決済操作なしで自律的に購入する必要がある
  • アカウント設定、OAuth フロー、API キー管理が不要である
  • キーワード:「USDC で購入」「USDC SPL」「自律型購入」「エージェントコマース」「x402 決済」「プログラムによるギフトカード購入」「Solana mainnet-beta」「partial-sign」「VersionedTransaction」「compute-budget」「pay-skills レジストリ」「SOL 不要」「ETH 不要」
  • ユースケース:ギフトカードの自動調達、旅行用 eSIM の提供、プログラムによる報酬、レジストリ主導の Solana 決済

要件

Base レール
要件詳細
Base 上の USDCチェーン 8453、コントラクト 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
EIP-712 署名transferWithAuthorization(EIP-3009)の型付きデータに署名します
ガス用 ETH不要 — Cryptorefills がオンチェーンで認証を中継します
HTTP クライアント標準的な REST API 呼び出し
アカウント不要
Solana レール
要件詳細
Solana メインネット上の USDC SPLミント EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v、小数点以下 6 桁
Solana キーペア64 バイトの Ed25519 シークレット(Phantom/Solflare のエクスポート形式に対応)
Solana RPC アクセス最新の recentBlockhash を取得するために必要です。デフォルトは https://api.mainnet-beta.solana.com です。信頼性の高い RPC であれば使用できます
v0 トランザクション署名正規の 3 命令構成で VersionedTransaction を構築し、部分署名します — protocol.md を参照してください
ガス用 SOL不要 — CDP ファシリテーターが自身のプールから SOL のガス代を支払います
HTTP クライアント標準的な REST API 呼び出し
アカウント不要

支出の保護策

実際のお金を使う自律エージェントには、厳格な管理が必要です。

  • 開始前にセッションごとの支出上限を設定します(デフォルト:セッションごとの上限は最大 $100、取引ごとの上限は最大 $50。ユーザーから明示的な依頼があった場合に限り引き上げます)。
  • 署名する前に、402 レスポンスから注文金額を確認します。決して確認せずに署名しないでください。
  • レールごとに専用ウォレットを用意し、必要な額のステーブルコインのみを保有させます。
  • ウォレットの秘密鍵/シークレットをログに記録、公開、共有しないでください。環境変数またはシークレットマネージャーを使用します。
  • すべての取引を記録します:order_id、商品、金額、ウォレットアドレス、レール、取引署名/ハッシュ。
  • 402 レスポンスの maxAmountRequired を超える額に署名しないでください。
  • 何かに署名する前に、402 を認証します。 payTo はセッションごとの入金ウォレットです。マニフェストには入金ウォレットが記載されていないため、許可リストの使用は不可能です。その代わり、各 402 にはゲートウェイによって署名された JWS(ES256)である X-Payment-Required-Signature が含まれます。マニフェストの attestation.keys/attestation.jwks_uri にあるキー(マニフェストと同じオリジン)を使って検証し、次の条件を満たすことを確認してください:iss == POST 先のオリジン、sid == X-Session-Id ヘッダー、pr_sha256 == base64url(sha256(PAYMENT-REQUIRED ヘッダー値を受信したままの状態で使用))、pay_to/network == デコードした accepts[0] の値、exp が未来の時刻であること。ヘッダーがない場合、またはいずれかの確認に失敗した場合は、402 を拒否し、署名しないでください。 詳細な手順と verify402() のコード例:references/protocol.md → 402 アテステーションの検証。

Solana 固有の注意事項:

  • payTo は OWNER の公開鍵であり、ATA ではありません。 (payTo, mint) から受取人の ATA を導出してください。payTo を ATA として扱って送金に署名すると失敗します。
  • 部分署名の前に、extra.feePayer が PAYMENT-REQUIRED の値と一致することを確認します。さらに、その値をトランザクションの payerKey として使用します。
  • 部分署名の直前に recentBlockhash を再取得します。 有効期間は約 60 秒です。ゲートウェイはこれを示すため maxTimeoutSeconds を 60 に制限します。Solana では Phase 1 と Phase 2 の間にユーザーへのプロンプトを挟まないでください。
  • シリアライズする前に、構築したトランザクションの命令が正確に 3 つであることを確認します(compute-unit limit、compute-unit price、TransferChecked)。
  • SPL の TransferChecked(タグ 0x0c)を使用し、Transfer(0x03)は使用しないでください。 通常の Transfer は CDP により unknown_error で拒否されます。

一般事項:

  • ギフトカードコード(voucher_code)は現金同様に扱います。安全に保管し、公開したりログに記録したりしないでください。
  • デジタル商品は、配達後の返品・返金ができません。
  • 利用規約:https://www.cryptorefills.com/terms/

マニフェストは各ホストの /.well-known/x402.json で配信され、attestation ブロック(署名キー、jwks_uri、検証手順)が含まれています。Phase 1 で使用した同じホストからマニフェストを読み込んでください。iss はそのオリジンと一致する必要があり、jwks_uri も同じオリジンでなければなりません。

Phase 2 は必ず Phase 1 と同じホストに送信してください。 X-Session-Id のセッションはホストに紐付けられています。別のホストに POST すると、セッションの検索に失敗するおそれがあります。

基本的なワークフロー

GET  /v1/brands          → discover brands
GET  /v1/catalog         → get products and prices
POST /v1/orders          → 402 + PAYMENT-REQUIRED + X-Session-Id + X-Payment-Required-Signature
   ↓ verify the attestation (JWS) — reject the 402 if it is missing or invalid
   ↓ sign (EIP-712 for Base, partial-sign v0 tx for Solana)
POST /v1/orders          → submit with PAYMENT-SIGNATURE [+ X-Session-Id] → 200
GET  /v1/orders/{id}     → poll until delivered

フロー、REST コントラクト、注文/配達モデルは、どちらのレールでも同一です。異なるのは Phase 1 のヘッダー選択、PAYMENT-REQUIRED の extra ブロック、署名方式のみです。

手順

1. ブランドを閲覧する
GET /v1/brands?country_code=us

指定した国で利用可能なブランドを返します。各エントリには brand_name、family、category、min、max が含まれます。

国コードには、レールにかかわらず ISO 3166-1 Alpha-2 の小文字(us、it、br)を使用します。カタログまたは購入スキルから国コードを受け取った場合(これらでは大文字が使用されています)、x402 エンドポイントを使用する前に小文字に変換してください。

2. カタログを取得
GET /v1/catalog?country_code=us&brand_name=Amazon.com

product_id、is_range、currency、price_usdc、およびdenomination(固定)またはmin_value/max_value(範囲)を含む商品を返します。

  • 固定商品(is_range: false):product_idをそのまま使用します。product_valueは省略します。額面はcurrency単位のdenominationです。
  • 範囲商品(is_range: true):希望額をブランドの現地通貨であるcurrency単位(USDではありません)でitems[].product_valueに設定します。たとえば、currency: "EUR"の€5のAmazon.nlカードの場合、product_value: 5を送信します。402レスポンスで、実際の決済に必要なUSDC額が提示されます(通常はprice_usdcにわずかな上乗せまたは差し引きがあります)。
注文前の確認:ステーブルコイン残高を確認

注文する前に、選択したレールでウォレットに十分なステーブルコインがあることを確認します。

  • Base:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913のbalanceOf(walletAddress)を呼び出します。
  • Solana:送信者のATAでgetTokenAccountBalanceを呼び出します — getAssociatedTokenAddress(mint=EPjF…WEGGkZwyTDt1v, owner=agent)。SOL残高は不要です。

カタログのprice_usdcは参考値です。正確な金額は402レスポンスで確定します。

3. 注文を作成 — フェーズ1(支払い要件を取得)

Base(デフォルト):

curl -X POST https://x402.cryptorefills.com/v1/orders \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "items": [{
      "product_id": "abc123",
      "beneficiary_account": "[email protected]",
      "product_value": 25
    }]
  }'
# → HTTP 402 with PAYMENT-REQUIRED, X-Session-Id and X-Payment-Required-Signature headers

Solana(ヘッダーで有効化):

curl -X POST https://x402.cryptorefills.com/v1/orders \
  -H "Content-Type: application/json" \
  -H "X-Preferred-Network: solana" \
  -d '<same body>'

Solana(ホスト固定):

curl -X POST https://solana.x402.cryptorefills.com/v1/orders \
  -H "Content-Type: application/json" \
  -d '<same body>'

範囲商品の場合はproduct_valueが必須です。固定額面の商品では省略します。オプション:ポーリングの代わりにWebhookで配信通知を受け取る場合は、"callback_url": "https://..."を追加します。

次の3つのレスポンスヘッダーを取得します:

  • PAYMENT-REQUIRED — 支払い要件を含むbase64urlエンコード済みJSON(レールごとの形式は以下を参照)。
  • X-Session-Id — UUID。フェーズ2でそのまま返します(Solanaでは必須、Baseでは任意)。
  • X-Payment-Required-Signature — 上記2つのヘッダーを証明するJWS(iss、sid、pr_sha256、pay_to、network、exp)。署名の前に検証してください — references/protocol.mdを参照してください。ヘッダーがない場合は、402が失敗したものとして扱います。
PAYMENT-REQUIRED — Baseの例
{
  "x402Version": 2,
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",
    "maxAmountRequired": "25000000",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "extra": { "name": "USD Coin", "version": "2", "decimals": 6 },
    "payTo": "0x...",
    "description": "$25.00 Amazon Gift Card"
  }],
  "expiresAt": 1830000000
}
BaseとのSolanaの差分(Solanaの全例はprotocol.mdを参照)
BaseSolana
networkeip155:8453solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp(完全なCAIP-2)
assetEVMコントラクトSPLミント、base58(USDCの場合はEPjF…WEGGkZwyTDt1v)
extra{name, version, decimals}{feePayer} — payerKeyとして使用
payTo受取人のウォレット受取人のOWNER公開鍵(ATAはファシリテーター側で導出)
expiresAtウィンドウ約15分約60秒
4. 支払いに署名
Base — EIP-712 / EIP-3009

transferWithAuthorizationの型付きデータに署名します。

ドメイン:Base上のUSDCコントラクト。 型:TransferWithAuthorization(address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce)。

フィールド値
fromお客様のウォレットアドレス
to402レスポンスのpayTo
value402レスポンスのmaxAmountRequired
validAfter0
validBefore402レスポンスのexpiresAt(Unix秒)
nonceランダムな32バイトの16進数

EIP-712の型付きデータ構造の詳細は、references/protocol.mdを参照してください。

Solana — v0トランザクションに部分署名

v0 VersionedTransactionを順序どおりに正確に3つの命令で構築します:ComputeBudget set-limit(200_000 units)→ ComputeBudget set-price(1000 microLamports)→ SPL createTransferCheckedInstruction(タグ0x0c、Transferの0x03ではありません)。mint = asset、senderAta = getAssociatedTokenAddress(mint, signer)、recipientAta = getAssociatedTokenAddress(mint, payTo)(payToはowner)、payerKey = extra.feePayerを使用します。Solana RPCから新しいrecentBlockhashを取得します。tx.sign([signer])で部分署名し、feePayerスロットはCDP用に残します。シリアライズ後のサイズは1232バイト以下にします。

手順の全体はreferences/protocol.mdを参照してください。

5. 注文を完了 — フェーズ2

PAYMENT-SIGNATUREを付けて同じ本文を再度POSTします。フェーズ1のX-Session-Idをそのまま返します(Solanaでは必須)。

Base
curl -X POST https://x402.cryptorefills.com/v1/orders \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: <base64url-encoded JSON>" \
  -d '<same body as phase 1>'
# → HTTP 200

PAYMENT-SIGNATUREのペイロード(その後、JSONをbase64urlエンコードします):

{
  "x402Version": 2,
  "scheme": "exact",
  "network": "eip155:8453",
  "payload": {
    "signature": "0x...",
    "authorization": {
      "from": "0xYourWallet",
      "to": "0xPayToAddress",
      "value": "25000000",
      "validAfter": "0",
      "validBefore": "1830000000",
      "nonce": "0xRandomBytes32"
    }
  }
}
Solana
curl -X POST https://x402.cryptorefills.com/v1/orders \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: <base64url-encoded JSON>" \
  -H "X-Session-Id: <UUID from Phase 1 response>" \
  -d '<same body as phase 1>'
# → HTTP 200

PAYMENT-SIGNATURE ペイロード(外側の JSON を base64url エンコードします。内側の payload.transaction は通常の base64 です):

{
  "x402Version": 2,
  "scheme": "exact",
  "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
  "payload": {
    "transaction": "<plain-base64 of serialized v0 transaction>"
  }
}

エンコード規則。 両方のレールで、外側の PAYMENT-SIGNATURE ラッパーは base64url です。Solana では、内側の payload.transaction フィールドのみ通常の base64 です(Solana エコシステムの規約。ファシリテーターにそのまま渡される不透明なデータです)。両者を統一しないでください。

サーバーは HTTP 200 で応答します:

{
  "order_id": "cr_abc123",
  "status": "processing",
  "estimated_delivery_seconds": 60,
  "poll_url": "/v1/orders/cr_abc123"
}
6. 配送を追跡する
GET /v1/orders/{order_id}

status が completed または failed になるまで、5~10 秒ごとにポーリングします。10 分経過したらポーリングを停止し、注文が滞留している可能性があることを報告してください。order_id を添えて [email protected] にお問い合わせください。

completed になると、deliveries 配列に次の情報が含まれます:

  • voucher_code — ギフトカードの引き換えコード
  • pin — 必要な場合の PIN
  • url — 該当する場合の引き換え URL
  • brand_name、product_name — 購入した商品

実例:Solana で €5 の Amazon.nl ギフトカードを購入する

手順ごとの説明を組み合わせた、エンドツーエンドの確認です。実際の数値を使用し、ウォレットは匿名化しています。

# 1. Discover Amazon.nl
curl 'https://x402.cryptorefills.com/v1/brands?country_code=nl' | jq '.[] | select(.family|test("Amazon"))'
#   → {"brand_name":"Amazon.nl","family":"Amazon.nl","category":"e-commerce", ...}

# 2. Find a range product priced in EUR
curl 'https://x402.cryptorefills.com/v1/catalog?country_code=nl&brand_name=Amazon.nl' | jq '.[0]'
#   → {"product_id":"amzn-nl-range","is_range":true,"currency":"EUR",
#      "min_value":5,"max_value":500,"price_usdc":"5.42", ...}
#   1 EUR isn't offered (min is 5 EUR) — pick 5 EUR.

# 3. Phase 1 — opt into Solana
curl -i -X POST https://x402.cryptorefills.com/v1/orders \
  -H "Content-Type: application/json" \
  -H "X-Preferred-Network: solana" \
  -d '{"email":"[email protected]",
       "items":[{"product_id":"amzn-nl-range",
                 "beneficiary_account":"[email protected]",
                 "product_value":5}]}'
#   → HTTP/1.1 402
#      X-Session-Id: 3f9c1a8b-...           ← capture, echo on Phase 2
#      PAYMENT-REQUIRED: <base64url JSON>   ← decode for accepts[0]
#      X-Payment-Required-Signature: <JWS>  ← verify first (protocol.md → Verifying the 402 attestation)
#
#   accepts[0] decoded:
#     network:           solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
#     asset:             EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
#     maxAmountRequired: "5420000"          ← 5.42 USDC
#     payTo:             <owner pubkey>     ← derive recipient ATA from this
#     extra.feePayer:    <CDP pubkey>       ← use as transaction.payerKey
// 4. Decode PAYMENT-REQUIRED, verify budget, build the partial-signed v0 tx
import {ComputeBudgetProgram, Connection, Keypair, PublicKey,
        TransactionMessage, VersionedTransaction} from '@solana/web3.js';
import {createTransferCheckedInstruction, getAssociatedTokenAddress} from '@solana/spl-token';
import bs58 from 'bs58';

// 4a. Parse the 402 response
const paymentRequired = JSON.parse(
  Buffer.from(phase1Headers['payment-required'], 'base64url').toString());
const sessionId = phase1Headers['x-session-id'];
const {payTo, asset, maxAmountRequired, extra} = paymentRequired.accepts[0];

// 4b. Spending-safeguard checks BEFORE signing
const SPEND_LIMIT_ATOMIC = BigInt(50_000_000);              // $50 = 50e6 atomic USDC
if (BigInt(maxAmountRequired) > SPEND_LIMIT_ATOMIC) throw new Error('over budget');
if (asset !== 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v') throw new Error('wrong mint');

// 4c. Build the transaction
const signer       = Keypair.fromSecretKey(bs58.decode(process.env.SOLANA_SIGNER_KEY));
const conn         = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');
const mint         = new PublicKey(asset);
const owner        = new PublicKey(payTo);                  // OWNER, not an ATA
const feePayer     = new PublicKey(extra.feePayer);         // CDP signs this slot

const senderAta    = await getAssociatedTokenAddress(mint, signer.publicKey);
const recipientAta = await getAssociatedTokenAddress(mint, owner);
const {blockhash}  = await conn.getLatestBlockhash('finalized');  // 'finalized' is older but accepted by all validators — reduces timing sensitivity

const message = new TransactionMessage({
  payerKey:        feePayer,
  recentBlockhash: blockhash,
  instructions: [
    ComputeBudgetProgram.setComputeUnitLimit({units: 200_000}),
    ComputeBudgetProgram.setComputeUnitPrice({microLamports: 1000}),
    createTransferCheckedInstruction(senderAta, mint, recipientAta,
                                     signer.publicKey, BigInt(maxAmountRequired), 6),
  ],
}).compileToV0Message();

const tx = new VersionedTransaction(message);
tx.sign([signer]);                                    // partial — leaves feePayer slot
// Assert on the pre-compilation array — MessageV0 exposes `compiledInstructions`, not `instructions`.
// Reading `tx.message.instructions` throws TypeError. Use the source array passed to TransactionMessage.
if (message.version !== 0) throw new Error('expected v0 message');
if (tx.message.compiledInstructions.length !== 3) throw new Error('expected exactly 3 instructions');
if (tx.serialize().length > 1232) throw new Error('tx too large');

const txB64       = Buffer.from(tx.serialize()).toString('base64');     // inner: plain base64
const inner       = {x402Version: 2, scheme: 'exact',
                     network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
                     payload: {transaction: txB64}};
const headerValue = Buffer.from(JSON.stringify(inner)).toString('base64url');  // outer: base64url
# 5. Phase 2 — same host as Phase 1, echo X-Session-Id from step 3
curl -X POST https://x402.cryptorefills.com/v1/orders \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: <headerValue from step 4c>" \
  -H "X-Session-Id: <sessionId from step 4a>" \
  -d '<same body as Phase 1>'
#   → HTTP/1.1 200
#      {"order_id":"cr_xxx","status":"processing","poll_url":"/v1/orders/cr_xxx", ...}

# 6. Poll
curl https://x402.cryptorefills.com/v1/orders/cr_xxx
#   → {"status":"completed",
#      "deliveries":[{"voucher_code":"XXXX-YYYY-ZZZZ","brand_name":"Amazon.nl", ...}]}

手順 1~6 をシナリオに適用しても組み合わせられない場合は、references/troubleshooting.md に失敗の詳細が記載されています。

フィールド名の対応(x402 と MCP)

x402 と MCP のスキルを切り替える場合は、次のフィールド名の違いに注意してください。

概念x402(このスキル)MCP(cryptorefills-buy)
ギフトカードコードvoucher_codedeliverable.pin_code
PINpin(独立したフィールド)pin_code に含まれる
注文ステータスstatus(単一フィールド)order_state + payment_state
注文 ID の形式cr_ 付きUUID

重大な注意点

両方のレール
  • 国コード:x402 エンドポイントでは小文字です(US ではなく us)。MCP スキルでは大文字を使用します。エンドポイントが異なるため、ルールも異なります。
  • ブランド名:大文字と小文字が区別されます。/v1/brands の応答に記載されている正確な値を使用してください。
  • X-Preferred-Network の値:大文字と小文字が区別される小文字のみで、base または solana に限ります。複数レール対応ホストでは、Base または Solana(先頭大文字)を指定すると 400 invalid_network が返されます。
  • 金額の精度:402 の maxAmountRequired と完全に一致させてください。丸めたり変更したりしないでください。
  • 外側のエンコード:両方のレールで、PAYMENT-SIGNATURE の外側のラッパーは base64url です(ゲートウェイのデコーダーに適合します)。
  • レールの混在禁止:セッションで使用するレールはフェーズ 1 で選択したものに固定されます。フェーズ 2 でレールを切り替えないでください。
  • フェーズ 2 は同じホストに送信:フェーズ 1 で使用したのと同じホストに、フェーズ 2 の POST を送信してください。セッションはホストに紐付けられています。
  • 署名なしの 402:X-Payment-Required-Signature がない 402、または署名検証に失敗した 402 は拒否しなければなりません。「TLS 接続に問題がなさそうだった」という理由で処理を続行してはいけません。受信したままの PAYMENT-REQUIRED ヘッダー文字列をハッシュ化してください。デコードした JSON を再シリアライズしてはいけません。
Base
  • USDC コントラクト:Base では、必ず 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 と完全に一致させてください。
  • チェーン ID:8453(Base メインネット)である必要があります。チェーンが異なると署名は無効です。
  • 支払いのタイムアウト:402 の expiresAt フィールドに期限が示されます(約 15 分)。期限切れ前に署名して再送信してください。
  • Nonce:トランザクションごとに一意である必要があります。暗号学的に安全なランダム値を 32 バイト使用してください。
  • EIP-712 ドメイン:Base 上の USDC コントラクトのドメインセパレーターと一致させる必要があります。
Solana
  • ネットワーク文字列:"solana" や "solana-mainnet" ではなく、完全な CAIP-2 solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp を指定する必要があります。
  • payTo は OWNER の公開鍵であり、ATA ではありません。 ファシリテーターは (owner, mint) から受取人の ATA を導出します。
  • Transfer(0x03)ではなく、TransferChecked(0x0c)を使用します。 CDP は前者を unknown_error で拒否します。
  • 命令は順序どおりに正確に 3 つ:ComputeBudget の set-limit、ComputeBudget の set-price、TransferChecked。CDP では 3~6 個が適用されます。
  • payerKey = PAYMENT-REQUIRED の extra.feePayer です。CDP は settle 時にこのスロットに署名し、SOL のガス代を支払います。
  • トランザクションパケットの上限:1232 バイト。標準的な 3 命令の形式なら十分に収まります。
  • ブロックハッシュの有効期間:約 60 秒。部分署名の直前に再取得してください。Phase 1 と Phase 2 の間にユーザープロンプトを挟まないでください。
  • Phase 1 のレスポンスに含まれる X-Session-Id を Phase 2 でエコーしてください。必須です(SPL トランザクションは不透明なため、ゲートウェイがセッションを参照するほかの方法はありません)。
  • 内部エンコーディング:PAYMENT-SIGNATURE JSON 内の payload.transaction は通常の base64(Solana の規約)です。外側のラッパーのみ base64url です。

参考資料

このスキルファイルに記載された内容より詳しい情報が必要な場合にのみ、参考資料を読み込んでください。

ファイル読み込むタイミング内容
references/protocol.md正確な署名手順(Base の EIP-712 ドメイン/型、または Solana の完全な VersionedTransaction 構築方法)や 402 アテステーション検証器が必要な場合2 フェーズのフロー、ヘッダー、レールごとの PAYMENT-REQUIRED の形式、X-Payment-Required-Signature の検証(verify402)、Base の EIP-712/EIP-3009 の詳細、Solana の 3 命令の手順
references/endpoints.mdAPI 呼び出しの正確なリクエスト/レスポンススキーマが必要な場合REST API リファレンス、Hosts テーブル、すべてのヘッダーの一覧、エラーレスポンスコード
references/troubleshooting.mdリクエストが失敗する、または予期しないステータスが返される場合レールごとのエラーカタログと復旧パターン

コメント