DEV Community

Cover image for Wie man Stripe Webhooks in CI mit Apidog erfasst und validiert
Emre Demir
Emre Demir

Posted on • Originally published at apidog.com

Wie man Stripe Webhooks in CI mit Apidog erfasst und validiert

Ein Kunde bezahlt, Stripe sendet ein payment_intent.succeeded-Ereignis an Ihr Backend, und Ihr Endpunkt soll die Bestellung als bezahlt markieren. Genau dieser letzte Schritt kann stillschweigend fehlschlagen: Der Webhook trifft ein, Ihr Handler wirft einen Fehler, und niemand bemerkt es bis zum Support-Ticket: „Ich habe bezahlt, aber mein Konto wird weiterhin als unbezahlt angezeigt.“ Ein CI-Test sollte deshalb bei jedem Release beweisen, dass das Ereignis empfangen und verarbeitet wurde.

Apidog noch heute ausprobieren

Der schwierige Teil: Ein Webhook ist ein eingehender HTTP-Aufruf von Stripe an Ihre Anwendung, keine Anfrage, die Ihr Testtool selbst sendet. Die meisten API-Testwerkzeuge sind auf das Gegenteil ausgelegt. Dieser Leitfaden zeigt den unterstützten Weg mit Apidog: Webhooks im eigenen Backend erfassen, persistent speichern und anschließend in CI validieren. Einen allgemeinen Einstieg bietet der Leitfaden zum Testen von Webhooks; das Zustellungsmodell beschreibt die Stripe-Webhook-Dokumentation.

Die entscheidende Einschränkung

Laut Apidogs Dokumentation unterstützt Apidog kein natives Abhören eingehender Webhooks. Sie können Stripe also nicht auf eine öffentliche Apidog-Listener-URL richten und Ereignisse dort in Echtzeit abfangen.

Das ist keine Sackgasse, sondern bestimmt die Testarchitektur:

  1. Ihr Backend empfängt und validiert den Stripe-Webhook.
  2. Ihr Backend speichert das Ereignis in der Datenbank.
  3. Apidog fragt den gespeicherten Datensatz ab.
  4. Der Test validiert Ereignis und fachliche Seiteneffekte.

Dieses Erfassungs-und-Abfrage-Muster ist CI-tauglich, weil Datenbankabfragen deterministisch, wiederholbar und automatisierbar sind.

Architektur: Erfassen, speichern, validieren

Das Muster besteht aus vier Komponenten:

  1. Ein Backend-Endpunkt empfängt eingehende Stripe-Webhooks.
  2. Eine Tabelle wie stripe_event_logs protokolliert die Ereignisdaten.
  3. Ein Apidog-Post-Request Processor führt eine SQL-Abfrage aus.
  4. Assertions prüfen, ob das erwartete Ereignis und der erwartete Anwendungszustand vorhanden sind.

Die Verantwortung ist klar getrennt:

  • Ihre Anwendung prüft die Stripe-Signatur, speichert das Ereignis und verarbeitet die Bestellung.
  • Apidog liest die gespeicherten Daten zurück und entscheidet, ob der Test erfolgreich ist.

Schritt 1: Stripe-Webhooks im Backend erfassen

Erstellen Sie eine Route, an die Stripe per POST senden kann. Der folgende Express-Handler prüft die Signatur, speichert das Ereignis idempotent und markiert anschließend die Bestellung als bezahlt.

import express from "express";
import Stripe from "stripe";

const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;

app.post(
  "/webhooks/stripe",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    let event;

    try {
      event = stripe.webhooks.constructEvent(
        req.body,
        req.headers["stripe-signature"],
        endpointSecret
      );
    } catch (err) {
      return res.status(400).send(`Signature check failed: ${err.message}`);
    }

    // Ereignis persistent speichern, damit der Test es später validieren kann.
    await db.query(
      `INSERT INTO stripe_event_logs (event_id, type, payload, handled_at)
       VALUES ($1, $2, $3, now())
       ON CONFLICT (event_id) DO NOTHING`,
      [event.id, event.type, JSON.stringify(event.data.object)]
    );

    if (event.type === "payment_intent.succeeded") {
      const intent = event.data.object;
      await markOrderPaid(intent.metadata.order_id);
    }

    res.json({ received: true });
  }
);
Enter fullscreen mode Exit fullscreen mode

