Zum Inhalt springen
Dokumentation

Leads und Übergaben per Webhook an deine Tools senden

Sende neue Leads, Übergaben und Live-Chat-Anfragen, Formulareinsendungen, gebuchte Termine und Rücksendeanfragen aus intoCHAT als signiertes JSON an deinen Server, Zapier, Make oder n8n: Events, Inhalte, Signaturen und Wiederholungen.

Ein Webhook schickt ein Ereignis deines Agenten innerhalb von Sekunden an eine Adresse deiner Wahl, als signierte JSON-Anfrage per POST. So landen neue Leads in deinem CRM, oder eine Automatisierung startet. Das funktioniert mit deinem eigenen Server und mit Automatisierungstools, die eingehende Webhooks annehmen, etwa Zapier, Make oder n8n: Du nutzt den Auslöser des Tools für eingehende Webhooks. Die eigenen intoCHAT-Apps für Zapier und Make sind fertig und werden verfügbar, sobald sie in den Verzeichnissen dieser Tools veröffentlicht sind; siehe Zapier und Make. Willst du diese Ereignisse als Nachrichten in einem Slack-Channel, brauchst du keinen Webhook: Nutze die Slack-Benachrichtigungen.

Events

EventName im DashboardWird gesendet, wenn
lead.createdNew leadein neuer Kontakt gespeichert wird, aus dem Lead-Formular oder aus Kontaktdaten, die der Besucher in den Chat geschrieben hat.
handoff.requestedHand-off requestedder Agent ein Gespräch per E-Mail an dein Team geschickt hat. Siehe Übergabe per E-Mail.
form.submittedForm submittedein Besucher eines deiner Chat-Formulare abgeschickt hat.
booking.createdMeeting bookedein Besucher im Chat einen Termin gebucht hat. Siehe Terminbuchung mit Cal.com oder Calendly.
live_chat.requestedLive chat requestedder Agent dein Team gebeten hat, in den Chat zu kommen, weil ein Besucher nach einer Person gefragt hat, während jemand aus deinem Team online war. Siehe Live-Chat.
return.requestedReturn requestedein Besucher darum gebeten hat, Artikel einer Bestellung zurückzusenden oder umzutauschen, die der Agent verifiziert hat. Siehe Bestellstatus und Rücksendungen.

lead.created kommt einmal pro Kontakt. Sendet ein wiederkehrender Besucher dieselben Daten noch einmal, gibt es kein neues Event, ebenso wenig, wenn ein Chat einem dort schon gespeicherten Kontakt eine Telefonnummer hinzufügt.

handoff.requested kommt nur, wenn die E-Mail an dein Team tatsächlich verschickt wurde. Übergaben aus dem Playground lösen es ebenfalls aus, gekennzeichnet mit "test": true. Hast du Helpdesk-Tickets verbunden, kommt es, sobald das Ticket erstellt wurde oder das Erstellen fehlgeschlagen ist, meist ein paar Sekunden später, und enthält das Ticket, wenn es eines gibt.

form.submitted kommt einmal pro Einsendung. Ein Formular lässt sich pro Gespräch nur einmal abschicken, und eine Einsendung löst nie lead.created aus, auch wenn das Formular nach einer E-Mail-Adresse fragt.

booking.created kommt einmal pro Buchung, nachdem Cal.com oder Calendly sie angenommen und intoCHAT sie gespeichert hat. Eine Buchung löst nie lead.created aus. Buchungen aus dem Playground sind echte Buchungen und lösen es ebenfalls aus, ohne Test-Kennzeichen. Spätere Änderungen in Cal.com oder Calendly, etwa eine Absage, lösen kein Event aus.

live_chat.requested kommt einmal pro Anfrage, wenn der Agent dein Team bittet dazuzukommen, egal ob jemand dazukommt oder nicht. Fragt ein Besucher erneut, nachdem die Anfrage verfallen oder der Live-Chat beendet ist, kommt ein neues Event. Der Playground fordert nie einen Live-Chat an und löst dieses Event daher nie aus.

return.requested kommt einmal pro Rücksendeanfrage, sobald intoCHAT sie gespeichert hat. Jedes Gespräch kann eine Anfrage pro Bestellung senden, eine erneute Anfrage für dieselbe Bestellung löst also nichts aus. Anfragen aus dem Playground lösen es ebenfalls aus, ohne Test-Kennzeichen.

