Browse Events Webhooks

stable · guide · 0.1.0

接收 Domain Event Webhook

驗證並處理 webhook

  1. 在解析 JSON 前,先拒絕超過五分鐘的 X-MiniCenter-Timestamp,並以訂閱 secret 對 timestamp.delivery_id.raw_body 計算 HMAC-SHA256;使用 constant-time compare 核對 X-MiniCenter-Signaturesha256= 值。
  2. 驗證 X-MiniCenter-Event-ID 與 body 的 id 相同,再用 Event Reference 的 canonical schema 驗證 envelope。
  3. X-MiniCenter-Delivery-ID 防止重播,並以事件 id 作為處理結果唯一鍵;已處理的事件直接回覆成功。
  4. stream_id 時,確認 sequence 緊接上一筆事件。
  5. 先持久化處理結果,再回覆成功;失敗時讓 MiniCenter 重試。
JSON example
{
  "id": "10000000-0000-4000-8000-000000000001",
  "type": "files.object.available",
  "schema_version": 1,
  "occurred_at": "2026-07-30T09:00:00Z",
  "published_at": "2026-07-30T09:00:01Z",
  "stream_id": "file-object-42",
  "sequence": 1,
  "correlation_id": "20000000-0000-4000-8000-000000000002",
  "data": {"object_id": "42"}
}

不要假設全域事件順序。若同一 stream 出現 sequence 缺口,先暫停該 stream 並修復快照。

執行簽章驗證範例

以下範例只需要 PHP。複製程式碼後執行,即會建立一組完整 headers、驗證五分鐘時效與 HMAC 簽章,最後輸出已驗證的事件 ID:

PHP example
$secret = 'replace-with-subscription-secret';
$body = '{"id":"10000000-0000-4000-8000-000000000001","type":"files.object.available","schema_version":1}';
$timestamp = (string) time();
$deliveryId = 'delivery-example-1';
$headers = [
    'X-MiniCenter-Delivery-ID' => $deliveryId,
    'X-MiniCenter-Event-ID' => '10000000-0000-4000-8000-000000000001',
    'X-MiniCenter-Timestamp' => $timestamp,
    'X-MiniCenter-Signature' => 'sha256='.hash_hmac(
        'sha256',
        $timestamp.'.'.$deliveryId.'.'.$body,
        $secret,
    ),
];

if (abs(time() - (int) $headers['X-MiniCenter-Timestamp']) > 300) {
    throw new RuntimeException('Expired webhook.');
}
$expected = 'sha256='.hash_hmac(
    'sha256',
    $headers['X-MiniCenter-Timestamp'].'.'.$headers['X-MiniCenter-Delivery-ID'].'.'.$body,
    $secret,
);
if (! hash_equals($expected, $headers['X-MiniCenter-Signature'])) {
    throw new RuntimeException('Invalid signature.');
}
$event = json_decode($body, true, flags: JSON_THROW_ON_ERROR);
if ($headers['X-MiniCenter-Event-ID'] !== $event['id']) {
    throw new RuntimeException('Event ID mismatch.');
}

echo "Verified {$event['id']}\n";