Menu
Sections
BitVoy EC Checkout API

Stablecoin Payment for
Your Online Store

独自ECサイトにUSDC / JPYC / USDTなどのステーブルチェックアウトをAPI連携で導入。 Intent発行 → チェックアウトページリダイレクト → Webhook通知の3ステップで、 暗号資産による支払いを即日受付できます。

特長

ECサイトにステーブルチェックアウトを導入するための、すべての機能を備えています。

シンプルなAPI連携

REST APIでIntent(チェックアウト要求)を発行し、ユーザーをBitVoyチェックアウトページにリダイレクトするだけ。複雑なブロックチェーン処理はBitVoyが全て代行します。

Webhook通知

チェックアウト完了時にWebhookで即座に通知。HMAC署名付きで改ざん検知も万全です。注文ステータスの自動更新に最適です。

リアルタイム為替レート

CoinGecko APIを利用し、JPY / USD等の法定通貨価格をリアルタイムでステーブルコインに変換。サーバーサイドで正確な金額を算出できます。

複数通貨 × 複数チェーン

顧客が好みのステーブルコインとチェーンを選択可能。

USDC JPYC USDT
Polygon Kaia Avalanche Base

ガスレスチェックアウト

SMARTモードではERC-4337 Paymasterがガス代をスポンサー。FASTモードでもRelayerが代理送信し、USDC/JPYCはガス代無料です。顧客はガス代を気にせずチェックアウトできます。

直接入金

チェックアウトが完了すると、指定のウォレットアドレスに直接送金されます。中間の保管はなく、数秒で資金を受け取れます。

WalletConnect対応

MetaMaskやRainbow等のWalletConnect対応ウォレットからもチェックアウト可能。BitVoyアカウントを持たない顧客にも対応でき、決済の間口が広がります。


チェックアウトフロー

スニペットがIntent発行からチェックアウトページへのリダイレクトまでを自動で処理します。チェックアウト完了後、WebhookとリダイレクトでECサイトに結果が通知されます。

ECサイト
注文確定
チェックアウト
BitVoy
Intent自動発行
(スニペット)
BitVoy
チェックアウトページ
パスキー認証
+ 送金
Webhook
intent.succeeded
注文確定処理
完了ページ
return_url
リダイレクト

詳細シーケンス

Payment Sequence Diagram

Intent ステータス遷移

CREATED PRESENTED AUTHORIZED PROCESSING SUCCEEDED
ステータス説明
CREATEDIntent発行済み、ユーザー未操作
PRESENTEDユーザーがチェックアウト画面を表示
AUTHORIZEDパスキー認証・送金承認完了
PROCESSINGトランザクション送信済み、チェーン確認待ち
SUCCEEDEDチェックアウト完了(ブロック確認済み)
FAILED送金失敗またはトランザクション revert
EXPIRED有効期限切れ(デフォルト15分)
CANCELEDユーザーがキャンセル

WalletConnect経由のチェックアウトフロー

Intent発行時のレスポンスには、2つのチェックアウトURLが含まれます。顧客の環境に応じて使い分けることができます。

フィールド対象ユーザー説明
payment_start_url BitVoyユーザー BitVoyウォレットでパスキー認証 → 送金。アカウント登録済みの顧客向け。
wc_payment_url 外部ウォレットユーザー MetaMask・Rainbow等のWalletConnect対応ウォレットで直接決済。BitVoyアカウント不要。
Intent発行
POST /intents
ECサイト
チェックアウト方法を選択
または両方提示
payment_start_url
BitVoyウォレット
パスキー認証
wc_payment_url
外部ウォレット
WalletConnect

スニペットで簡単導入

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-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-lang任意表示言語(ja / en。省略時はブラウザ言語)
data-wc任意WalletConnectボタンの表示(デフォルト: true。false で非表示)

チェーン選択はスニペットのUIで顧客が行います。通貨ごとに対応チェーンが自動表示されます。


導入手順

1

クライアント登録

登録フォームから申請してください。以下の情報をご用意いただきます:

登録完了後、以下の認証情報が発行されます:

2

スニペットを設置

チェックアウトページに上記のスニペットコードを貼り付け、data-client-id に発行されたクライアントIDを設定します。 金額・通貨・注文番号はサーバーサイドでHTMLに埋め込んでください。

3

Webhook受信エンドポイントを実装

intent.succeeded イベントを受け取り、注文ステータスを「支払い済み」に更新します。 必ず X-BitVoy-Signature を検証してください。

4

チェックアウト完了ページを実装

data-return-url に指定したURLでユーザーを受け取り、注文完了画面を表示します。 クエリパラメータに intent_idtxid が付与されます。


API リファレンス

スニペットを使用せず、独自のチェックアウトUIを実装したい場合に利用できるAPIです。Intent発行・ステータス確認・Webhook検証をサーバーサイドから直接制御できます。

ベースURL: https://bitvoy.org

POST /oidc-payment/intents

Checkout Intentを発行します。ECサイトのサーバーサイドから呼び出してください。

リクエストパラメータ

パラメータ必須説明
rp_client_id必須クライアントID
client_secret必須クライアントシークレット
order_ref必須ECサイト側の注文番号(冪等性キー)
amount必須金額(人間が読める単位。例: "100" = 100 JPYC)
currency必須通貨コード: USDC / JPYC / USDT
payee必須入金先ウォレットアドレス(文字列またはオブジェクト)
chain必須polygon / kaia / avalanche / base
execution_mode任意FAST(デフォルト)/ SMART(ガスレス)
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",
  "wc_payment_url": "https://bitvoy.org/wc/pay/int_xxx"
}

