cryptorefills-x402 について
cryptorefills-x402は、AIエージェントがアカウントやAPIキーなしで、USDCを使ってCryptorefillsの商品を購入するためのスキルです。BaseとSolanaの決済フローに対応し、支払い要件の検証と署名・支出の保護策を備えています。
主な機能
- 01ブランドと商品カタログの閲覧
- 02USDCによる注文
- 03BaseまたはSolana決済の選択
- 04署名付き支払い要件の検証
- 05注文の配送状況確認
活用シーン
- 01ギフトカードの自動購入
- 02旅行用eSIMの手配
- 03プログラムによる報酬の提供
- 04レジストリー経由のSolana決済
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cryptorefills/ agents --skill cryptorefills-x402インストール後、Claude Code で/cryptorefills-x402を入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/endpoints.mdprotocol.mdtroubleshooting.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: base | EVM、EIP-712 対応 | USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913、チェーン 8453 | 不要 — Cryptorefills が中継 |
| Solana | x402.cryptorefills.com | X-Preferred-Network: solana | Solana キーペア | 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を参照)
| Base | Solana | |
|---|---|---|
network | eip155:8453 | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp(完全なCAIP-2) |
asset | EVMコントラクト | 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 | お客様のウォレットアドレス |
to | 402レスポンスのpayTo |
value | 402レスポンスのmaxAmountRequired |
validAfter | 0 |
validBefore | 402レスポンスの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— 必要な場合の PINurl— 該当する場合の引き換え URLbrand_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_code | deliverable.pin_code |
| PIN | pin(独立したフィールド) | 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-2solana: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.md | API 呼び出しの正確なリクエスト/レスポンススキーマが必要な場合 | REST API リファレンス、Hosts テーブル、すべてのヘッダーの一覧、エラーレスポンスコード |
references/troubleshooting.md | リクエストが失敗する、または予期しないステータスが返される場合 | レールごとのエラーカタログと復旧パターン |