Achten Sie dabei auf zwei Punkte:

  • Signatur vor jeder Verarbeitung prüfen: Verwenden Sie stripe.webhooks.constructEvent() mit dem unveränderten Raw Body. Die Hintergründe erläutert der Artikel zur Webhook-Signaturverifizierung.
  • Idempotent speichern: Stripe kann dasselbe Ereignis mehrfach zustellen. ON CONFLICT (event_id) DO NOTHING verhindert doppelte Protokolleinträge.

Verwenden Sie in der Praxis einen eindeutigen Index oder Primary Key für event_id.

Schritt 2: Datenbank in der Apidog-Umgebung konfigurieren

Richten Sie in Apidog eine Datenbankverbindung für die Umgebung ein, die Ihre CI-Pipeline verwendet, beispielsweise Staging oder eine dedizierte Testdatenbank.

Wichtig ist die Zuordnung:

Testumgebung API-Endpunkt Datenbank
Staging Staging-Backend Staging-Datenbank
CI-Test Test-Backend Testdatenbank

Die API und die abgefragte Datenbank müssen zur selben Umgebung gehören. Wenn Ihr Test ein Ereignis in Staging auslöst, aber eine andere Datenbank abfragt, schlägt die Validierung fehl, obwohl der Webhook korrekt verarbeitet wurde.

Schritt 3: Ereignis mit dem Post-Request Processor abfragen

Der Post-Request Processor ist der zentrale Apidog-Schritt für dieses Muster. Er führt nach einer Testanfrage SQL aus und kann die zurückgegebenen Werte validieren.

Ein typischer Ablauf für payment_intent.succeeded:

  1. Das Testszenario löst eine Zahlung aus, etwa durch Erstellen und Bestätigen eines Payment Intents im Stripe-Testmodus.
  2. Stripe liefert das Ereignis an /webhooks/stripe.
  3. Der Handler prüft die Signatur und schreibt eine Zeile in stripe_event_logs.
  4. Der nächste Testschritt fragt diese Zeile mit einem Post-Request Processor ab.
  5. Assertions prüfen Ereignisdaten und fachlichen Zustand.

Eine einfache SQL-Abfrage lautet:

SELECT event_id, type, payload, handled_at
FROM stripe_event_logs
WHERE type = 'payment_intent.succeeded'
ORDER BY handled_at DESC
LIMIT 1;
Enter fullscreen mode Exit fullscreen mode

Prüfen Sie mindestens:

  • type ist payment_intent.succeeded
  • event_id entspricht dem Ereignis, das Ihr Test ausgelöst hat
  • payload enthält den erwarteten Betrag oder die erwartete Bestellreferenz
  • handled_at ist gesetzt

Noch besser: Verwenden Sie nicht nur den Ereignistyp als Filter. Übergeben Sie die erwartete event_id oder eine eindeutige order_id aus dem Testkontext, damit kein Protokolleintrag eines vorherigen Laufs validiert wird.

SELECT event_id, type, payload, handled_at
FROM stripe_event_logs
WHERE event_id = :expected_event_id
  AND type = 'payment_intent.succeeded'
LIMIT 1;
Enter fullscreen mode Exit fullscreen mode

Mit asynchroner Zustellung umgehen

Webhook-Zustellung ist asynchron. Wenn Ihr Test unmittelbar nach dem Auslösen der Zahlung abfragt, kann Stripe das Ereignis noch nicht zugestellt haben.

Verwenden Sie deshalb eine kurze Wartezeit oder eine Retry-Schleife:

max. 5 Versuche
Wartezeit: 2 Sekunden
Abbruch: Sobald die erwartete event_id gefunden wurde
Enter fullscreen mode Exit fullscreen mode

Die Reihenfolge lautet:

Zahlung auslösen
  → auf Stripe-Zustellung warten
  → stripe_event_logs abfragen
  → Assertions ausführen
Enter fullscreen mode Exit fullscreen mode

Ein kleines Wiederholungsfenster verhindert instabile Tests, ohne die Pipeline unnötig zu verlangsamen.

Lokale Entwicklung: Ereignisse in Echtzeit weiterleiten