Webhook hinzufügen

  1. Öffne deinen Agenten und wechsle zum Tab Leads. Webhooks steht weiter unten im Tab, über Slack alerts.
  2. Klicke auf Add webhook.
  3. Füge unter Endpoint URL die Adresse ein, die dein Server oder dein Tool für eingehende Webhooks nennt.
  4. Lass unter Events to send die Events angehakt, die du willst: New lead, Hand-off requested, Form submitted, Meeting booked, Live chat requested und Return requested. Bei einem neuen Webhook sind alle sechs angehakt. Ein früher angelegter Webhook behält seine Events. Klicke dort auf Edit und hake Form submitted, Meeting booked, Live chat requested oder Return requested an, wenn er diese bekommen soll.
  5. Lass Active eingeschaltet und klicke auf Add webhook.
  6. Kopiere das angezeigte Signing Secret, leg es dort ab, wo dein Empfänger es lesen kann, und klicke auf I've saved it.
  7. Klicke auf Send test event, um die Verbindung zu prüfen. Das Ergebnis steht unter den Buttons.

Die Adresse muss mit https:// beginnen und auf einen öffentlichen Server zeigen. Private und interne Netzwerkadressen wie localhost oder 192.168.1.10 werden beim Speichern abgelehnt und vor jeder Zustellung erneut geprüft. Jeder Agent kann bis zu 5 Webhooks haben.

Webhooks, die Zapier, Make oder dein eigener Code über die REST-API abonniert haben, zählen nicht zu den 5; siehe Von Integrationen erstellte Webhooks. Ebenso wenig die Webhooks einzelner Formulare; siehe Ein Webhook für ein einzelnes Formular.

Um einen Webhook zu pausieren, ohne seine Einstellungen zu verlieren, schalte ihn aus. Er zeigt dann Paused. Events, die während der Pause passieren, werden nicht gesendet, auch nicht später. Eine Zustellung, die gerade auf eine Wiederholung wartet, schlägt beim nächsten Versuch fehl; ist der Webhook wieder aktiv, kannst du sie erneut senden. Mit Edit änderst du Adresse und Events. Remove löscht den Webhook samt Zustellverlauf.

Von Integrationen erstellte Webhooks

Eine Integration kann über die REST-API mit einem deiner API-Schlüssel einen Webhook für deinen Agenten abonnieren. Die Apps für Zapier und Make tun das, wenn du einen Zap einschaltest oder einem Szenario einen sofortigen Trigger hinzufügst.

Diese Webhooks stehen mit den anderen in der Karte Webhooks, mit einem Kennzeichen, das sagt, woher sie kommen: via Zapier, via Make oder via API. Sie werden zugestellt, signiert, wiederholt und protokolliert wie die Webhooks, die du selbst hinzufügst, und du kannst Send test event, Recent deliveries, den Schalter Active und New secret bei ihnen nutzen.

  • Sie haben keinen Button Edit: Adresse und Events gehören dem Zap, dem Szenario oder dem Code, der sie angelegt hat, und eine Änderung hier würde ihn kaputt machen.
  • Remove löscht einen davon. Der Zap oder das Szenario bleibt eingeschaltet, bekommt aber keine Events mehr; schalte ihn auch dort aus, oder schalte ihn aus und wieder ein, um einen neuen Webhook zu abonnieren.
  • Die Integration entfernt ihren Webhook selbst, wenn du den Zap ausschaltest oder den Trigger löschst.
  • Widerrufst du den API-Schlüssel, der sie erstellt hat, werden sie gelöscht. Siehe Schlüssel widerrufen.
  • Ein Agent kann bis zu 25 davon haben, zusätzlich zu den 5, die du selbst hinzufügst.

Ein Webhook für ein einzelnes Formular

