Aller au contenu

Webhooks

Ereignisse empfangen, Signaturen prüfen, Wiederholungen verstehen.

Endpunkt anlegen

Unter Entwickler → Webhooks oder per API:

curl https://api.freika.com/v1/webhook_endpoints \
  -H "Authorization: Bearer $FREIKA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://deinshop.ch/webhooks/freika",
    "events": ["payment.succeeded", "payment.failed", "refund.succeeded", "payout.paid"]
  }'

Die Antwort enthält das secret (beginnt mit whsec_). Es wird nur einmal angezeigt.

Ereignisse

EreignisWann
payment.createdZahlung erstellt
payment.authorizedBetrag reserviert
payment.succeededZahlung erfolgreich
payment.failedZahlung abgelehnt oder fehlgeschlagen
payment.canceledZahlung abgebrochen oder abgelaufen
refund.succeeded, refund.failedRückerstattung ausgeführt oder gescheitert
payout.paidAuszahlung überwiesen
chargeback.createdRückbuchung eingegangen
terminal.online, terminal.offlineTerminalstatus geändert

Aufbau

{
  "id": "evt_01J9X3B7",
  "type": "payment.succeeded",
  "created_at": "2026-09-10T09:01:12Z",
  "environment": "live",
  "data": { "id": "pay_01J9X3A4Q6", "status": "succeeded", "amount": 8900 }
}

Signatur prüfen

Jede Zustellung trägt den Header Freika-Signature:

Freika-Signature: t=1757494872,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Prüfe so:

  1. Nimm den Rohtext des Bodys (nicht neu serialisieren).
  2. Bilde t + "." + body und berechne HMAC-SHA256 mit deinem secret.
  3. Vergleiche mit v1 in konstanter Zeit.
  4. Lehne Ereignisse ab, deren t älter als 5 Minuten ist.
import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret: string, header: string, rawBody: string): boolean {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Antworten und Wiederholungen

Antworte innert 10 Sekunden mit 2xx. Alles andere gilt als Fehlschlag. Wir wiederholen mit wachsendem Abstand bis zu 3 Tage lang: nach 1, 5, 30 Minuten, dann stündlich, dann alle 6 Stunden. Ereignisse können mehrfach ankommen; verarbeite sie idempotent anhand von id.

Zustellprotokoll

Unter Entwickler → Webhooks → Zustellungen siehst du jede Zustellung mit Antwortcode und kannst sie erneut senden. Per API: POST /v1/events/{id}/resend.

Testen

Testereignis senden im Dashboard schickt ein payment.succeeded mit Beispieldaten an deinen Endpunkt. In der Sandbox kannst du Zahlungen durchspielen und die echten Ereignisse empfangen.