独自ECサイトにUSDC / JPYC / USDTなどのステーブルコイン決済をAPI連携で導入。 Intent発行 → 決済ページリダイレクト → Webhook通知の3ステップで、 暗号資産による支払いを即日受付できます。
ECサイトにステーブルコイン決済を導入するための、すべての機能を備えています。
REST APIでIntent(決済要求)を発行し、ユーザーをBitVoy決済ページにリダイレクトするだけ。複雑なブロックチェーン処理はBitVoyが全て代行します。
決済完了時にWebhookで即座に通知。HMAC署名付きで改ざん検知も万全です。注文ステータスの自動更新に最適です。
CoinGecko APIを利用し、JPY / USD等の法定通貨価格をリアルタイムでステーブルコインに変換。サーバーサイドで正確な金額を算出できます。
顧客が好みのステーブルコインとチェーンを選択可能。
ERC-4337 Account Abstractionにより、ユーザーのガス代をPaymasterがスポンサー。顧客はガス代を気にせず決済できます。
決済が完了すると、指定のウォレットアドレスに直接送金されます。中間の保管はなく、数秒で資金を受け取れます。
BitVoy EC Payment APIは、Payment Intent方式を採用しています。ECサイトのサーバーからIntentを発行し、顧客をBitVoy決済ページにリダイレクト。決済完了後、WebhookとリダイレクトでECサイトに結果が通知されます。
| ステータス | 説明 |
|---|---|
CREATED | Intent発行済み、ユーザー未操作 |
PRESENTED | ユーザーが決済画面を表示 |
AUTHORIZED | パスキー認証・送金承認完了 |
PROCESSING | トランザクション送信済み、チェーン確認待ち |
SUCCEEDED | 決済完了(ブロック確認済み) |
FAILED | 送金失敗またはトランザクション revert |
EXPIRED | 有効期限切れ(デフォルト15分) |
CANCELED | ユーザーがキャンセル |
ベースURL: https://bitvoy.org
Payment Intentを発行します。ECサイトのサーバーサイドから呼び出してください。
| パラメータ | 必須 | 説明 |
|---|---|---|
rp_client_id | 必須 | クライアントID |
client_secret | 必須 | クライアントシークレット |
order_ref | 必須 | ECサイト側の注文番号(冪等性キー) |
amount | 必須 | 金額(人間が読める単位。例: "100" = 100 JPYC) |
currency | 必須 | 通貨コード: USDC / JPYC / USDT |
payee | 必須 | 入金先ウォレットアドレス(文字列またはオブジェクト) |
chain | 必須 | avalanche / base |
execution_mode | 任意 | STANDARD(デフォルト)/ AA(ガスレス) |
network | 任意 | mainnet(デフォルト)/ testnet |
expires_in | 任意 | 有効期限(秒、デフォルト: 900 = 15分) |
return_url | 任意 | 決済完了後のリダイレクト先URL |
metadata | 任意 | ECサイト固有の追加情報(JSONオブジェクト) |
{
"intent_id": "int_01KK8VGFWGNQ62CAB3MA1N69B7",
"status": "CREATED",
"expires_at": "2026-03-20T09:15:00.000Z",
"intent_token": "eyJ...",
"payment_start_url": "https://bitvoy.org/oidc/authorize?...intent_id=int_xxx"
}
payment_start_url にユーザーをリダイレクトすると、BitVoy決済ページが表示されます。
Intentのステータスと決済結果を確認します。
Authorization: Basic BASE64(client_id:) または ?client_id={client_id}
{
"intent_id": "int_01KK8VGFWGNQ62CAB3MA1N69B7",
"status": "SUCCEEDED",
"amount": "100",
"currency": "JPYC",
"chain": "avalanche",
"order_ref": "ORDER-12345",
"result": {
"paid_at": "2026-03-20T09:01:00.000Z",
"tx_hash": "0xf7a41da56eb6b4b276bc3c7d84d94d6944cc8fc9...",
"chain": "avalanche",
"paid_amount": "100"
}
}
Intentのステータスが変化するたびに、登録された webhook_url にPOSTリクエストが送信されます。
| イベント | タイミング |
|---|---|
intent.succeeded | 決済完了時 |
intent.failed | 決済失敗時 |
intent.expired | 有効期限切れ時 |
{
"event": "intent.succeeded",
"timestamp": "2026-03-20T09:01:00.000Z",
"intent": {
"intent_id": "int_01KK8VGFWGNQ62CAB3MA1N69B7",
"status": "SUCCEEDED",
"order_ref": "ORDER-12345",
"amount": "100000000000000000000",
"currency": "JPYC",
"chain": "avalanche",
"network": "mainnet",
"payee": {
"type": "address",
"address": "0x1234...abcd"
},
"created_at": "2026-03-20T09:00:00.000Z",
"expires_at": "2026-03-20T09:15:00.000Z",
"result": {
"paid_at": "2026-03-20T09:01:00.000Z",
"tx_hash": "0xf7a41da56eb6b4b276bc3c7d84...",
"chain": "avalanche",
"network": "mainnet",
"paid_amount": "100000000000000000000"
}
}
}
注意: Webhookペイロード内の amount / paid_amount はminor unit(JPYC: 18桁、USDC: 6桁)です。
Webhookリクエストには以下のヘッダーが付与されます:
| Header | 説明 |
|---|---|
X-BitVoy-Event | イベント名(例: intent.succeeded) |
X-BitVoy-Timestamp | 送信時刻(ISO 8601) |
X-BitVoy-Signature | HMAC-SHA256署名(下記参照) |
Webhookリクエストには X-BitVoy-Signature ヘッダーが付与されます:
X-BitVoy-Signature: sha256=HEX(HMAC-SHA256(payload, webhook_secret))
登録フォームから申請してください。以下の情報をご用意いただきます:
shop.example.com登録完了後、以下の認証情報が発行されます:
client_id — クライアントIDclient_secret — クライアントシークレットwebhook_secret — Webhook署名検証用シークレット
チェックアウト時にサーバーからBitVoy APIを呼び出し、Payment Intentを発行します。
client_secret は必ずサーバーサイドで管理し、フロントエンドに露出させないでください。
intent.succeeded イベントを受け取り、注文ステータスを「支払い済み」に更新します。
必ず X-BitVoy-Signature を検証してください。
return_url に指定したURLでユーザーを受け取り、注文完了画面を表示します。
クエリパラメータに intent_id と txid が付与されます。
const express = require('express'); const app = express(); const BITVOY_API = 'https://bitvoy.org'; const CLIENT_ID = process.env.BITVOY_CLIENT_ID; const CLIENT_SECRET = process.env.BITVOY_CLIENT_SECRET; const WEBHOOK_SECRET = process.env.BITVOY_WEBHOOK_SECRET; const PAYEE_ADDRESS = '0x...'; // 入金先アドレス // チェックアウト: Intent発行 → リダイレクト app.post('/checkout', async (req, res) => { const { orderId, amount, currency, chain } = req.body; const resp = await fetch(`${BITVOY_API}/oidc-payment/intents`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ rp_client_id: CLIENT_ID, client_secret: CLIENT_SECRET, order_ref: orderId, amount: amount, // 例: "4500" (4500 JPYC) currency: currency, // 例: "JPYC" payee: PAYEE_ADDRESS, chain: chain, // 例: "avalanche" execution_mode: 'AA', // ガスレス決済 return_url: `https://shop.example.com/orders/${orderId}/complete`, metadata: { source: 'my-ec-site' } }) }); const data = await resp.json(); // intent_id を注文に紐付けて保存 await saveIntentToOrder(orderId, data.intent_id); // ユーザーをBitVoy決済ページにリダイレクト res.json({ payment_url: data.payment_start_url }); });
const crypto = require('crypto'); app.post('/webhook/bitvoy', express.raw({ type: 'application/json' }), async (req, res) => { // 1. 署名を検証 const signature = req.headers['x-bitvoy-signature']; const expected = 'sha256=' + crypto .createHmac('sha256', WEBHOOK_SECRET) .update(req.body) .digest('hex'); if (signature !== expected) { return res.status(401).json({ error: 'Invalid signature' }); } const payload = JSON.parse(req.body); // 2. intent.succeeded イベントを処理 if (payload.event === 'intent.succeeded') { const { intent_id, order_ref, result } = payload.intent; // 注文を「支払い済み」に更新 await updateOrderStatus(order_ref, { status: 'paid', tx_hash: result.tx_hash, paid_at: result.paid_at, intent_id: intent_id }); } res.json({ received: true }); });
// ユーザーがBitVoy決済ページから戻ってくるURL app.get('/orders/:orderId/complete', async (req, res) => { const { intent_id, txid } = req.query; const order = await getOrder(req.params.orderId); // Webhookが先に到達していれば、既に paid になっている // まだの場合はポーリングで確認 if (order.status !== 'paid' && intent_id) { const resp = await fetch( `${BITVOY_API}/oidc-payment/intents/${intent_id}?client_id=${CLIENT_ID}` ); const intent = await resp.json(); if (intent.status === 'SUCCEEDED') { await updateOrderStatus(order.id, { status: 'paid' }); } } res.render('order-complete', { order, txid }); });
import requests, os BITVOY_API = 'https://bitvoy.org' CLIENT_ID = os.environ['BITVOY_CLIENT_ID'] CLIENT_SECRET = os.environ['BITVOY_CLIENT_SECRET'] @app.route('/checkout', methods=['POST']) def checkout(): data = request.get_json() resp = requests.post(f'{BITVOY_API}/oidc-payment/intents', json={ 'rp_client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, 'order_ref': data['order_id'], 'amount': data['amount'], 'currency': 'USDC', 'payee': '0x...', 'chain': 'base', 'execution_mode': 'AA', 'return_url': f'https://shop.example.com/orders/{data["order_id"]}/complete', }) intent = resp.json() return jsonify({'payment_url': intent['payment_start_url']})
import hmac, hashlib @app.route('/webhook/bitvoy', methods=['POST']) def webhook(): payload = request.get_data() sig = request.headers.get('X-BitVoy-Signature', '') expected = 'sha256=' + hmac.new( WEBHOOK_SECRET.encode(), payload, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(sig, expected): return jsonify({'error': 'Invalid signature'}), 401 data = request.get_json() if data['event'] == 'intent.succeeded': intent = data['intent'] update_order(intent['order_ref'], status='paid', tx_hash=intent['result']['tx_hash']) return jsonify({'received': True})
<button id="pay-btn">ステーブルコインで支払う</button> <script> document.getElementById('pay-btn').addEventListener('click', async () => { const res = await fetch('/checkout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ order_id: 'ORDER-12345', amount: '4500', currency: 'JPYC', chain: 'avalanche' }) }); const { payment_url } = await res.json(); // BitVoy決済ページにリダイレクト window.location.href = payment_url; }); </script>
はい。BitVoy EC Payment APIはプラットフォーム非依存のREST APIです。Node.js、Python、PHP、Ruby、Go等、どのバックエンドからでもHTTPリクエストで連携できます。
ありません。BitVoyはチェックアウト時の追加の決済手段として導入するだけで、既存の決済フローとは独立して動作します。
USDC、JPYC、USDTに対応しています。チェーンはAvalancheとBaseをサポートしています。チェーンごとのガス代と速度が異なるため、用途に合わせて選択してください。
ERC-4337 Account Abstraction を利用し、Paymasterが顧客のガス代を肩代わりします。execution_mode: "AA" を指定するだけで有効になり、顧客はガス代を意識せずステーブルコインのみで決済できます。
法定通貨からステーブルコインへの変換が必要な場合は、ECサイト側で変換してからIntent発行時の amount に指定してください。BitVoy側でも /shopify/rate エンドポイントでCoinGeckoベースのレート取得が可能です。
STANDARDモード: 決済額の1.0%(USDC/JPYCはガス代無料、USDTは初回のみ承認ガス代あり)。
AAモード(PREMIUM): ガス代完全無料(弊社負担)。
Avalanche: 0.5% + ¥20/件(JPY) / 0.5% + $0.15/件(USD)
Base: 0.5% + $0.10/件(USD)
最低取引金額: ドル建て $2 / 円建て ¥300
顧客がステーブルコインで支払うと、ブロックチェーン上のトランザクション確定後(通常数秒)に、設定した入金先ウォレットアドレスへ直接送金されます。中間の保管はありません。
Webhookが届かない場合でも、GET /oidc-payment/intents/{intent_id} でステータスをポーリングできます。return_urlへのリダイレクト時にも intent_id が付与されるため、決済結果を確実に確認できます。
発生しません。order_ref にはクライアントごとにユニーク制約があるため、同じ注文番号で重複してIntentを発行することはできません。
はい。Intent発行時に network: "testnet" を指定するとテストネット(Fuji / Base Sepolia等)で動作します。テスト用のステーブルコインで決済フローを確認できます。
ブロックチェーン上のトランザクションは取り消しできないため、返金はストア側からウォレットアドレスへ手動で送金する形になります。ECサイト上での返金処理は通常通り記録可能です。
ステーブルコイン決済の導入に興味がありましたら、お気軽にお問い合わせください。