Ein Chat-Formular kann einen eigenen Webhook haben, der nur die Events form.submitted dieses Formulars bekommt. Du fügst ihn im Editor des Formulars im Tab Actions unter Webhook for this form hinzu und verwaltest ihn dort, nicht in der Karte Webhooks.

  • Er hat ein eigenes Signing Secret, das nur einmal angezeigt wird, und wird genau wie die Webhooks hier zugestellt, signiert, wiederholt und protokolliert, mit demselben Rahmen und denselben Daten von form.submitted.
  • Er sendet nur form.submitted, nur für sein Formular. Seine Events lassen sich nicht ändern, und ein Test-Event funktioniert wie unten beschrieben.
  • Er zählt nicht zu den 5 Webhooks des Agenten und steht nicht in der Karte Webhooks.
  • Die Webhooks des Agenten, die Form submitted empfangen, bekommen weiterhin die Einsendungen aller Formulare, auch die eines Formulars mit eigenem Webhook. Jeder Webhook bekommt eine eigene Zustellung mit eigener ID.
  • Wird das Formular gelöscht, werden sein Webhook und dessen Zustellverlauf gelöscht.

Das Signing Secret

Jeder Webhook hat ein eigenes Signing Secret, das mit whsec_ beginnt. Vollständig siehst du es nur einmal, direkt nach dem Hinzufügen oder nach dem Erstellen eines neuen Secrets. Danach zeigt die Karte nur noch die letzten vier Zeichen.

Hast du das Secret verloren oder glaubst du, dass jemand anderes es kennt, klicke auf New secret. Das alte Secret funktioniert sofort nicht mehr, gib das neue also gleich an deinen Empfänger weiter.

Was gesendet wird

Jede Zustellung ist eine POST-Anfrage mit JSON-Inhalt und diesen Headern:

HeaderWert
Content-Typeapplication/json
User-AgentintoCHAT-Webhooks/1.0
X-IntoChat-EventDer Name des Events, etwa lead.created
X-IntoChat-DeliveryDie ID der Zustellung. Sie bleibt bei jeder Wiederholung gleich.
X-IntoChat-TimestampWann dieser Versuch gesendet wurde, in Unix-Sekunden
X-IntoChat-Signaturesha256=, gefolgt von der Signatur, siehe unten

Der Inhalt hat immer denselben Rahmen. id ist die ID der Zustellung, derselbe Wert wie X-IntoChat-Delivery:

{
  "id": "DELIVERY_ID",
  "event": "lead.created",
  "created_at": "2026-10-07T09:30:00.000Z",
  "agent": { "id": "AGENT_ID", "name": "Acme Assistant" },
  "data": { }
}

Daten von lead.created

FeldInhalt
leadIdDie ID des Leads
agentId, agentNameDer Agent, der den Lead erfasst hat
emailDie E-Mail-Adresse oder null
phoneDie Telefonnummer oder null
nameDer Name aus dem Lead-Formular oder null. Aus einer Chat-Nachricht wird nie ein Name übernommen.
customFieldsDie Antworten auf deine eigenen Felder als Liste von { "id", "label", "value" }. Leer, wenn es keine gibt.
sourceform oder chat
conversationIdDas Gespräch, aus dem der Lead stammt, oder null
collectedAtWann der Lead gespeichert wurde, als ISO-8601-Zeit in UTC
identityNur bei einem Besucher, der mit der Identitätsprüfung verifiziert wurde: { "userId", "name", "email" }. Fehlt sonst.

Daten von handoff.requested

FeldInhalt
conversationIdDas übergebene Gespräch
visitorEmailDie Adresse, die der Besucher für die Antwort genannt hat
summaryWas der Besucher braucht, in den Worten des Agenten
pageDie Seite, auf der der Chat begann, oder null
countryDer zweistellige Ländercode des Besuchers oder null
requestedAtWann die Übergabe verschickt wurde, als ISO-8601-Zeit in UTC
testtrue bei einer Übergabe aus dem Playground, sonst false
ticketNur wenn Helpdesk-Tickets für diese Übergabe ein Ticket geöffnet haben: { "provider", "id", "url" }, wobei provider zendesk, freshdesk oder hubspot ist, id die Nummer des Tickets als String und url das Ticket in deinem Helpdesk öffnet. Fehlt sonst.

Daten von form.submitted

