言語を選択

Webhook

アクティベーションのイベントをリアルタイムでサーバーに受け取り、SmsGrab-Signature ヘッダーを検証します。再試行、テスト送信、自動無効化についても説明します。

このページの内容
  1. イベント
  2. Webhook を作成する
  3. 送信内容
  4. 署名を検証する
  5. すばやく応答する
  6. 再試行
  7. 自動無効化
  8. テストと再送

Webhook は、イベントが発生した時点であなたのサーバーに送信するので、問い合わせを繰り返す必要がありません。1 つの Webhook は 1 つの API キーに属し、そのキーで購入した番号のイベントと、アカウントの残高不足の警告を受け取ります。

イベント

イベント タイミング
activation.created 番号を購入した
activation.code_received 新しい SMS ごとに、それまでのすべてのメッセージとともに
activation.completed あなたが完了した、またはコード受信後に時間切れになった
activation.cancelled コードの前にキャンセル、返金済み
activation.expired 時間内にコードなし、返金済み
activation.refunded 請求が返金されるたびに
balance.low 残高が設定したしきい値を下回った
webhook.test あなたが開始したテスト送信

Webhook を作成する

アカウント > 開発者 でキーを開き、URL、受け取るイベント、任意の説明を指定して Webhook を追加します。1 つのキーに最大 3 つの Webhook を設定できます。

URL の条件:

  • https:// で始まる
  • IP アドレスではなくホスト名を使う
  • 公開アドレスを指す(プライベートネットワーク、localhost、それに類する範囲は拒否されます)

whsec_ で始まる署名シークレットが発行されます。API キーと同じく、表示されるのは 1 回だけです。あとで変更することもでき、その際もパスワードが必要です。

送信内容

HTTP
POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: SmsGrab-Webhooks/1.0
SmsGrab-Event: activation.code_received
SmsGrab-Delivery: 9f7d6c1e-2b44-4c1a-8f0e-6a3d2c1b0e9f
SmsGrab-Signature: t=1790503200,v1=3b9a0c…

{ "id": "evt_4e1f…", "type": "activation.code_received", "created_at": "2026-09-27T10:06:12.004Z",
  "api_version": "2026-09-27", "data": { "activation": { "id": "5c1d0c2e-…", "status": "CODE_RECEIVED" } } }

署名を検証する

SmsGrab-Signature には、タイムスタンプ t と v1 が含まれます。v1 は、t、ピリオド、リクエストの生のボディをつなげたものを、あなたのシークレットをキーとして HMAC-SHA256 で計算した値です。タイムスタンプがあなたの時計と 300 秒以上ずれている送信は拒否し、署名は定数時間で比較してください。

PHP
[$t, $v1] = (function (string $h): array {
    parse_str(str_replace(',', '&', $h), $p);
    return [(int) ($p['t'] ?? 0), (string) ($p['v1'] ?? '')];
})($_SERVER['HTTP_SMSGRAB_SIGNATURE'] ?? '');
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $t.'.'.$body, getenv('SMSGRAB_WEBHOOK_SECRET'));
$ok = abs(time() - $t) <= 300 && hash_equals($expected, $v1);
Python
import hmac, hashlib, time

def verify(header: str, body: bytes, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t = int(parts.get("t", "0"))
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return abs(time.time() - t) <= 300 and hmac.compare_digest(expected, parts.get("v1", ""))
JavaScript
import crypto from 'node:crypto';

export function verify(header, rawBody, secret) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const t = Number(parts.t ?? 0);
  const expected = crypto.createHmac('sha256', secret).update(`${t}.`).update(rawBody).digest('hex');
  const given = Buffer.from(parts.v1 ?? '', 'utf8');
  return Math.abs(Date.now() / 1000 - t) <= 300 && given.length === expected.length
    && crypto.timingSafeEqual(Buffer.from(expected, 'utf8'), given);
}

JSON をパースする前に、必ず受け取ったままの生のボディで検証してください。

すばやく応答する

10 秒以内 に任意の 2xx ステータスで応答し、時間のかかる処理はキューなどで後から行ってください。リダイレクトはたどりません。

再試行

失敗した送信は、1 分後、5 分後、15 分後、1 時間後、3 時間後、6 時間後、12 時間後、24 時間後に再試行されます。再試行には同じイベントの id が含まれるので、処理済みの ID を保存して重複をスキップしてください。1 つのアクティベーションのイベントは順番どおりに届きます。

自動無効化

  • 410 Gone で応答すると、Webhook はすぐに無効になります。
  • 24 時間以上にわたって 50 回連続で失敗すると Webhook は無効になり、通知が届きます。エンドポイントを修正してから、Webhook を再度有効にしてください。
  • キーを無効化すると、その Webhook も無効になります。

テストと再送

Webhook のページから webhook.test イベントを送信すると、ステータスコード、応答時間、エラーをすぐに確認できます。送信履歴にはすべての送信が 30 日間保存され、どれでも再送できます。

この記事は役に立ちましたか?

解決しませんでしたか?

お気軽にご連絡ください。すべてのメッセージに、通常は数時間以内に返信します。

メールでのお問い合わせ support@smsgrab.com