独自ECサイトにUSDC / JPYC / USDTなどのステーブルチェックアウトをAPI連携で導入。 Intent発行 → チェックアウトページリダイレクト → Webhook通知の3ステップで、 ステーブルコインによる支払いを即日受付できます。
ECサイトにステーブルチェックアウトを導入するための、すべての機能を備えています。
REST APIでIntent(チェックアウト要求)を発行し、ユーザーをBitVoyチェックアウトページにリダイレクトするだけ。複雑なブロックチェーン処理はBitVoyが全て代行します。
チェックアウト完了時にWebhookで即座に通知。HMAC署名付きで改ざん検知も万全です。注文ステータスの自動更新に最適です。
CoinGecko APIを利用し、JPY / USD等の法定通貨価格をリアルタイムでステーブルコインに変換。サーバーサイドで正確な金額を算出できます。
顧客が好みのステーブルコインとチェーンを選択可能。
SMARTモードではERC-4337 Paymasterがガス代をスポンサー。FASTモードでもRelayerが代理送信し、USDC/JPYCはガス代無料です。顧客はガス代を気にせずチェックアウトできます。
チェックアウトが完了すると、指定のウォレットアドレスに直接送金されます。中間の保管はなく、数秒で資金を受け取れます。
MetaMaskやRainbow等のWalletConnect対応ウォレットからもチェックアウト可能。BitVoyアカウントを持たない顧客にも対応でき、決済の間口が広がります。
スニペットがIntent発行からチェックアウトページへのリダイレクトまでを自動で処理します。チェックアウト完了後、WebhookとリダイレクトでECサイトに結果が通知されます。
| ステータス | 説明 |
|---|---|
CREATED | Intent発行済み、ユーザー未操作 |
PRESENTED | ユーザーがチェックアウト画面を表示 |
AUTHORIZED | パスキー認証・送金承認完了 |
PROCESSING | トランザクション送信済み、チェーン確認待ち |
SUCCEEDED | チェックアウト完了(ブロック確認済み) |
FAILED | 送金失敗またはトランザクション revert |
EXPIRED | 有効期限切れ(デフォルト15分) |
CANCELED | ユーザーがキャンセル |
Intent発行時のリクエストで execution_mode を指定することで、顧客の決済手段を選択できます。レスポンスには payment_url が1つ返され、その内容はモードによって異なります。
execution_mode | 対象ユーザー | 説明 |
|---|---|---|
FAST(デフォルト) |
BitVoyユーザー | BitVoyウォレットでパスキー認証 → 送金。アカウント登録済みの顧客向け。 |
SMART |
BitVoyユーザー | Account Abstraction(ERC-4337)によるガスレス決済。Avalanche / Base 対応。 |
WC |
外部ウォレットユーザー | MetaMask・Rainbow等のWalletConnect対応ウォレットで直接決済。BitVoyアカウント不要。 |
HTMLに数行のコードを貼るだけで、チェックアウトボタンが表示されます。Intent発行・為替変換・チェーン選択はすべてスニペットが自動で処理します。APIの直接呼び出しは不要です。
<div id="bitvoy-checkout" data-client-id="YOUR_CLIENT_ID" data-amount="3000" data-shop-currency="JPY" data-currencies="USDC,JPYC" data-order-ref="order_12345" data-return-url="https://myshop.com/thanks" data-metadata='{"user_id":"12345"}' data-lang="ja"> </div> <script src="https://bitvoy.org/checkout/button.js" async></script>
| 属性 | 必須 | 説明 |
|---|---|---|
data-client-id | 必須 | 登録時に発行されたクライアントID |
data-amount | 必須 | チェックアウト金額(法定通貨建て) |
data-shop-currency | 任意 | ストアの表示通貨(デフォルト: JPY) |
data-currency | 任意 | デフォルトの決済通貨(デフォルト: USDC) |
data-currencies | 任意 | 選択可能なステーブルコイン(カンマ区切り。例: USDC,JPYC,USDT) |
data-chains-filter | 任意 | 表示するチェーンを限定(カンマ区切り。例: polygon,avalanche) |
data-order-ref | 任意 | 注文番号(重複チェックアウト防止) |
data-return-url | 任意 | チェックアウト完了後のリダイレクト先URL |
data-metadata | 任意 | ECサイト固有の追加情報(JSONオブジェクト)。user_id を指定すると管理画面の決済一覧・検索・CSV出力に反映される |
data-lang | 任意 | 表示言語(ja / en。省略時はブラウザ言語) |
data-wc | 任意 | WalletConnectボタンの表示(デフォルト: true。false で非表示) |
チェーン選択はスニペットのUIで顧客が行います。通貨ごとに対応チェーンが自動表示されます。
登録フォームから申請してください。以下の情報をご用意いただきます:
shop.example.com登録完了後、以下の認証情報が発行されます:
client_id — スニペットに設定するクライアントIDwebhook_secret — サーバーサイドAPI呼び出し時の X-Signature 生成 / Webhook署名検証用シークレット
チェックアウトページに上記のスニペットコードを貼り付け、data-client-id に発行されたクライアントIDを設定します。
金額・通貨・注文番号はサーバーサイドでHTMLに埋め込んでください。
intent.succeeded イベントを受け取り、注文ステータスを「支払い済み」に更新します。
必ず X-BitVoy-Signature を検証してください。
data-return-url に指定したURLでユーザーを受け取り、注文完了画面を表示します。
クエリパラメータに intent_id と txid が付与されます。
スニペットを使用せず、独自のチェックアウトUIを実装したい場合に利用できるAPIです。Intent発行・ステータス確認・Webhook検証をサーバーサイドから直接制御できます。
サンプル実装として MerchantKit(ZIP) を提供しています。Express サーバー・Webhook 受信・PKCE フローを含む動作確認用サンプルです。
ベースURL: https://bitvoy.org
Checkout Intent を発行します。ECサイトのサーバーサイドから呼び出してください。
サーバーサイドからの呼び出しには X-Signature ヘッダー(HMAC-SHA256)が必要です。
X-Signature: HEX(HMAC-SHA256(JSON.stringify(requestBody), webhook_secret))
フロントエンド(スニペット)から呼び出す場合は Origin ヘッダーのドメイン照合で認証されるため X-Signature は不要です。
| パラメータ | 必須 | 説明 |
|---|---|---|
client_id | 必須 | クライアントID |
amount | 必須 | shop_currency 建ての金額(例: "3000" = 3000 JPY)。APIサーバー側でステーブルコインへ変換されます。 |
chain | 必須 | polygon / kaia / avalanche / base |
shop_currency | 任意 | ストアの表示通貨(デフォルト: サイト設定 or JPY)。amount の基準通貨として使用。 |
currency | 任意 | 決済ステーブルコイン: USDC / JPYC / USDT(デフォルト: サイト設定の default_currency) |
order_ref | 任意 | ECサイト側の注文番号(Webhook / ステータス確認で使用) |
execution_mode | 任意 | FAST(デフォルト)/ SMART(ガスレス)/ WC(WalletConnect) |
return_url | 任意 | チェックアウト完了後のリダイレクト先URL(登録済みURLのみ有効) |
lang | 任意 | 決済画面の表示言語: ja / en |
metadata | 任意 | ECサイト固有の追加情報(JSONオブジェクト、最大4KB)。user_id を指定すると管理画面の決済一覧・検索・CSV出力に反映される |
{
"intent_id": "int_01KK8VGFWGNQ62CAB3MA1N69B7",
"payment_url": "https://bitvoy.org/oidc/authorize?...&state=int_xxx",
"amount": "22.5",
"currency": "USDC",
"chain": "avalanche",
"expires_at": "2026-03-20T09:15:00.000Z"
}
payment_url はモードによって内容が異なります。FAST / SMART モードはBitVoyウォレット(OIDC)URL、WC モードはWalletConnect URL(https://bitvoy.org/wc/pay/...)が返されます。
amount は shop_currency → currency に変換後のステーブルコイン金額(人間が読める単位)です。
Intentのステータスとチェックアウト結果を確認します。認証不要。
{
"intent_id": "int_01KK8VGFWGNQ62CAB3MA1N69B7",
"status": "SUCCEEDED",
"amount": "22.5",
"currency": "USDC",
"chain": "avalanche",
"order_ref": "ORDER-12345",
"created_at": "2026-03-20T09:00:00.000Z",
"expires_at": "2026-03-20T09:15:00.000Z",
"result": {
"tx_hash": "0xf7a41da56eb6b4b276bc3c7d84d94d6944cc8fc9...",
"paid_at": "2026-03-20T09:01:00.000Z"
}
}
法定通貨 → ステーブルコインの換算レートを取得します。
| パラメータ | 必須 | 説明 |
|---|---|---|
client_id | 必須 | クライアントID |
currency | 必須 | 決済ステーブルコイン: USDC / JPYC / USDT |
shop_currency | 任意 | 変換元通貨(デフォルト: サイト設定 or JPY) |
amount | 任意 | 指定すると converted_amount も返す |
{
"rate": 0.0075,
"shop_currency": "JPY",
"pay_currency": "USDC",
"converted_amount": 22.5
}
Intentのステータスが変化するたびに、登録された webhook_url にPOSTリクエストが送信されます。
| イベント | タイミング |
|---|---|
intent.succeeded | チェックアウト完了時 |
intent.failed | チェックアウト失敗時 |
intent.expired | 有効期限切れ時 |
intent.canceled | ユーザーがキャンセル時 |
intent.refunded | 返金完了時 |
{
"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"
}
}
}
{
"event": "intent.refunded",
"timestamp": "2026-03-20T10:00: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"
}
},
"refund": {
"refund_id": "abc123def456...",
"refund_to": "0xabcd...1234",
"amount": "100000000000000000000",
"currency": "JPYC",
"chain": "avalanche",
"tx_hash": "0xe3b2c91a47fd8b5e276dc3d94...",
"refunded_at": "2026-03-20T10:00:00.000Z"
}
}
注意: Webhookペイロード内の amount / paid_amount はminor unit(JPYC: 18桁、USDC: 6桁)です。
Webhookリクエストには以下のヘッダーが付与されます:
| Header | 説明 |
|---|---|
X-BitVoy-Delivery | 配信ID(同一イベントのリトライ間で不変。受信側の重複排除キーとして使用可能) |
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))
const crypto = require('crypto'); const express = require('express'); const app = express(); const BITVOY_API = 'https://bitvoy.org'; const CLIENT_ID = process.env.BITVOY_CLIENT_ID; const WEBHOOK_SECRET = process.env.BITVOY_WEBHOOK_SECRET; // チェックアウト: Intent発行 → リダイレクト app.post('/checkout', async (req, res) => { const { orderId, amount, chain } = req.body; const body = { client_id: CLIENT_ID, order_ref: orderId, amount: amount, // 例: "3000" (3000 JPY) shop_currency: 'JPY', // ストアの通貨 → ステーブルコインに自動変換 currency: 'USDC', // 決済ステーブルコイン chain: chain, // 例: "avalanche" execution_mode: 'FAST', // FAST / SMART / WC return_url: `https://shop.example.com/orders/${orderId}/complete`, metadata: { user_id: String(req.session.userId) } }; // X-Signature: HMAC-SHA256(JSON.stringify(body), webhook_secret) const signature = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(JSON.stringify(body)) .digest('hex'); const resp = await fetch(`${BITVOY_API}/checkout/create`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Signature': signature }, body: JSON.stringify(body) }); const data = await resp.json(); // intent_id を注文に紐付けて保存 await saveIntentToOrder(orderId, data.intent_id); // payment_url にユーザーをリダイレクト(モードに応じた内容が返される) res.json({ payment_url: data.payment_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}/checkout/status/${intent_id}` ); const intent = await resp.json(); if (intent.status === 'SUCCEEDED') { await updateOrderStatus(order.id, { status: 'paid' }); } } res.render('order-complete', { order, txid }); });
import hmac, hashlib, json, requests, os BITVOY_API = 'https://bitvoy.org' CLIENT_ID = os.environ['BITVOY_CLIENT_ID'] WEBHOOK_SECRET = os.environ['BITVOY_WEBHOOK_SECRET'] @app.route('/checkout', methods=['POST']) def checkout(): data = request.get_json() order_id = data['order_id'] body = { 'client_id': CLIENT_ID, 'order_ref': order_id, 'amount': data['amount'], # 例: "3000" (3000 JPY) 'shop_currency': 'JPY', # ストアの通貨 → ステーブルコインに自動変換 'currency': 'USDC', 'chain': 'base', 'execution_mode': 'FAST', 'return_url': f'https://shop.example.com/orders/{order_id}/complete', } # X-Signature: HMAC-SHA256(JSON.stringify(body), webhook_secret) body_str = json.dumps(body, separators=(',', ':')) signature = hmac.new( WEBHOOK_SECRET.encode(), body_str.encode(), hashlib.sha256 ).hexdigest() resp = requests.post( f'{BITVOY_API}/checkout/create', data=body_str, headers={'Content-Type': 'application/json', 'X-Signature': signature} ) intent = resp.json() return jsonify({'payment_url': intent['payment_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})
フロントエンドからはECサイト自身のバックエンド経由でIntent発行し、受け取った payment_url にリダイレクトします。execution_mode をバックエンドに渡すことでBitVoy / WalletConnect を切り替えられます。
<button id="pay-bitvoy">BitVoyウォレットで支払う</button> <button id="pay-wc">外部ウォレットで支払う(MetaMask等)</button> <script> async function createCheckout(executionMode) { const res = await fetch('/checkout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ order_id: 'ORDER-12345', amount: '3000', // JPY建て金額 chain: 'avalanche', execution_mode: executionMode }) }); return res.json(); } // BitVoyウォレット(FAST / SMART モード)で決済 document.getElementById('pay-bitvoy').addEventListener('click', async () => { const { payment_url } = await createCheckout('FAST'); window.location.href = payment_url; }); // 外部ウォレット(WalletConnect)で決済 document.getElementById('pay-wc').addEventListener('click', async () => { const { payment_url } = await createCheckout('WC'); window.location.href = payment_url; }); </script>
はい。BitVoy EC Checkout APIはプラットフォーム非依存のREST APIです。Node.js、Python、PHP、Ruby、Go等、どのバックエンドからでもHTTPリクエストで連携できます。
ありません。BitVoyはチェックアウト時の追加の決済手段として導入するだけで、既存のチェックアウトフローとは独立して動作します。
USDC、JPYC、USDTに対応しています。チェーンはPolygon、Kaia、Avalanche、Baseをサポートしています。FASTモードでは全4チェーン(USDC: Polygon/Avalanche/Base、JPYC: Kaia/Polygon/Avalanche)、SMARTモードではAvalancheとBaseに対応しています。
ERC-4337 Account Abstraction を利用し、Paymasterが顧客のガス代を肩代わりします。execution_mode: "SMART" を指定するだけで有効になり、顧客はガス代を意識せずステーブルコインのみで決済できます。
Intent発行時に amount(法定通貨建て)と shop_currency(例: JPY)を渡すだけで、BitVoyサーバー側がCoinGeckoベースのリアルタイムレートで自動変換します。変換後のステーブルコイン金額はレスポンスの amount フィールドで確認できます。事前にレートを確認したい場合は GET /checkout/rate エンドポイントをご利用ください。
FASTモード: チェックアウト額の1.0%(USDC/JPYCはガス代無料、USDTは初回のみ承認ガス代あり)。最低取引金額: USDC/USDT $0.99、JPYC ¥99
SMARTモード: チェックアウト額の0.5% + 固定手数料/件(USDC/USDT $0.15、JPYC ¥20)。ガス代完全無料(弊社負担)。最低取引金額: USDC/USDT $0.01、JPYC ¥1
顧客がステーブルコインで支払うと、ブロックチェーン上のトランザクション確定後(通常数秒)に、設定した入金先ウォレットアドレスへ直接送金されます。中間の保管はありません。
Webhookが届かない場合でも、GET /checkout/status/{intent_id} でステータスをポーリングできます。return_url へのリダイレクト時にも intent_id と status が付与されるため、チェックアウト結果を確実に確認できます。
発生しません。order_ref にはクライアントごとにユニーク制約があるため、同じ注文番号で重複してIntentを発行することはできません。
ブロックチェーン上のトランザクションは取り消しできないため、返金はストア側からお客様のウォレットアドレスへ送金する形になります。Shop DashboardのRefundモードから返金先アドレスを確認・編集して送金を実行でき、完了時に intent.refunded Webhookで通知されます。ECサイト上での返金処理も通常通り記録可能です。
旧API(/oidc-payment/intents)のドキュメントは
EC Payment API V1 を参照してください。
ステーブルチェックアウトの導入に興味がありましたら、お気軽にお問い合わせください。