メインコンテンツまでスキップ

クイックスタート: x402 でリクエスト課金型 API を作る

このガイドでは、Awaji テストネット上で x402 プロトコルを使い、リクエストごとに少額の MUSD または MJPY を呼び出し側に課金する API エンドポイントの作成手順を説明します。

完了すると、次のものが手に入ります:

  • 未払いのリクエストに 402 Payment Required を返す、稼働中の Express サーバー
  • 自動で支払いを行い、レスポンスを取得するクライアントスクリプト
  • 今後の開発の土台となる、Awaji 上で動作するエンドツーエンドの決済フロー

所要時間: 約 30 分

まずテストネットトークンを入手

リクエストの支払いには、ウォレットに MUSD または MJPY が必要です。開始前に フォーセットで新しいテストネットウォレットに資金を入れてください。

Awaji テストネット

これらの例は 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 というファイルを作成します:

.env
SELLER_ADDRESS=0xYourEvmAddress
警告

.env ファイルは絶対にコミットしないでください。.gitignore に追加します:

echo ".env" >> .gitignore

4. サーバーを作成する

プロジェクトフォルダに、以下の内容で server.js というファイルを作成します:

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"));
2 つの支払いオプション

このエンドポイントは accepts 配列で MUSDMJPY の両方を提示するため、呼び出し側はどちらのステーブルコインでも支払えます。片方だけを受け付けたい場合は、もう一方のエントリを削除してください。

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 ファイルを作成します:

.env
EVM_PRIVATE_KEY=0xYourPrivateKey
警告

必ず新しいテストネットウォレットのみを使用してください。実資金の入ったウォレットは絶対に使わないでください。

4. クライアントを作成する

client.js というファイルを作成します:

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 — 買い手がチャネルに一度資金を入れ、リクエストごとにオフチェーンのバウチャーに署名します。売り手はオンチェーンでまとめて決済します。高頻度の呼び出しに適しています。

次のステップ