クイックスタート: x402 でリクエスト課金型 API を作る
このガイドでは、Awaji テストネット上で x402 プロトコルを使い、リクエストごとに少額の MUSD または MJPY を呼び出し側に課金する API エンドポイントの作成手順を説明します。
完了すると、次のものが手に入ります:
- 未払いのリクエストに
402 Payment Requiredを返す、稼働中の Express サーバー - 自動で支払いを行い、レスポンスを取得するクライアントスクリプト
- 今後の開発の土台となる、Awaji 上で動作するエンドツーエンドの決済フロー
所要時間: 約 30 分
リクエストの支払いには、ウォレットに MUSD または MJPY が必要です。開始前に フォーセットで新しいテストネットウォレットに資金を入れてください。
これらの例は Awaji テストネット用に設定されています。デプロイ済みの x402 およびステーブルコインのアドレスはすべて x402 コントラクトを参照してください。
前提条件
開始する前に、以下がインストールされていることを確認してください:
- Node.js v22 以上 —
node --versionで確認します。インストールが必要な場合は nvm を使ってください:nvm install 22 && nvm use 22 - テストネットウォレットの秘密鍵 — 実資金が入っていない新しいウォレットを使用してください。MetaMask で作成するか、Foundry がインストールされていれば
cast wallet newでも作成できます - テストネット MUSD または MJPY — フォーセットを使ってウォレットに資金を入れてください
パート 1: 売り手 — 課金対応の API エンドポイントを作る
1. プロジェクトフォルダを作成する
ターミナルを開き、売り手サーバー用の新しいフォルダを作成します:
mkdir x402-seller
cd x402-seller
2. プロジェクトを初期化する
npm init -y
npm pkg set type=module
npm install @x402/express @x402/core @x402/evm express dotenv
3. .env ファイルを作成する
プロジェクトフォルダに、ウォレットアドレスを記載した .env というファイルを作成します:
SELLER_ADDRESS=0xYourEvmAddress
.env ファイルは絶対にコミットしないでください。.gitignore に追加します:
echo ".env" >> .gitignore
4. サーバーを作成する
プロジェクトフォルダに、以下の内容で server.js というファイルを作成します:
import "dotenv/config";
import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";
const app = express();
// Your Awaji testnet receiving address — loaded from .env
const payTo = process.env.SELLER_ADDRESS;
// Awaji facilitator — handles payment verification and settlement
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://x402-production-6134.up.railway.app",
});
// Awaji testnet — chain ID 6497
const AWAJI_NETWORK = "eip155:6497";
// MUSD token on Awaji
// EIP-712 domain params (name/version) must live in `extra` — that's where
// the ExactEvmScheme reads them when building the permit signature.
const MUSD = {
address: "0xb9C49B527294E8472eD48B800E81b5FA69D0f72E",
extra: {
name: "MIZUHIKI USD",
version: "2",
},
decimals: 6,
};
// MJPY token on Awaji
const MJPY = {
address: "0x78f5f0Ac4EF201618b97638ded959b155c4f4B04",
extra: {
name: "Mizuhiki JPY",
version: "2",
},
decimals: 6,
};
app.use(
paymentMiddleware(
{
"GET /api/data": {
accepts: [
{
scheme: "exact",
network: AWAJI_NETWORK,
payTo,
price: {
amount: "1000", // 0.001 MUSD (6 decimals) - adjust as needed
asset: MUSD.address,
extra: MUSD.extra,
},
},
{
scheme: "exact",
network: AWAJI_NETWORK,
payTo,
price: {
amount: "150000", // adjust as needed
asset: MJPY.address,
extra: MJPY.extra,
},
},
],
description: "Paid data endpoint",
mimeType: "application/json",
unpaidResponseBody: function () {
return {
contentType: "application/json",
body: { message: "Payment required to access this resource" },
};
},
},
},
new x402ResourceServer(facilitatorClient).register(
AWAJI_NETWORK,
new ExactEvmScheme(),
),
),
);
// This handler only runs after payment is verified
app.get("/api/data", (req, res) => {
res.json({
message: "Payment verified. Here is your data.",
timestamp: Date.now(),
});
});
app.listen(4021, () => console.log("Server running on http://localhost:4021"));
このエンドポイントは accepts 配列で MUSD と MJPY の両方を提示するため、呼び出し側はどちらのステーブルコインでも支払えます。片方だけを受け付けたい場合は、もう一方のエントリを削除してください。
5. サーバーを起動する
node server.js
次のように表示されるはずです:
Server running on http://localhost:4021
6. 402 チャレンジをテストする
新しいターミナルウィンドウで、次を実行します:
curl http://localhost:4021/api/data
PAYMENT-REQUIRED ヘッダー付きの 402 Payment Required レスポンスが返るはずです。これで、サーバーがエンドポイントを正しく保護していることが確認できます。このサーバーは起動したままにして、パート 2 に進みます。
パート 2: 買い手 — API 呼び出しの支払いを自動化する
このパート用に新しいターミナルウィンドウを開きます。売り手サーバーはもう一方のウィンドウで起動したままにしておきます。
1. プロジェクトフォルダを作成する
mkdir x402-buyer
cd x402-buyer
2. プロジェクトを初期化する
npm init -y
npm install @x402/fetch @x402/core @x402/evm viem dotenv
売り手のときと同じように、package.json に "type": "module" を追加します。
3. .env ファイルを作成する
買い手ウォレットの秘密鍵を記載した .env ファイルを作成します:
EVM_PRIVATE_KEY=0xYourPrivateKey
必ず新しいテストネットウォレットのみを使用してください。実資金の入ったウォレットは絶対に使わないでください。
4. クライアントを作成する
client.js というファイルを作成します:
import "dotenv/config";
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
// Load your testnet private key from .env
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY);
// Create x402 client and register the EVM payment scheme
const client = new x402Client();
client.register("eip155:*", new ExactEvmScheme(signer));
// Wrap fetch — payment is handled automatically on 402 responses
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
console.log("→ Sending request to paid endpoint...");
// Probe the endpoint first to log the payment details
const probe = await fetch("http://localhost:4021/api/data");
if (probe.status === 402) {
const raw = probe.headers.get("PAYMENT-REQUIRED");
const paymentRequired = JSON.parse(
Buffer.from(raw, "base64").toString("utf8"),
);
const option = paymentRequired.accepts?.[0];
console.log("← 402 Payment Required");
console.log(` Network: ${option?.network}`);
console.log(` Amount: ${option?.amount} (atomic units)`);
console.log(` Asset: ${option?.asset}`);
console.log(` Pay to: ${option?.payTo}`);
}
console.log("→ Signing and submitting payment on-chain...");
// This call handles the full 402 handshake automatically
const response = await fetchWithPayment("http://localhost:4021/api/data");
// Log the settlement receipt from the response header
const raw = response.headers.get("PAYMENT-RESPONSE");
const receipt = JSON.parse(Buffer.from(raw, "base64").toString("utf8"));
console.log(
"✓ Payment settled — tx hash:",
receipt?.txHash ?? receipt?.transactionHash ?? JSON.stringify(receipt),
);
const data = await response.json();
console.log("✓ Response received:", data);
5. クライアントを実行する
node client.js
次のような出力が表示されるはずです:
→ Sending request to paid endpoint...
← 402 Payment Required
Network: eip155:6497
Amount: 1000 (atomic units)
Asset: 0xb9C49B527294E8472eD48B800E81b5FA69D0f72E
Pay to: 0xYourSellerAddress
→ Signing and submitting payment on-chain...
✓ Payment settled — tx hash: 0x...
✓ Response received: { message: 'Payment verified. Here is your data.', timestamp: ... }
仕組み
Client x402 Middleware Your Handler
│ │ │
│── GET /api/data ──────────────────>│ │
│<── 402 + PAYMENT-REQUIRED header ──│ │
│ │ │
│ (client signs & submits │ │
│ payment on Awaji) ──────────────│ │
│ │ │
│── GET /api/data + PAYMENT-SIGNATURE│ │
│ ────────────────────────────────>│ │
│ verifies via facilitator │
│ │── request passes ────────>│
│<────────────────────────────────────────── 200 + data ─────────│
支払いがオンチェーンで検証されない限り、あなたのハンドラーは決して実行されません。402 ハンドシェイク全体はミドルウェアが担います。
決済スキーム
上記の例では exact(リクエストごとの固定価格)を使用しています。x402 は次のスキームもサポートします:
upto— クライアントが上限額を承認し、売り手は実際の使用量(例: トークン数)に応じてのみ課金します。EVM のみ対応。batch-settlement— 買い手がチャネルに一度資金を入れ、リクエストごとにオフチェーンのバウチャーに署名します。売り手はオンチェーンでまとめて決済します。高頻度の呼び出しに適しています。
次のステップ
- x402 コントラクト — エージェント開発向けの x402 およびステーブルコインのコントラクトアドレスとネットワーク詳細
- 事前デプロイ済みコントラクト — Awaji 上の標準ユーティリティコントラクト(Multicall3、Permit2、Create2 Factory など)