開発者向け
ウェブフック
請求書のステータスが変化すると、CryBitは加盟店のウェブフックURLに対して、署名付きのPOSTリクエスト(JSON形式)を送信します。
設定
加盟店設定の連携タブで、ウェブフックURLを設定し、通知するイベント(paid、expired、refunded、cancelled)にチェックを入れます。URLはポート80、443、8080、8443のいずれかを使用する、公開されたHTTPまたはHTTPSアドレスである必要があります。リダイレクトは追跡されません。この設定は請求書のリクエストではなく、加盟店単位で行います。
ヘッダー
| ヘッダー | 値 |
|---|---|
X-CryBit-Event | イベント名(例: payment.paid)。 |
X-CryBit-Signature | t=<unix time>,v1=<hex>: 署名シークレットを用いた"<t>.<raw body>"のHMAC-SHA256。 |
署名を検証する
署名シークレットは、加盟店設定のウェブフックURLの隣に表示されます。生のリクエストボディに対して署名を計算し、一定時間で比較したうえで、5分より古いリクエストは拒否してください。
PHP
$secret = getenv('CRYBIT_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_CRYBIT_SIGNATURE'] ?? '';
parse_str(str_replace(',', '&', $header), $p); // t=…&v1=…
$t = (int) ($p['t'] ?? 0);
$expected = hash_hmac('sha256', $t . '.' . $body, $secret);
if (abs(time() - $t) > 300 || !hash_equals($expected, $p['v1'] ?? '')) {
http_response_code(400);
exit;
}
// the request is genuine: store the event, answer 200, do the rest later
http_response_code(200);Node.js
import crypto from 'node:crypto'
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=')))
const t = Number(parts.t)
const expected = crypto.createHmac('sha256', secret).update(t + '.' + rawBody).digest('hex')
const ok = parts.v1 && parts.v1.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected))
return ok && Math.abs(Date.now() / 1000 - t) <= 300
}配信とリトライ
- 速やかに2xxのステータスで応答してください。CryBitは約12秒待機します。
- 応答がない場合、CryBitは15秒後、1分後、5分後、15分後、30分後、その後2時間後、6時間後、24時間後にリトライします。
- 429を除く4xxの応答があった場合、リトライは停止します。
- 同じイベントが複数回届くことがあるため、order_idまたは請求書のuuidをキーとして冪等に処理してください。
- ウェブフックを受け損ねた場合は、GET /api/v1/payments/{uuid}でステータスを確認してください。これが常に正となる情報源です。
FAQ
配信内容を確認できますか?
はい。加盟店アカウントのAPIログページでは、リクエストとウェブフックの配信履歴を、ステータスコードとボディとともに確認できます。