payment_start_url にユーザーをリダイレクトすると、BitVoyチェックアウトページが表示されます。wc_payment_url はWalletConnect対応の外部ウォレットからチェックアウトする場合のURLです。

リダイレクト時に &lang=ja または &lang=en を付与すると、決済画面の表示言語を指定できます。省略時は英語になります。

GET /oidc-payment/intents/{intent_id}

Intentのステータスとチェックアウト結果を確認します。

認証

Authorization: Basic BASE64(client_id:) または ?client_id={client_id}

レスポンス例(SUCCEEDED)

{
  "intent_id": "int_01KK8VGFWGNQ62CAB3MA1N69B7",
  "status": "SUCCEEDED",
  "amount": "100",
  "currency": "JPYC",
  "chain": "avalanche",
  "order_ref": "ORDER-12345",
  "payee": {
    "type": "address",
    "address": "0x1234...abcd"
  },
  "expires_at": "2026-03-20T09:15:00.000Z",
  "created_at": "2026-03-20T09:00:00.000Z",
  "execution_mode": "SMART",
  "metadata": { "source": "my-ec-site" },
  "result": {
    "paid_at": "2026-03-20T09:01:00.000Z",
    "tx_hash": "0xf7a41da56eb6b4b276bc3c7d84d94d6944cc8fc9...",
    "chain": "avalanche",
    "paid_amount": "100"
  }
}

注意: ステータスが FAILED の場合、fail_codefail_reason フィールドが追加されます。

Webhook通知

Intentのステータスが変化するたびに、登録された webhook_url にPOSTリクエストが送信されます。

イベント一覧

イベントタイミング
intent.createdIntent発行時
intent.succeededチェックアウト完了時
intent.failedチェックアウト失敗時
intent.expired有効期限切れ時
intent.canceledユーザーがキャンセル時

Webhookペイロード例(intent.succeeded)

{
  "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ヘッダー

Webhookリクエストには以下のヘッダーが付与されます:

Header説明
X-BitVoy-Eventイベント名(例: intent.succeeded
X-BitVoy-Timestamp送信時刻(ISO 8601)
X-BitVoy-SignatureHMAC-SHA256署名(下記参照)

署名検証

Webhookリクエストには X-BitVoy-Signature ヘッダーが付与されます:

X-BitVoy-Signature: sha256=HEX(HMAC-SHA256(payload, webhook_secret))

実装例

Node.js (Express)

Intent発行(チェックアウト)

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: 'SMART',   // ガスレスチェックアウト
      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チェックアウトページにリダイレクト
  // payment_start_url: BitVoyウォレット(パスキー認証)
  // wc_payment_url:   外部ウォレット(WalletConnect)
  res.json({
    payment_url: data.payment_start_url,
    wc_payment_url: data.wc_payment_url
  });
});

Webhook受信

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 });
});

チェックアウト完了ページ(return_url)

// ユーザーが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 });
});

Python (Flask)

Intent発行

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': 'SMART',
        'return_url': f'https://shop.example.com/orders/{data["order_id"]}/complete',
    })

    intent = resp.json()
    return jsonify({'payment_url': intent['payment_start_url']})

Webhook検証

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-bitvoy">BitVoyウォレットで支払う</button>
<button id="pay-wc">外部ウォレットで支払う(MetaMask等)</button>

<script>
async function checkout() {
  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'
    })
  });
  return res.json();
}

// BitVoyウォレット(パスキー認証)で決済
// lang パラメータで決済画面の表示言語を指定('ja' | 'en')
document.getElementById('pay-bitvoy').addEventListener('click', async () => {
  const { payment_url } = await checkout();
  const lang = document.documentElement.lang || 'ja';
  window.location.href = payment_url + '&lang=' + lang;
});

// 外部ウォレット(WalletConnect)で決済
document.getElementById('pay-wc').addEventListener('click', async () => {
  const { wc_payment_url } = await checkout();
  const lang = document.documentElement.lang || 'ja';
  window.location.href = wc_payment_url + '?lang=' + lang;
});
</script>

よくある質問

Shopifyじゃなくても使えますか?

はい。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" を指定するだけで有効になり、顧客はガス代を意識せずステーブルコインのみで決済できます。

為替レートはどのように計算されますか?

法定通貨からステーブルコインへの変換が必要な場合は、ECサイト側で変換してからIntent発行時の amount に指定してください。BitVoy側でも /shopify/rate エンドポイントでCoinGeckoベースのレート取得が可能です。

手数料はかかりますか?

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が届かない場合は?

Webhookが届かない場合でも、GET /oidc-payment/intents/{intent_id} でステータスをポーリングできます。return_urlへのリダイレクト時にも intent_id が付与されるため、チェックアウト結果を確実に確認できます。

同じ注文で二重チェックアウトは発生しますか?

発生しません。order_ref にはクライアントごとにユニーク制約があるため、同じ注文番号で重複してIntentを発行することはできません。

返品・返金はどうなりますか?

ブロックチェーン上のトランザクションは取り消しできないため、返金はストア側からウォレットアドレスへ手動で送金する形になります。ECサイト上での返金処理は通常通り記録可能です。

導入のご相談

ステーブルチェックアウトの導入に興味がありましたら、お気軽にお問い合わせください。