Das Erfassungs-und-Abfrage-Muster eignet sich für CI. Während der lokalen Entwicklung benötigen Sie dagegen meist eine Echtzeit-Weiterleitung, weil Stripe localhost nicht direkt erreichen kann.

Die Stripe CLI kann Webhooks an Ihren lokalen Server weiterleiten:

stripe listen --forward-to localhost:3000/webhooks/stripe
Enter fullscreen mode Exit fullscreen mode

Damit erhalten Sie echte Stripe-Ereignisse auf Ihrem lokalen Port und können Handler, Signaturprüfung und Fehlerbehandlung direkt testen.

Ngrok erfüllt denselben Zweck, indem es Ihren lokalen Port über eine öffentliche URL erreichbar macht. Verwenden Sie Relay-Tools für den lokalen Entwicklungszyklus und das Datenbank-plus-Post-Request Processor-Muster für reproduzierbare CI-Validierungen.

Apidogs native Webhook-Funktion richtig einordnen

Apidog besitzt eine Funktion namens Webhook. Sie dient jedoch nicht dazu, eingehende Stripe-Ereignisse zu empfangen.

Die native Webhook-Funktion beschreibt und dokumentiert ausgehende Webhooks Ihres Systems: Ihre Anwendung ruft bei einem Ereignis eine externe URL auf. Das ist das Gegenteil des Stripe-Falls, bei dem Stripe Ihre Anwendung aufruft.

So dokumentieren Sie einen eigenen ausgehenden Webhook in Apidog:

  1. Klicken Sie in der linken Seitenleiste auf +.
  2. Wählen Sie New Other Protocol APIs.
  3. Wählen Sie Webhook.
  4. Konfigurieren Sie:
    • Request Method, typischerweise POST
    • Webhook Name
    • optionale Debug URL
    • Request Body, Header und weitere Einstellungen unter Other Info
  5. Klicken Sie auf Save.

Für einen Test tragen Sie eine URL in Debug URL ein und klicken auf Send. Beachten Sie: Die Debug URL dient nur zum Testen und erscheint nicht in veröffentlichter Dokumentation oder im OpenAPI-Export.

Mehr zum Entwurf solcher Callbacks beschreibt der Artikel über Webhooks im API-Design.

Härtung für produktionsnahe Tests

Sobald der Happy Path funktioniert, erweitern Sie die Tests gezielt.

1. Eindeutige Ereignisse statt „letztes Ereignis“ prüfen

Validieren Sie immer die konkrete event_id oder eine test-spezifische order_id. So vermeiden Sie, dass ein alter Datensatz einen neuen Test fälschlich erfolgreich macht.

Bereinigen Sie außerdem stripe_event_logs regelmäßig oder isolieren Sie Testläufe über eindeutige IDs.

2. Fehlerpfade testen

Ein Webhook-Test sollte nicht nur bestätigen, dass gültige Ereignisse verarbeitet werden. Prüfen Sie auch, dass ungültige Ereignisse nicht verarbeitet werden:

  • fehlerhafte Stripe-Signatur
  • unerwarteter Ereignistyp
  • fehlende Bestellreferenz
  • bereits verarbeitetes Ereignis

Erwarten Sie in diesen Fällen beispielsweise:

  • HTTP 400 bei ungültiger Signatur
  • keinen neuen handled_at-Zeitstempel
  • keine Änderung in orders
  • keinen doppelten Eintrag für dieselbe event_id

Die Best Practices für Zahlungs-Webhooks behandeln Idempotenz und Wiederholungsverhalten, die Ihre Tests abdecken sollten.

3. Fachlichen Seiteneffekt validieren

„Webhook ist angekommen“ reicht nicht aus. Testen Sie auch, ob die fachliche Verarbeitung erfolgt ist.

Wenn Ihr Handler eine orders-Tabelle aktualisiert, fügen Sie eine zweite Abfrage hinzu:

SELECT id, payment_status, paid_at
FROM orders
WHERE id = :expected_order_id;
Enter fullscreen mode Exit fullscreen mode

Die entscheidende Assertion lautet dann beispielsweise:

payment_status = 'paid'
paid_at IS NOT NULL
Enter fullscreen mode Exit fullscreen mode

Damit beweist Ihr Test die gesamte Kette:

Stripe-Ereignis
  → Webhook empfangen
  → Signatur geprüft
  → Ereignis gespeichert
  → Bestellung als bezahlt markiert
Enter fullscreen mode Exit fullscreen mode

4. Tests regelmäßig ausführen

Führen Sie das Szenario nicht nur als Merge-Gate aus. Sobald es in Apidog gespeichert ist, können Sie es regelmäßig planen und so Fehler zwischen Deployments erkennen. Der Leitfaden zum Planen von API-Tests in Apidog zeigt den Ablauf.

Workflow mit der Apidog CLI automatisieren

Der Nutzen entsteht, wenn das Szenario unbeaufsichtigt in CI läuft. Installieren Sie zunächst die Apidog CLI und authentifizieren Sie sich:

npm install -g apidog-cli
apidog login --with-token <YOUR_ACCESS_TOKEN>
Enter fullscreen mode Exit fullscreen mode

Führen Sie anschließend das gespeicherte Webhook-Validierungsszenario gegen die gewünschte Umgebung aus:

apidog run --access-token $APIDOG_ACCESS_TOKEN -t <SCENARIO_ID> -e <ENV_ID> -r cli
Enter fullscreen mode Exit fullscreen mode

Die Parameter bedeuten:

  • -t: ID des Testszenarios
  • -e: ID der Umgebung
  • -r: Reporter

Für Konsolenausgabe und einen HTML-Bericht in Ihren CI-Artefakten:

apidog run \
  --access-token $APIDOG_ACCESS_TOKEN \
  -t <SCENARIO_ID> \
  -e <ENV_ID> \
  -r html,cli
Enter fullscreen mode Exit fullscreen mode

Das Szenario enthält den Post-Request Processor und die SQL-Abfragen. Bei einer fehlgeschlagenen Validierung liefert der Befehl einen Exit-Code ungleich null, sodass Ihre Pipeline den Merge blockieren kann.

Weitere Details finden Sie im Apidog CLI Installationsleitfaden und im CI/CD-Pipeline-Walkthrough.

Häufig gestellte Fragen

Kann Apidog einen Stripe-Webhook direkt empfangen?

Nein. Apidog unterstützt kein natives Abhören eingehender Webhooks. Empfangen und speichern Sie das Ereignis in Ihrem Backend; Apidog liest es anschließend über einen Post-Request Processor aus der Datenbank.

Wo finden die Assertions statt?

Im Post-Request Processor einer Anfrage in Ihrem Testszenario. Dieser fragt die über die Umgebung konfigurierte Datenbankverbindung ab und validiert die zurückgegebenen Werte.

Wie vermeide ich Race Conditions bei der Zustellung?

Fügen Sie vor der Datenbankabfrage eine kurze Wartezeit oder Retry-Logik ein. Fragen Sie außerdem nach einer eindeutigen event_id oder order_id ab, nicht nur nach dem neuesten Ereignis eines Typs.

Benötige ich einen kostenpflichtigen Plan?

Die Dokumentation für diesen Workflow nennt keine konkreten Plan-Einschränkungen. Prüfen Sie die aktuellen Details auf der Preisseite oder laden Sie Apidog herunter, um Datenbankverbindung und Post-Request Processor in einem Testprojekt zu prüfen.

Ist die native Webhook-Funktion von Apidog dafür nützlich?

Nicht für eingehende Stripe-Ereignisse. Sie ist ein Dokumentations- und Designtool für ausgehende Webhooks Ihrer eigenen Anwendung.

Zusammenfassung

Sie können Stripe nicht auf Apidog richten und Ereignisse dort live abfangen. Der unterstützte und CI-taugliche Ablauf ist:

  1. Stripe-Webhook im eigenen Endpunkt empfangen.
  2. Signatur mit constructEvent() prüfen.
  3. Ereignis idempotent in stripe_event_logs speichern.
  4. Bestellung oder andere fachliche Seiteneffekte verarbeiten.
  5. Ereignis und Anwendungszustand per Apidog-Post-Request Processor abfragen.
  6. Das Szenario mit apidog run in CI ausführen.

So prüft Ihre Pipeline bei jedem Merge nicht nur, ob ein Stripe-Ereignis zugestellt wurde, sondern ob eine echte Zahlung die zugehörige Bestellung tatsächlich auf paid setzt.

Top comments (0)