Integrationen

Webhooks an LeadJourney senden

Die vollständige Anleitung, um Events per Webhook an LeadJourney zu senden – der Endpoint, beide Wege der Authentifizierung, alle Felder, die du mitsenden kannst (Identifier, Umsatz, Namen, Custom Fields), wie wiederholte Aufrufe behandelt werden und wie du einen Webhook testest und debuggst, der nicht ankommt.

Ein Webhook ist der Weg, auf dem dein eigenes System LeadJourney mitteilt, dass etwas passiert ist: Ein Lead ist eingegangen, ein Termin wurde gebucht, ein Deal ist gewonnen. Du sendest einen POST-Request mit einem kleinen JSON-Body, und LeadJourney ordnet dieses Event dem Ad-Klick zu, aus dem der Lead entstanden ist.

Das ist der richtige Weg, wenn der Meilenstein in deiner eigenen Software liegt – einem eigenen CRM, deinem eigenen Buchungsformular, einem selbst gebauten Backend – und es keinen nativen Connector gibt, der ihn für dich beobachtet.

Kurz gesagt

  1. Kopiere Webhook-URL und Postback-Secret aus Settings → Events → Conversion API.
  2. Sende einen POST mit Content-Type: application/json, dem Header Authorization: Bearer <dein Secret> und einem Body mit dem Event-Typ und mindestens einem Identifier (click_id, email oder phone).
  3. Prüfe das Ergebnis im Events Manager und im API-Postbacks-Log.

Wann du einen Webhook brauchst

  • Es gibt einen nativen Connector für das Tool (HubSpot, Pipedrive, Stripe, Calendly und weitere). Dann brauchst du nichts davon – verbinden und Events mappen genügt. Siehe Apps.
  • Der Meilenstein liegt in deinem eigenen System. Dein CRM, dein Buchungssystem, dein Backend: Dann sendest du das Event selbst per Webhook. Darum geht es hier.

Bevor du startest

Drei Dinge müssen stehen:

  1. Das Tracking läuft. Events werden dem Besucher zugeordnet, der auf deine Anzeige geklickt hat – die Klicks müssen also zuerst erfasst werden. Siehe Tracking-Script installieren.
  2. Das Event existiert. Der type, den du sendest, muss zu einem Event in deinem Events Manager passen. Jeder Workspace startet mit Lead und WonClient.
  3. Du hast deine Zugangsdaten. Öffne Settings → Events → Conversion API:
ZugangsdatumWas es ist
Webhook-URLDer Endpoint, an den du sendest. Sie sieht aus wie https://api.leadjourney.io/api/v1/postback/DEINE-WORKSPACE-ID und enthält deine Workspace-ID bereits.
Postback-SecretDein Authentifizierungs-Secret, beginnt mit pb_…. Behandle es wie ein Passwort; du kannst es hier neu erzeugen, falls es je nach außen gelangt.

Das Secret gehört auf deinen Server

Wer das Postback-Secret hat, kann Conversions in deinen Workspace schreiben. Halte es in einer serverseitigen Umgebungsvariable – niemals in Browser-Code, einer Mobile-App oder einem öffentlichen Repository. Soll eine Seite im Browser ein Event auslösen, ruft sie deine eigene Backend-Route auf, und dein Backend setzt den Header und leitet weiter.

Aufbau eines Requests

Jedes Event ist ein POST mit JSON-Body:

curl -X POST "https://api.leadjourney.io/api/v1/postback/DEINE-WORKSPACE-ID" \
  -H "Authorization: Bearer DEIN_POSTBACK_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "Lead",
    "click_id": "8f3c2a1e-4b7d-4c1a-9e2f-6d5b3a7c9e10",
    "email": "[email protected]"
  }'

Das ist der ganze Vertrag: URL + Authorization-Header + JSON-Body. Alles Weitere unten ist Detail rund um diese drei Teile.

Keine eigenen Header möglich? Token in der URL

Manche Tools können keine eigenen Header senden. Dann hängst du das Secret stattdessen als token-Query-Parameter an – …/postback/DEINE-WORKSPACE-ID?token=DEIN_POSTBACK_SECRET – und lässt den Body unverändert. Nutze das nur, wenn der Header wirklich nicht geht: Tokens in URLs landen leichter in Proxy- und Server-Logs.

Was du mitsenden kannst

FeldTypPflichtWas es bewirkt
typeStringPflichtDer Event-Name, exakt wie im Events Manager (z. B. Lead, WonClient).
click_idString (UUID)BedingtDie Click-ID des Leads – der stärkste Match. Pflicht, wenn email und phone fehlen.
emailStringBedingtDie E-Mail-Adresse des Leads. Pflicht, wenn click_id und phone fehlen.
phoneStringBedingtDie Telefonnummer des Leads. Pflicht, wenn click_id und email fehlen.
revenueZahlOptionalDer Wert der Conversion. Pflicht bei WonClient.
cash_collectedZahlOptionalWas tatsächlich eingegangen ist, falls du das getrennt vom gebuchten Umsatz führst.
first_nameStringOptionalDer Vorname des Leads.
last_nameStringOptionalDer Nachname des Leads.
custom_fieldsObjektOptionalDeine eigenen Felder als Key-Value-Paare. Müssen vorher angelegt sein.