FeldInhalt
submissionIdDie ID der Einsendung
formId, formNameDas abgeschickte Formular
agentId, agentNameDer Agent, der das Formular gezeigt hat
answersDie Antworten des Besuchers als Liste von { "id", "label", "value" }, in der Reihenfolge des Formulars. Leer gelassene optionale Felder fehlen.
conversationIdDas Gespräch, in dem das Formular abgeschickt wurde
submittedAtWann die Einsendung gespeichert wurde, als ISO-8601-Zeit in UTC
identityNur bei einem Besucher, der mit der Identitätsprüfung verifiziert wurde: { "userId", "name", "email" }. Fehlt sonst.

Daten von booking.created

FeldInhalt
bookingIdDie ID der Buchung in intoCHAT
providerDer Kalender: calcom oder calendly
providerBookingIdDie ID der Buchung in Cal.com oder die URI des Eingeladenen in Calendly, zum Beispiel https://api.calendly.com/scheduled_events/…/invitees/…
agentId, agentNameDer Agent, bei dem der Termin gebucht wurde
eventTypeId, eventTypeUri, eventTitleDer gebuchte Ereignistyp: eventTypeId ist die Nummer aus Cal.com, eventTypeUri die URI aus Calendly. Das jeweils andere Feld ist null.
startAt, endAtBeginn und Ende des Termins, als ISO-8601-Zeiten in UTC
timeZoneDie Zeitzone des Besuchers, etwa Europe/Berlin, oder UTC, wenn sein Browser keine angegeben hat
attendeeName, attendeeEmailName und E-Mail-Adresse, die der Besucher eingegeben hat
providerStatusaccepted oder pending, wenn du die Buchung erst in Cal.com bestätigen musst. Calendly-Buchungen sind immer accepted.
conversationIdDas Gespräch, in dem der Termin gebucht wurde
createdAtWann die Buchung gespeichert wurde, als ISO-8601-Zeit in UTC
identityNur bei einem Besucher, der mit der Identitätsprüfung verifiziert wurde: { "userId", "name", "email" }. Fehlt sonst.

Daten von live_chat.requested

FeldInhalt
conversationIdDas Gespräch, in dem der Besucher nach einer Person gefragt hat
visitorMessageDie letzte Nachricht des Besuchers, gekürzt auf 500 Zeichen mit … am Ende, wenn sie länger ist
pageDie Seite, auf der der Chat begann, oder null
countryDer zweistellige Ländercode des Besuchers oder null
requestedAtWann der Agent dein Team gebeten hat dazuzukommen, als ISO-8601-Zeit in UTC

Das Event sagt nicht, ob jemand dazugekommen ist. Wer den Chat wann übernommen hat, siehst du im Live-Chat-Posteingang und im Verlauf.

Daten von return.requested

FeldInhalt
returnRequestIdDie ID der Anfrage in intoCHAT
providerDer Shop: shopify oder woocommerce
orderName, orderIdDie Bestellung, wie dein Shop sie anzeigt, zum Beispiel #1042, und ihre ID im Shop
emailDie E-Mail-Adresse der Bestellung. Der Besucher hat bewiesen, dass er sie kennt, oder die Identitätsprüfung deiner Website hat sie übergeben.
kindreturn oder exchange
itemsDie Artikel, jeweils als { "title", "quantity" }. Der Titel enthält die Variante, wenn das Produkt in mehreren bestellt wurde, zum Beispiel Wool scarf - Blue.
reasonDer Grund, in den Worten des Besuchers
statusrequested
agentId, agentNameDer Agent, bei dem die Anfrage gestellt wurde
conversationIdDas Gespräch, in dem die Anfrage gestellt wurde
createdAtWann die Anfrage gespeichert wurde, als ISO-8601-Zeit in UTC

In deinem Shop wurde nichts genehmigt oder geändert. Wickle die Rücksendung dort ab und markiere sie dann in der Liste Returns im Tab Leads als erledigt.

Die Feldnamen aller Events nutzen camelCase.

Test-Event

Send test event sendet eine Anfrage mit "event": "test" und diesen Daten: { "message": "This is a test event from intoCHAT. Your webhook is set up correctly." }. Sie geht raus, egal welche Events der Webhook abonniert hat, auch wenn er pausiert ist, und wird nur einmal versucht. Weil ihre Daten anders aussehen als echte Events, braucht ein Tool, das Felder anhand eines Beispiels zuordnet, dafür ein echtes Event, etwa einen Lead, den du selbst auf deiner Website absendest.

