# blockwallets ネイティブ REST API

> blockwallets のネイティブ REST API:Bearer キー、セント単位の請求と冪等な ref、入金アカウント、HMAC-SHA256 署名付き Webhook、イベントと再送。
>
> HTML: https://blockwallets.io/docs/api?lang=ja · English: https://blockwallets.io/docs/api.md?lang=en

## ネイティブ REST API

ネイティブ API は blockwallets 独自の REST インターフェースです。米セント建ての請求、注文ごとの冪等な `ref`、全ネットワークに対応する固定の入金アカウント、HMAC-SHA256 で署名された Webhook を備えています。[Cryptomus 互換 API](https://blockwallets.io/docs/cryptomus?lang=ja) と同じホスト型決済ページに同じ請求が作られ、手数料と残高も同じです。

キーは管理画面の「開発者 › 連携とキー」で自分で発行します:Live キーと Test キー、およびそれぞれの Webhook 署名シークレット。どれも表示は一度だけで、一覧にはプレフィックスしか表示されません。アカウントで二段階認証を有効にしている場合、Live キーの発行やローテーションにはコードの入力が必要です。加盟店アカウントがまだない場合は[利用を申し込んで](https://blockwallets.io/?lang=ja#join)ください。すでに Cryptomus を使っている場合は[Cryptomus 互換 API](https://blockwallets.io/docs/cryptomus?lang=ja)をご覧ください([選び方](https://blockwallets.io/docs?lang=ja#which))。

### キーとリクエスト

ベース URL は `https://blockwallets.io` です。リクエストとレスポンスは JSON で、すべてのリクエストに次を付けます。

- `Authorization: Bearer bw_live_…` または `Bearer bw_test_…`:プレフィックスでモードが決まります。Test キーには Test の請求だけが見え、テストネットで動作します

- `POST` リクエストには `Content-Type: application/json`

- キーはサーバー上だけで保管し、ウェブページやアプリには絶対に入れないでください。当社にはそのハッシュだけを保存します

エラーは HTTP ステータスと `{"error": {"code": "…", "message": "…"}}` で返ります:400 `invalid_request`(フィールドの不足または形式不正)、401 `unauthorized`(キーがない、不明、または無効)、404 `not_found`、409 `conflict`(請求の現在の状態と矛盾するリクエスト)、422 `currency_unsupported`。

### エンドポイント

| エンドポイント | 内容 |
| --- | --- |
| `GET /v1/networks` | このキーのモードで現在受け付けられるネットワーク:最低額、承認数、通常の着金時間、手数料の目安。レート付きの通貨には現在のレートも含まれます |
| `POST /v1/invoices` | 請求を作成(201)、または同じ `ref` の既存の請求を返す(200) |
| `GET /v1/invoices?ref=…` | 自分の `ref` で請求を照会 |
| `GET /v1/invoices/:id` | id で請求を照会 |
| `POST /v1/invoices/:id/network` | 請求のネットワークを自分で選択(ホワイトラベルの決済ページ向け):表示用の `address` と `pay_amount` が返ります |
| `POST /v1/invoices/:id/close` | 送金がまだ見つかっていない支払い待ちの請求を閉じる |
| `POST /v1/deposit-accounts` | 1人のお客様の入金アカウントを開設(201)または取得(200):全ネットワークの恒久アドレス |
| `GET /v1/deposit-accounts?customer_ref=…` | `customer_ref` で入金アカウントを照会 |
| `GET /v1/deposit-accounts/:id` | id で入金アカウントを照会 |
| `GET /v1/deposits` | 1つのアカウントの入金一覧(`account_id` または `customer_ref`、`limit` は 1〜200、既定 50) |
| `GET /v1/deposits/:id` | 入金を1件照会 |
| `GET /v1/events` | 1つの請求または入金の Webhook 配信履歴(`invoice_id` または `deposit_id`) |
| `POST /v1/events/:id/redeliver` | Webhook を再送(202) |

請求または入金アカウントの照会に `?probe=1` を付けると、その場でチェーンも確認します(10 秒に1回まで)。付けない場合は、毎分確認しているスキャナーの最新の状態が返ります。

### 請求を作成 POST /v1/invoices

お客様が会計に進んだら `POST /v1/invoices` を呼び出し、レスポンスの `pay_url` へリダイレクトします。

```curl
curl -X POST https://blockwallets.io/v1/invoices \
  -H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
  -d '{"ref":"order_1042","amount":4200,"title":"Order #1042",
       "return_url":"https://shop.example/cart","success_url":"https://shop.example/thanks?order=1042",
       "meta":{"user_id":42}}'
```

| フィールド | 必須 | 説明 |
| --- | --- | --- |
| `ref` | はい | 注文番号:英字、数字、`_ . : -` で 1〜64 文字。モードごとに一意です。同じ `ref` を同じフィールドで再送すると同じ請求が返り、フィールドが異なると 409 が返ります |
| `amount` | はい | 米セント単位の整数の金額:`4200` = $42.00。ネットワークを選んだあとは、そのネットワークの最低額を下回れません |
| `title` | はい | 決済ページに表示される内容、64 文字以内 |
| `return_url` | はい | 決済ページの「戻る」の遷移先。サイトのドメイン上である必要があります |
| `success_url` | いいえ | 支払い後にお客様が移動する先。既定は `return_url` |
| `network` | いいえ | [ネットワーク表](https://blockwallets.io/docs/api?lang=ja#networks)のネットワーク id を事前選択します。省略すると、お客様が決済ページで選びます |
| `customer_ref` | いいえ | お客様の id、64 文字以内、そのまま返されます |
| `lifetime` | いいえ | 有効期間(秒)、600〜43200、既定 3600 |
| `amount_rule` | いいえ | `"any"` = 届いた分をすべて計上(チャージ向け):承認され次第 `paid`。省略すると管理画面「設定 › 支払いルールと料率」の「受取金額のルール」が適用されます |
| `accuracy_percent` | いいえ | 不足払いをどこまで支払い済みとみなすか、0〜5(パーセント)、既定 0 |
| `subtract_percent` | いいえ | プラットフォーム手数料のうちお客様が負担する割合、0〜100(パーセント)。`pay_amount` に上乗せされます。省略すると管理画面の既定値が適用されます |
| `payment_multiple` | いいえ | 不足した支払いに同じアドレスへ追加入金できるかどうか。既定は管理画面の設定(変更していなければオン)。`false`:最初の不足した送金で `wrong_amount` として終了します |
| `meta` | いいえ | 2 KB までの任意の JSON オブジェクト。照会と Webhook でそのまま返されます |
| `currency` | いいえ | `USD` のみ(既定)。それ以外は 422 が返ります |

すべての URL はサイトのドメイン上である必要があります(管理画面 →「開発者 › 連携とキー」)。レスポンスは下記の請求オブジェクトです。`network`、`address`、`pay_amount` は、ネットワークが選ばれたあとに設定されます。

### 請求オブジェクト

id は `inv_` で始まります。`amount` は米セント、`pay_amount` と `paid_amount` は選ばれたネットワーク上のコイン数量(小数の文字列)です。

```json
{
  "id": "inv_01J8…",
  "ref": "order_1042",
  "mode": "live",
  "status": "pending",
  "amount": 4200,
  "currency": "USD",
  "title": "Order #1042",
  "meta": { "user_id": 42 },
  "network": null,
  "address": null,
  "pay_amount": null,
  "paid_amount": null,
  "payments": [],
  "pay_url": "https://blockwallets.io/pay/inv_01J8…",
  "return_url": "https://shop.example/cart",
  "success_url": "https://shop.example/thanks?order=1042",
  "created_at": "2026-11-03T08:00:00.000Z",
  "expires_at": "2026-11-03T09:00:00.000Z",
  "paid_at": null,
  "closed_at": null
}
```

| status | 意味 | あなたの対応 |
| --- | --- | --- |
| `pending` | 支払い待ち | — |
| `confirming` | 送金を検知して承認待ち、または不足して届いたが追加入金が可能 | — |
| `paid` | 支払済み | 発送または入金処理 |
| `paid_over` | 支払済み(超過払い) | 同じ。超過分は残高に入ります |
| `wrong_amount` | 全額に満たないまま終了(期限切れ、または `payment_multiple` が false の場合は最初の不足した送金) | チャージ型の事業は届いた分(`paid_amount`。レート建ての通貨は `paid_cents` も)を計上できます。ショップは残りの支払いをお客様に依頼します |
| `closed` | 入金なしで期限切れ、またはあなたが閉じた | —(あとから届いた入金も計上され、通知されます) |

その他のフィールド:`pay_url`(ホスト型決済ページ)、`payments`(各送金の `txid`、`amount`、`confirmations`、`confirmed`)、`expires_at`、`paid_at`、`closed_at`。BTC、LTC、DOGE、BCH、ネイティブ通貨には `rate`(コイン1枚あたりの米ドル、30 分間固定)、`rate_locked_until`、`paid_cents`(届いた分の米セント換算)も付きます。

### ネットワーク

id を `network` として渡します。`GET /v1/networks` は、現在のモードで利用できるネットワークを返します。ネットワークは一時停止されることがあるため、固定で書き込まず、この結果を読んでください。

| network | 通貨 | チェーン | 最低額 |
| --- | --- | --- | --- |
| `USDT_TRC20` | USDT | TRON | $1 |
| `USDT_BEP20` | USDT | BNB Chain | $1 |
| `USDC_BEP20` | USDC | BNB Chain | $1 |
| `USDT_ERC20` | USDT | Ethereum | $5 |
| `USDC_ERC20` | USDC | Ethereum | $5 |
| `USDC_BASE` | USDC | Base | $1 |
| `USDT_POLYGON` | USDT | Polygon | $1 |
| `USDC_POLYGON` | USDC | Polygon | $1 |
| `USDT_ARBITRUM` | USDT | Arbitrum | $1 |
| `USDC_ARBITRUM` | USDC | Arbitrum | $1 |
| `USDT_OPTIMISM` | USDT | Optimism | $1 |
| `USDC_OPTIMISM` | USDC | Optimism | $1 |
| `USDT_AVALANCHE` | USDT | Avalanche | $1 |
| `USDC_AVALANCHE` | USDC | Avalanche | $1 |
| `USDT_XLAYER` | USDT | X Layer | $1 |
| `USDC_XLAYER` | USDC | X Layer | $1 |
| `USD1_BEP20` | USD1 | BNB Chain | $1 |
| `FDUSD_BEP20` | FDUSD | BNB Chain | $1 |
| `DAI_ERC20` | DAI | Ethereum | $5 |
| `DAI_ARBITRUM` | DAI | Arbitrum | $1 |
| `DAI_BASE` | DAI | Base | $1 |
| `BTC` | BTC | Bitcoin | $5 |
| `LTC` | LTC | Litecoin | $1 |
| `DOGE` | DOGE | Dogecoin | $1 |
| `BCH` | BCH | Bitcoin Cash | $1 |
| `TRX` | TRX | TRON | $1 |
| `BNB` | BNB | BNB Chain | $1 |
| `ETH` | ETH | Ethereum | $5 |
| `ETH_BASE` | ETH | Base | $1 |
| `ETH_ARBITRUM` | ETH | Arbitrum | $1 |
| `ETH_OPTIMISM` | ETH | Optimism | $1 |
| `POL` | POL | Polygon | $1 |
| `AVAX` | AVAX | Avalanche | $1 |
| `OKB` | OKB | X Layer | $1 |
| `USDT_SOL` | USDT | Solana | $1 |
| `USDC_SOL` | USDC | Solana | $1 |
| `SOL` | SOL | Solana | $1 |
| `USDT_TON` | USDT | TON | $1 |
| `TON` | TON | TON | $1 |

### 入金アカウント(固定アドレス) POST /v1/deposit-accounts

`POST /v1/deposit-accounts` に `{"customer_ref": "user_42"}` を渡すと、そのお客様に全ネットワークの恒久アドレスが発行されます(すべての EVM チェーンは1つのアドレスを共有)。届いた分はすべて米ドルで計上され、送金ごとに `deposit.credited` の Webhook が1回届きます。

```curl
curl -X POST https://blockwallets.io/v1/deposit-accounts \
  -H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
  -d '{"customer_ref":"user_42"}'
```

```json
{
  "id": "dac_01J8…",
  "mode": "live",
  "customer_ref": "user_42",
  "deposit_url": "https://blockwallets.io/deposit/dac_01J8…",
  "min_amount": 100,
  "currency": "USD",
  "networks": [
    { "id": "USDT_TRC20", "chain": "tron", "token": "USDT", "address": "TXy4…8kQ2", "min_amount": 100, "confirmations": 1, … },
    { "id": "USDC_BASE", "chain": "base", "token": "USDC", "address": "0x5aE1…", "min_amount": 100, "confirmations": 20, … }
  ]
}
```

- `customer_ref`:英字、数字、`_ . : @ -` で 1〜128 文字。同じ値からは常に同じアカウントが返ります。任意の `return_url` はあなたのドメイン上のもの

- レスポンスには `deposit_url`(アドレス、QR コード、最近の入金を表示するホスト型ページ)と `networks`(各ネットワークの `id`、`address`、`min_amount`、`confirmations`)が含まれます

- 入金の id は `dep_` で始まります。`amount` は米セント、`amount_token` はコイン数量で、レート付きの通貨には使用した `rate` が付きます

最低額(通常 $1、BTC $5)未満の送金は `below_min` として記録され、自動では計上されません。計上が必要な場合はご連絡ください。

### Webhook

管理画面(「開発者 › 連携とキー」。Live と Test にはそれぞれ専用の URL とシークレットがあります)の Webhook URL に JSON を POST します。ボディがそのままイベントです。

```http
POST /your/webhook
X-BW-Event: ev_01J8…
X-BW-Delivery: 1
X-BW-Signature: t=1793693052,v1=5f0c9b…

{"id":"ev_01J8…","type":"invoice.paid","created_at":"2026-11-03T08:04:12.000Z","invoice":{"id":"inv_01J8…","ref":"order_1042","status":"paid","amount":4200,…}}
```

- `X-BW-Signature`:`t=<unix seconds>,v1=<hex>`。`v1` = HMAC-SHA256(そのモードの Webhook シークレット, `t` + `.` + 生のボディ)

- `X-BW-Event`:イベント id(`ev_…`)。これで重複を排除します

- `X-BW-Delivery`:1 から始まる試行回数

| イベント | タイミング |
| --- | --- |
| `invoice.paid` | 請求が `paid` または `paid_over` になった(期限後に届いた入金を含む) |
| `invoice.wrong_amount` | 請求が `wrong_amount` で終了した |
| `invoice.closed` | 請求が入金なしで期限切れになった、またはあなたが閉じた |
| `deposit.credited` | 入金アカウントへの送金が計上された |

解析する前に生のボディで検証し、`t` がご自身の時計から 300 秒を超えて離れているものは拒否し、比較は定数時間で行ってください。ボディの `invoice` / `deposit` は、照会で返るものと同じオブジェクトです。

```nodejs
import crypto from "node:crypto";

// rawBody: the request body exactly as received (a string), header: X-BW-Signature
function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.trim().split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return typeof parts.v1 === "string" && parts.v1.length === expected.length
    && crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}
```

2xx の応答で配信済みとみなし、それ以外は 1 分後、5 分後、30 分後、2 時間後、12 時間後、24 時間後、24 時間後に再試行します(合計 8 回)。

### イベントと再送

`GET /v1/events?invoice_id=inv_…`(または `deposit_id=dep_…`)は、1つの請求または入金の Webhook を `state`、`attempts`、`last_status`、`last_error` とともに一覧します。`POST /v1/events/ev_…/redeliver` はすぐに再度キューに入れます(エンドポイントを直した直後などに使います)。管理画面の「開発者 › Webhook ログ」では、すべての試行をリクエストとレスポンス付きで確認できます。

### テストモード

`bw_test_` キーで作成した請求はテストネットで動き、本物のお金は動きません。ホスト型決済ページには「決済をシミュレート」ボタン(全額 / 半額 / 超過払い)が表示されるので、テストネットのコインを用意しなくても、状態の変化と Webhook を確認できます。