Bleib bei diesen Feldern – sie sind das, was die Conversion API definiert.

Der Event-Typ

type muss zeichengenau zum Event-Namen im Events Manager passen, Groß- und Kleinschreibung eingeschlossen. Ein Tippfehler legt kein neues Event an – der Aufruf landet einfach nicht dort, wo du ihn erwartest.

Mindestens ein Identifier

Ein Event ohne Identifier kann nicht zugeordnet werden. Sende, was du hast – am besten alle drei:

  • click_id – der stärkste Match, weil sie auf genau einen Ad-Klick zeigt. Dein System hat sie nur, wenn du sie beim Anlegen des Leads erfasst hast. Siehe Click-ID auslesen & speichern.
  • email – das Sicherheitsnetz. Sie matcht auch Leads, deren Click-ID verloren ging, etwa weil die Person das Gerät gewechselt hat.
  • phone – wertvoll bei telefonlastigen Funnels. Sende sie im internationalen Format (+49170…), damit dieselbe Person systemübergreifend erkannt wird.

Halte nie ein Event zurück, nur weil die Click-ID fehlt

Ein Lead, der organisch, telefonisch oder auf einem anderen Gerät kam, hat womöglich keine Click-ID. Sende das Event trotzdem mit email und phone – es wird erfasst und kann weiterhin zugeordnet werden. Siehe Wie Events einem Lead zugeordnet werden.

Umsatz

Sende revenue als Zahl, nicht als String, mit Punkt als Dezimaltrennzeichen: 1499.00, nicht "1.499,00 €". Deine Workspace-Währung bestimmt, wie diese Zahl in den Reports dargestellt wird.

  • revenue ist Pflicht bei WonClient – ohne den Wert zählt der Deal zwar, trägt aber keinen Umsatz zu deinem ROAS bei.
  • cash_collected ist für Geschäftsmodelle, die einen Vertragswert vorab buchen, aber in Raten einnehmen. Sind beide gleich, kannst du es weglassen.
  • Bei einer Rückerstattung sendest du ein negatives revenue, um die Summe zu korrigieren.

Namen

first_name und last_name beeinflussen das Matching nicht – sie reichern den Lead-Datensatz an, damit du in den Reports erkennst, wer hinter einer Conversion steckt.

Custom Fields

Alles, was für dein Geschäft spezifisch ist – Branche, Tarif, Deal-Größe, Lead-Score – kommt in custom_fields. Lege jedes Feld einmal unter Settings → Events → Custom Fields an und sende dann seinen exakten Webhook-Key:

{
  "type": "WonClient",
  "email": "[email protected]",
  "revenue": 1499.00,
  "custom_fields": {
    "industry": "Software",
    "company_size": 100,
    "deal_size": 1499.00
  }
}

Das Feld muss vor dem ersten Senden existieren, und sein Typ muss zum Wert passen – ein String für Textfelder, eine Zahl für Zahlen- und Währungsfelder. Custom Fields werden danach zu Group By- und Filter-Dimensionen in deinen Reports. Siehe Custom Fields.

Beispiel-Payloads

Derselbe Endpoint nimmt jedes Event entgegen – nur der Body ändert sich.

{
  "type": "Lead",
  "click_id": "8f3c2a1e-4b7d-4c1a-9e2f-6d5b3a7c9e10",
  "email": "[email protected]",
  "phone": "+491701234567",
  "first_name": "Anna",
  "last_name": "Schmidt"
}
{
  "type": "BookedCall",
  "click_id": "8f3c2a1e-4b7d-4c1a-9e2f-6d5b3a7c9e10",
  "email": "[email protected]"
}

Die Click-ID ist die, die du beim Anlegen des Leads am Kontakt gespeichert hast – genau das hält jeden späteren Meilenstein am selben Klick.

{
  "type": "WonClient",
  "click_id": "8f3c2a1e-4b7d-4c1a-9e2f-6d5b3a7c9e10",
  "email": "[email protected]",
  "revenue": 1499.00,
  "cash_collected": 499.00,
  "custom_fields": {
    "plan": "Pro"
  }
}
{
  "type": "Refund",
  "email": "[email protected]",
  "revenue": -1499.00
}

Ein negatives revenue korrigiert die Summe. Lege das Event Refund vorher im Events Manager an.

Aus deinem Code senden

Häng dich dort ein, wo der Zustand tatsächlich wechselt – im Formular-Handler, in der Methode, die einen Deal abschließt, im Webhook-Handler deines Zahlungsanbieters – und sende einen POST pro Meilenstein:

await fetch(`https://api.leadjourney.io/api/v1/postback/${process.env.LJ_WORKSPACE_ID}`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LJ_POSTBACK_SECRET}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    type: "WonClient",
    click_id: deal.contact.ljClickId, // die am Kontakt gespeicherte Click-ID
    email: deal.contact.email,
    revenue: deal.amount,
  }),
  signal: AbortSignal.timeout(10_000),
});
$ch = curl_init("https://api.leadjourney.io/api/v1/postback/" . getenv("LJ_WORKSPACE_ID"));
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 10,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("LJ_POSTBACK_SECRET"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "type"     => "WonClient",
        "click_id" => $deal->contact->lj_click_id,
        "email"    => $deal->contact->email,
        "revenue"  => $deal->amount,
    ]),
]);
curl_exec($ch);
curl_close($ch);
import os, requests

requests.post(
    f"https://api.leadjourney.io/api/v1/postback/{os.environ['LJ_WORKSPACE_ID']}",
    headers={
        "Authorization": f"Bearer {os.environ['LJ_POSTBACK_SECRET']}",
        "Content-Type": "application/json",
    },
    json={
        "type": "WonClient",
        "click_id": deal.contact.lj_click_id,
        "email": deal.contact.email,
        "revenue": deal.amount,
    },
    timeout=10,
)
curl -X POST "https://api.leadjourney.io/api/v1/postback/$LJ_WORKSPACE_ID" \
  -H "Authorization: Bearer $LJ_POSTBACK_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "WonClient",
    "click_id": "'"$CLICK_ID"'",
    "email": "[email protected]",
    "revenue": 1499.00
  }'

Wo du den Aufruf einhängst

MeilensteinWo du dich einhängst
Lead entstehtIm Handler deines Formulars oder deiner Buchungsroute, direkt nachdem der Datensatz gespeichert ist
Stufe wechselt (qualifiziert, gebucht, erschienen)In der Methode oder dem Datenbank-Trigger, der die Stufe ändert
Deal gewonnen, Zahlung eingegangenIm Webhook-Handler deines Zahlungsanbieters oder in der Methode, die den Deal auf gewonnen setzt
RückerstattungDort, wo die Erstattung gebucht wird

Speichere die Click-ID am Kontakt, sobald der Lead entsteht. Jedes spätere Event liest sie dann aus deiner eigenen Datenbank zurück – das hält den kompletten Funnel an einem Klick, auch Wochen später.

Zuverlässigkeit

  • Blockiere den Nutzer nicht. Sende den Webhook aus einem Background-Job oder einer Queue, mit einem Timeout von wenigen Sekunden. Ein langsamer Aufruf darf nie eine Registrierung oder einen Checkout verzögern.
  • Wiederhole bei Fehlern. Behandle jede Antwort außerhalb von 2xx als Fehlschlag und versuche es mit kurzem Backoff erneut.
  • Baue keine eigene Dedup-Logik. Nutze die Event-Modi unten – dann bläht ein wiederholter Aufruf deine Zahlen nicht auf.

Wiederholte Aufrufe: Duplikate und Updates

Wie ein zweiter Webhook für denselben Lead behandelt wird, entscheidest du pro Event im Events Manager, nicht in deinem Code:

ModusWas passiert
Create new conversionJeder Webhook wird als neues Event erfasst – etwa für Wiederkäufe.
Ignore duplicate postbacksNur das erste Event pro Lead wird behalten. Ideal für Lead, damit ein doppelter Submit nicht doppelt zählt.
Edit conversion with new dataDas bestehende Event wird aktualisiert – für einen Umsatzwert, der später korrigiert wird.
Keep original data, increment payoutDas ursprüngliche Event bleibt, der neue Umsatz kommt obendrauf (nur WonClient).

Den Modus legst du beim Anlegen des Events fest – siehe Events & Events Manager.

Testen und debuggen

Einen Klick zum Matchen erzeugen

Öffne deine Seite über einen getrackten Link – eine Test-Anzeigen-URL oder einen Link aus dem UTM Builder –, damit es einen Klick gibt, an den sich das Event hängen kann.

Ein Test-Event senden

Sende einen Webhook (das cURL-Beispiel oben genügt). Unter Settings → Events steigt der Total-Zähler des Events, Last Received aktualisiert sich, und der Status wechselt von Created auf Active.

Den rohen Aufruf ansehen

Öffne das API-Postbacks-Log. Es zeigt Statuscode, den gesendeten Payload und ob der Aufruf über Klick, E-Mail oder Telefon gematcht hat. Hier debuggst du einen Webhook, der nicht ankommt.

Wenn etwas nicht ankommt

SymptomÜbliche Ursache
Event bleibt auf Created / Never receivedEs erreicht LeadJourney gar nichts: falsche URL, fehlende Workspace-ID, oder der Aufruf feuert nie
Antwort meldet fehlende BerechtigungFalsches oder neu erzeugtes Postback-Secret, oder der Header fehlt – prüfe Authorization: Bearer pb_…
Aufruf kommt an, aber in den Reports taucht nichts aufDer type passt nicht exakt zum Event-Namen, oder es wurde kein Identifier gesendet
Conversion erfasst, aber nicht zugeordnetKeine click_id, und E-Mail/Telefon passen zu keinem getrackten Besucher – siehe Fehlende Leads
Zahlen zu hochDer Modus des Events ist Create new conversion, während dein System Retries sendet – wechsle auf Ignore duplicate postbacks

FAQ

Verwandte Artikel