Dokumentation

1. Ein Event veröffentlichen

curl -X POST https://hookpulse.altixcode.com/api/v1/apps/APP_ID/events \
  -H "Authorization: Bearer hp_…" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "invoice.paid",
    "payload": { "id": "in_123", "amount": 4900 },
    "dedupeKey": "invoice-123-paid"
  }'

Der Aufruf kehrt zurück, sobald das Event gespeichert und in die Warteschlange eingereiht ist. Übergeben Sie einen dedupeKey, dann sendet ein Retry aus Ihrem Job-Runner das Event nicht zweimal.

2. Was Ihr Kunde erhält

POST /their/endpoint
Content-Type: application/json
HookPulse-Signature: t=1700000000,v1=<base64 hmac>
HookPulse-Delivery-Id: dlv_…
HookPulse-Timestamp: 1700000000

{"id":"evt_…","type":"invoice.paid","createdAt":"…","data":{…}}

3. Die Verifizierung

Geben Sie Ihren Kunden das hier. Die zwei Fehler, die alle machen: der Vergleich mit === und das Ignorieren des Zeitstempels — und beide fallen nicht auf.

import { createHmac, timingSafeEqual } from 'node:crypto'

function verify(headers, rawBody, secret, toleranceSeconds = 300) {
  const header = headers['hookpulse-signature']
  const deliveryId = headers['hookpulse-delivery-id']
  const timestamp = Number(/t=(\d+)/.exec(header)?.[1])

  // Replay protection. Without this a captured request is valid forever.
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false

  const expected = createHmac('sha256', secret)
    .update(`${deliveryId}.${timestamp}.${rawBody}`)
    .digest('base64')

  return [...header.matchAll(/v1=([^,]+)/g)].some(([, presented]) => {
    const a = Buffer.from(presented)
    const b = Buffer.from(expected)
    return a.length === b.length && timingSafeEqual(a, b)
  })
}

Verifizieren Sie gegen den rohen Body, vor jedem JSON-Parsing. Erneutes Serialisieren verändert die Bytes, und dann schlägt jede Signatur fehl.

4. Ein Secret rotieren

Beim Rotieren wird ein neues Secret gesetzt, während das alte für einen von Ihnen gewählten Zeitraum gültig bleibt. Wir signieren sofort mit dem neuen, damit Ihre Kunden zur Migration angestoßen werden — ein Empfänger, der noch gegen das alte Secret prüft, funktioniert aber weiter, bis der Zeitraum endet.

5. Das Zustellungsprotokoll

Erzeugen Sie in Ihrem Backend ein Portal-Token — aufgebaut wie eine Webhook-Signatur und auf einen Ihrer Kunden ausgestellt — und rufen Sie die Portal-API von Ihrer eigenen Einstellungsseite aus auf. Jede Abfrage ist auf den Subscriber in diesem Token beschränkt, sodass keiner Ihrer Kunden jemals die Payloads eines anderen sehen kann.

GET  https://hookpulse.altixcode.com/api/portal/APP_ID/deliveries
POST https://hookpulse.altixcode.com/api/portal/APP_ID/deliveries/DELIVERY_ID/retry
Authorization: Bearer <portal token>

Oder einbetten

Fügen Sie bei Pro und Scale einfach &lt;hookpulse-log&gt; in Ihre Einstellungsseite ein, anstatt eine eigene Tabelle zu erstellen. Gleicher Token, gleicher Gültigkeitsbereich – das Log wird direkt für Sie gerendert, und dank Shadow Root gibt es keine Konflikte mit dem CSS Ihrer Seite.

<script src="https://hookpulse.altixcode.com/embed/hookpulse-log.js"></script>
<hookpulse-log app-id="APP_ID" token="PORTAL_TOKEN" api-url="https://hookpulse.altixcode.com"></hookpulse-log>

Ehrliche Grenzen