Sign in
はじめに/認証

認証とリクエスト署名

プロジェクト UUID と API キーを使用して、HMAC-SHA256 で API リクエストに署名します。

すべての API リクエスト(受信 Webhook を除く)には、プロジェクト UUID とリクエスト署名を含める必要があります。署名は、リクエストがあなたから送信されたものであり、途中で誰にも改ざんされていないことを証明します。

API キー

2328.io は、同一の署名アルゴリズムを共有しつつ異なるエンドポイントに対応する 2 つのキー を使用します:

KeyUsed for
API key支払い、固定ウォレット、残高、為替レート、および支払い/固定ウォレット Webhook の検証
Payout API keyすべての /v1/payout/* エンドポイントおよび出金 Webhook の検証

両方のキーは 2328.io のプロジェクト設定にあります。以下の例では便宜上「API key」と総称していますが、呼び出すエンドポイントに応じて適切なキーに置き換えてください。

絶対に 2 つのキーを混在させないでください。通常の API キーで出金リクエストに署名する(または出金キーで支払いリクエストに署名する)と署名エラーが返されます。

必須ヘッダー

HeaderTypeRequiredDescription
Content-Typestringyes常に application/json
projectstringyesプロジェクト UUID
signstringyesAPI キーで計算したリクエストの HMAC-SHA256 署名
User-Agentstringはいあなたのアプリケーションを識別します(例: MyShop/1.4 (+https://myshop.example))。User-Agent がないリクエストはブロックされる場合があります。

署名の仕組み

署名はリクエストボディのフィンガープリントだと考えてください。次の手順で生成します:

  1. ボディを JSON にシリアライズします(コンパクト — 余分な空白なし)。
  2. その JSON を Base64 でエンコードします。この手順により、入力が言語間で正規化されます — 純粋な ASCII になれば、どの言語でも HMAC に対して同じバイト列が生成されます。
  3. API キーで Base64 文字列の HMAC-SHA256 を計算し、結果を小文字の 16 進数に変換します。

GET やボディを持たないその他のリクエストタイプでは、JSON の代わりに空文字列に署名します。

空文字列の署名は、ある API キーに対して定数になります。GET 呼び出しが多い場合はキャッシュできます。

実装例

PHP
<?php
function apiSign(array $data, string $apiKey): string {
    $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    $base64 = base64_encode($json);
    return hash_hmac('sha256', $base64, $apiKey);
}

ボディなしリクエスト(GET)

ボディが空のリクエスト(例:GET /v1/payout/status/{uuid})では、空文字列に署名します:

Shell
SIGN=$(printf '' | openssl dgst -sha256 -hmac "$API_KEY" -hex | awk '{print $NF}')

完全なリクエスト例

Shell
curl -X POST https://api.2328.io/api/v1/payment \
  -H "Content-Type: application/json" \
  -H "User-Agent: MyShop/1.0 (+https://myshop.example)" \
  -H "project: YOUR_PROJECT_UUID" \
  -H "sign: YOUR_HMAC_SIGNATURE" \
  -d '{"amount":"100.00","currency":"USD","order_id":"ORDER-123"}'

API キーをクライアントサイドのコードに絶対に公開しないでください。 リクエストはバックエンドで署名してください。API キーが漏洩すると、誰でもマーチャントアカウントにフルアクセスできてしまいます。

Webhook 署名の検証

2328.io から Webhook が送信される際、同じアルゴリズムが逆向きに実行されます:

  1. ペイロードから sign フィールドを取り出します。
  2. 残りのフィールドを JSON エンコードします(コンパクト、空白なし)。
  3. その文字列を Base64 エンコードします。
  4. 適切なキーで HMAC-SHA256 を計算します。
  5. 受信した sign定数時間 の比較(hash_equalscrypto.timingSafeEqualhmac.compare_digestsubtle.ConstantTimeCompareOpenSSL.fixed_length_secure_compare)で比較します。

署名キーは Webhook の発生元によって異なります:

WebhookKey to verify with
支払い/固定ウォレットの Webhook(/v1/payment/v1/static-walletAPI key
出金 Webhook(/v1/payoutPayout API key

検証でよくある落とし穴。 あなたの JSON エンコーダーは送信側と完全に同じバイト列を生成する必要があります — そうでないと Base64 が変わり、署名が一致しません。

  • Go: json.NewEncoder を使い、SetEscapeHTML(false) を設定してください。デフォルトの json.Marshal<>&< にエスケープし、署名を壊します。
  • Python: json.dumpsensure_ascii=False を渡してください。これがないと、非 ASCII(キリル文字、中国語など)が \uXXXX にエスケープされます。
  • コンパクト JSON: フィールド間に空白を入れないこと(Python では separators=(",", ":"))。
  • フィールド順序(Go): 素の map[string]any は再エンコード時にキーをランダム化します。json.RawMessage、順序付き struct を使うか、生バイトから sign を取り除いてください。

検証が失敗し続ける場合は、ペイロードに対して自分で apiSign を実行してみてください — 受信した sign と同じ 16 進文字列を生成する必要があります。

有効な署名はリプレイを防ぎません。 署名は webhook が 2328.io から来たことを証明するだけで — 攻撃者がキャプチャした webhook を後から再送信するのを防ぐものではありません。資金を入金する前に、必ず uuid(静的ウォレットの場合は txid)で冪等性を確認してください。署名が欠落しているか不正な場合は HTTP 401 で拒否してください。

完全なコード例は Webhook 通知 にあります。リトライ処理と冪等性のルールは ベストプラクティス を参照してください。