Signatur prüfen

Prüfe jede Anfrage, bevor du ihr vertraust. X-IntoChat-Signature ist sha256=, gefolgt vom hexadezimalen HMAC-SHA256 aus Zeitstempel, Punkt und unverändertem Inhalt, also ${timestamp}.${rawBody}, mit dem Signing Secret des Webhooks als Schlüssel. Der Zeitstempel ist der Wert von X-IntoChat-Timestamp.

  • Berechne die Signatur über den Inhalt genau so, wie er ankommt, bevor du das JSON auswertest.
  • Vergleiche in konstanter Zeit.
  • Lehne alte Zeitstempel ab, damit eine abgefangene Anfrage nicht erneut abgespielt werden kann. Das Beispiel unten erlaubt 5 Minuten.

Dieses Node.js-Beispiel ist dasselbe wie unter Verify signatures in der Karte Webhooks, dort mit einem Copy-Button:

const crypto = require("crypto")

// rawBody: the request body exactly as received, before JSON parsing.
function verifyIntoChatWebhook(rawBody, headers, secret) {
  const timestamp = headers["x-intochat-timestamp"]
  const signature = headers["x-intochat-signature"] || ""

  // Reject anything older than 5 minutes, so a captured request can't be replayed.
  const age = Math.abs(Date.now() / 1000 - Number(timestamp))
  if (!timestamp || !(age <= 300)) return false

  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(timestamp + "." + rawBody)
    .digest("hex")

  const a = Buffer.from(signature)
  const b = Buffer.from(expected)
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

Kann dein Tool keine Signaturen prüfen, behandle die Webhook-Adresse wie ein Passwort: Wer sie kennt, kann Anfragen an sie senden.

Antworten und Duplikate erkennen

  • Antworte innerhalb von 10 Sekunden mit einem beliebigen 2xx-Status. Alles andere gilt als Fehlschlag: ein anderer Statuscode, keine Antwort in der Zeit oder ein Verbindungs- oder Zertifikatsfehler.
  • Weiterleitungen werden nicht verfolgt. Eine 3xx-Antwort gilt als Fehlschlag, trag also die endgültige Adresse ein.
  • Dasselbe Event kann mehr als einmal ankommen, etwa wenn dein Server es gespeichert, aber zu spät geantwortet hat. Nutze X-IntoChat-Delivery oder die id im Inhalt, um eine schon verarbeitete Zustellung zu ignorieren.
  • Jeder Webhook bekommt für dasselbe Event eine eigene Zustellung mit eigener ID.

Wiederholungen

  • Der erste Versuch startet direkt nach dem Event. Schlägt er fehl, folgen innerhalb weniger Sekunden bis zu zwei schnelle Wiederholungen.
  • Schlagen auch diese fehl, zeigt die Zustellung Retrying, und ein geplanter Job versucht es später erneut. Die Wiederholungen enden nach insgesamt 6 Versuchen oder 24 Stunden nach dem Event, je nachdem, was zuerst eintritt. Danach ist die Zustellung als Failed markiert.
  • Der geplante Job läuft derzeit einmal am Tag. In der Praxis bekommt eine Zustellung, die nach den schnellen Wiederholungen noch fehlschlägt, ein oder zwei weitere Versuche, innerhalb von etwa einem Tag nach dem Event.
  • Eine Zustellung an eine Adresse, die sich als privates Netzwerk herausstellt, schlägt sofort fehl, ohne Wiederholung.
  • Jede Wiederholung behält die ID der Zustellung und wird mit neuem Zeitstempel neu signiert.

Letzte Zustellungen

Klicke unter einem Webhook auf Recent deliveries, um seine letzten 20 Zustellungen zu sehen. Jede zeigt ihren Status (Sending, Retrying, Delivered oder Failed), das Event, die Uhrzeit, die Zahl der Versuche und den HTTP-Status. Eine Zustellung im Status Retrying zeigt, wann der nächste Versuch fällig ist, und eine nicht erfolgreiche zeigt den Fehler, etwa No response within 10 seconds.

Eine fehlgeschlagene Zustellung hat einen Button Resend, der sie sofort noch einmal versucht. Zustellungen werden nach 30 Tagen gelöscht.

Wie es weitergeht

Als Markdown anzeigen