Next.js スターターテンプレート
認証、料金ページ、ChainPay 決済があらかじめ組み込まれた完全な Next.js アプリ。クローンして 5 分で実行できます。
クイックスタート
3 ステップで暗号資産決済を受け付け — ブロックチェーンの知識は不要です。
決済注文を作成する
const response = await fetch("https://chainpay.pro/api/v1/orders", {
method: "POST",
headers: {
"Authorization": "Bearer sk_live_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
amount: 29.99,
currency: "USDT",
chain: "trc20",
externalId: "order_abc123", // your internal order ID
metadata: { userId: "user_456" } // arbitrary JSON, returned in webhook
})
});
const order = await response.json();
// order.checkoutUrl → redirect user here
// order.payAddress → or show the address directlyユーザーをチェックアウトへリダイレクトする
// Server-side redirect
res.redirect(order.checkoutUrl);
// Or client-side
window.location.href = order.checkoutUrl;決済が確認されたら Webhook を受け取る
{
"event": "payment.completed",
"orderId": "ord_a1b2c3d4e5f6",
"externalId": "order_abc123",
"amount": "29.99",
"netAmount": "29.75", // after 0.8% fee
"currency": "USDT",
"chain": "trc20",
"txHash": "e3b0c44298fc1c149afb...",
"completedAt": "2026-03-22T08:15:00Z",
"metadata": { "userId": "user_456" }
}処理する前に X-ChainPay-Signature ヘッダーを検証してください。検証用コードは セクションを参照してください。
認証
すべての API リクエストには、API キーを Bearer トークンとして含める必要があります。
Authorization: Bearer sk_live_YOUR_API_KEYcurl -X POST https://chainpay.pro/api/v1/orders \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"amount": 10, "currency": "USDT", "chain": "trc20"}'| キーのプレフィックス | 環境 | ブロックチェーン |
|---|---|---|
| sk_live_… | 本番環境 | 実際の取引 |
| sk_test_… | サンドボックス | 実際の資金は移動しません |
注文の作成
https://chainpay.pro/api/v1/ordersリクエストパラメータ
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
| amount | number | 必須 | USD 建ての決済金額(例:29.99)。相当する暗号資産の金額は、その時点の市場レートで計算されます。 |
| currency | string | 必須 | 受け取る暗号資産。次のいずれか:"USDT"、"ETH"、"BTC"、"SOL"。 |
| chain | string | 必須 | ブロックチェーンネットワーク。次のいずれか:"trc20"、"erc20"、"btc"、"sol"。選択した通貨と互換性がある必要があります。 |
| externalId | string | 任意 | 貴社内部の注文識別子。Webhook ではそのまま返されます。加盟店ごとに一意である必要があります。 |
| metadata | object | 任意 | 任意の JSON オブジェクト(最大 2 KB)。この注文のすべての Webhook で返されます — ユーザー ID やカート参照などの受け渡しに便利です。 |
対応する通貨 + チェーンの組み合わせ
| currency | chain | ネットワーク | 平均確認時間 |
|---|---|---|---|
| USDT | trc20 | TRON (TRC-20) | 約 1 分 |
| USDT | erc20 | Ethereum (ERC-20) | 約 2 分 |
| ETH | erc20 | Ethereum | 約 2 分 |
| BTC | btc | Bitcoin | 約 30 分 |
| SOL | sol | Solana | 5 秒未満 |
レスポンス
{
"orderId": "ord_a1b2c3d4e5f6g7h8",
"payAddress": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"cryptoAmount": "29.99",
"currency": "USDT",
"chain": "trc20",
"checkoutUrl": "https://chainpay.pro/pay/ord_a1b2c3d4",
"expiresAt": "2026-03-22T09:00:00Z",
"createdAt": "2026-03-22T08:30:00Z"
}チェックアウトフロー
ホスト型決済ページの仕組み。
- 1リダイレクト — 貴社のサーバーは、注文作成時に返された checkoutUrl へユーザーをリダイレクトします。
- 2決済ページ — ホスト型ページには、正確な暗号資産の金額があらかじめ入力された QR コードとウォレットアドレスが表示されます。ユーザーは QR コードをスキャンするか、アドレスをウォレットアプリにコピーします。
- 3確認 — ChainPay がブロックチェーンを監視します。必要な確認回数に達すると、注文ステータスが confirming、続いて completed に変わります。
- 4リダイレクトで戻る — 決済ページに成功画面が表示されます。ダッシュボードで successUrl を設定している場合、ユーザーは自動的にそこへリダイレクトされます。
- 5Webhook — 貴社のサーバーは payment.completed Webhook を受け取ります。Webhook 署名を検証してから注文を履行してください。
expired に変わり、payment.expired Webhook が送信されます。再試行するには新しい注文を作成してください。Webhook
ChainPay は注文ステータスが変化したときに、署名付きの HTTP POST リクエストを貴社の Webhook URL へ送信します。
セットアップ
ダッシュボード → アプリ → 新規アプリを開きます
Webhook URL を入力します(例:https://yourapp.com/api/webhooks/chainpay)
生成された Webhook シークレットをコピーします — 署名の検証に使用します
Webhook イベント
現在対応しているイベント:
| イベント | 発火するタイミング |
|---|---|
| payment.completed | 注文が支払われ、オンチェーンで確認された |
| payment.expired | 注文が支払われずに期限切れになった |
ペイロード形式
{
"event": "payment.completed",
"orderId": "ord_xxxxxxxx",
"amount": "9.99",
"currency": "USDT",
"chain": "trc20",
"txHash": "abc123...",
"netAmount": "9.92",
"completedAt": "2026-01-01T00:00:00.000Z",
"metadata": {
"userId": "your-user-id",
"plan": "monthly"
}
}署名の検証
すべての Webhook リクエストには X-ChainPay-Signature ヘッダーが含まれます。アプリの Webhook シークレットを用いて HMAC-SHA256 で検証してください:
import crypto from 'crypto'
function verifyWebhook(rawBody: string, signature: string, secret: string): boolean {
const computed = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(computed),
Buffer.from(signature)
)
}
// In your webhook handler:
export async function POST(req: Request) {
const rawBody = await req.text()
const signature = req.headers.get('x-chainpay-signature') ?? ''
if (!verifyWebhook(rawBody, signature, process.env.CHAINPAY_WEBHOOK_SECRET!)) {
return new Response('Unauthorized', { status: 401 })
}
const event = JSON.parse(rawBody)
if (event.event === 'payment.completed') {
const { userId, plan } = event.metadata
// activate user's plan
}
return new Response('OK')
}import hmac, hashlib
def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
computed = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(computed, signature)Webhook をテストする
ダッシュボード → アプリを開き、アプリを選択します
「テストイベントを送信」をクリックします
サーバーがリクエストを受信したか確認します(HTTP 200 が期待されます)
再試行ポリシー
配信に失敗した場合、指数バックオフで再試行されます:1 分 → 5 分 → 30 分 → 2 時間 → 24 時間(合計 5 回)。
5 回失敗すると、Webhook は失敗としてマークされます。配信失敗は ダッシュボード → アラートで確認してください。
ベストプラクティス
- 処理する前に必ず署名を検証する
- HTTP 200 を素早く返す — 重い処理は非同期で実行する
orderIdを使ってイベントを重複排除する(Webhook は複数回配信される場合があります)- 正確な署名検証のため、パースする前に生のボディを保存する
注文の照会
https://chainpay.pro/api/v1/orders/:id{
"id": "ord_a1b2c3d4e5f6g7h8",
"amount": "29.99",
"cryptoAmount":"29.99",
"netAmount": "29.75",
"currency": "USDT",
"chain": "trc20",
"status": "completed",
"payAddress": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"txHash": "e3b0c44298fc1c149afbf4c8996fb92...",
"externalId": "order_abc123",
"metadata": { "userId": "user_456" },
"createdAt": "2026-03-22T08:30:00Z",
"expiresAt": "2026-03-22T09:00:00Z",
"completedAt": "2026-03-22T08:45:00Z"
}注文ステータスの値
| ステータス | 説明 |
|---|---|
| pending | 注文が作成され、ユーザーの支払いを待っています。 |
| confirming | オンチェーンで取引が検知され、十分なブロック確認を待っています。 |
| completed | 決済が完全に確認されました。注文を履行して問題ありません。 |
| expired | 決済が検知されないまま 30 分が経過しました。 |
| failed | 予期しないエラーが発生しました。orderId を添えてサポートにお問い合わせください。 |
レート API
現在の USD 為替レートを取得します。API キーは不要です。
https://chainpay.pro/api/v1/rates{
"USDT": 1.0,
"ETH": 3450.00,
"BTC": 87500.00,
"SOL": 145.00,
"updatedAt": "2026-03-22T08:00:00Z"
}レートは集約された市場データから 60 秒ごとに更新されます。注文作成エンドポイントに渡す amount は常に USD として解釈され、API は注文作成時点のレートで暗号資産に換算します。
サンドボックスモード
実際の資金を動かさずに、完全な統合をテストできます。
?mode=test を付けて登録すると、sk_test_ の API キーが発行されます。サンドボックスモードでもすべての標準エンドポイントが同一に動作します — ブロックチェーンのポーリングはスキップされ、確認は手動でトリガーします。
ステップ 1 — サンドボックス API キーを取得する
curl -X POST "https://chainpay.pro/api/auth/register?mode=test" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "yourpassword"}'
# Response includes:
# { "merchant": { "apiKey": "sk_test_xxxxxxxxxxxxxxxx" } }ステップ 2 — テストキーで注文を作成する
curl -X POST https://chainpay.pro/api/v1/orders \
-H "Authorization: Bearer sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"amount": 10, "currency": "USDT", "chain": "trc20", "externalId": "test_order_1"}'ステップ 3 — 決済をシミュレートする
curl -X POST https://chainpay.pro/api/v1/sandbox/simulate-payment \
-H "Authorization: Bearer sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"orderId": "ord_abc123"}'
# Response:
{
"success": true,
"orderId": "ord_abc123",
"txHash": "sandbox_ord_abc123_1711000000000",
"netAmount": "9.92000000"
}
# The order status is now "completed" and your webhook is fired.sandbox_ のプレフィックスが付きます。simulate-payment エンドポイントは sk_test_ キーでのみ利用できます。本番キーで実行しようとすると 403 が返されます。エラーコード
すべてのエラーレスポンスは、一貫した JSON エンベロープを使用します:
{
"error": "INVALID_CHAIN",
"message": "chain 'foo' is not supported for currency USDT",
"status": 400
}| HTTP ステータス | 主なエラーコード | 原因と対処 |
|---|---|---|
| 400 | INVALID_AMOUNT, INVALID_CURRENCY, INVALID_CHAIN, MISSING_FIELD | リクエストボディが不正であるか、必須フィールドが欠けています。上のリクエストパラメータ表を確認してください。 |
| 401 | UNAUTHORIZED, INVALID_API_KEY | Authorization ヘッダーが欠落しているか無効です。Bearer <key> を送信していることを確認してください。 |
| 403 | FORBIDDEN, SANDBOX_ONLY | API キーにこの操作の権限がありません(例:本番キーで simulate-payment を使用)。 |
| 404 | ORDER_NOT_FOUND | 指定された ID の注文が存在しないか、貴社の加盟店アカウントに属していません。 |
| 429 | RATE_LIMITED | リクエストが多すぎます。デフォルトの上限は API キーごとに 60 req/min です。バックオフし、Retry-After ヘッダーの値の後に再試行してください。 |
| 500 | INTERNAL_ERROR | 予期しないサーバー側エラーです。指数バックオフで再試行してください。継続する場合は、リクエスト ID を添えてサポートにお問い合わせください。 |
決済
ChainPay が回収した資金を、いつどのように貴社のウォレットへ送るか。
決済では、完了済みかつ未決済のすべての金額を、ダッシュボードの 設定 → 決済ウォレットで設定したウォレットアドレスへ送ります。通貨ごとに別々の支払いアドレスを設定できます。
netAmount はすでに手数料差引後の金額を反映しています。決済では、その日のすべての netAmount の合計が送金されます。導入の準備はできましたか?
アカウントを作成すれば、数秒で API キーを取得できます。