• Customermates Logo
    CustomermatesDocumentation
  • Einführung
Erste Schritte
  • Quickstart
  • Kernkonzepte
KI verbinden
  • Custom Connector
  • CLI & Editoren
  • Ratenlimits
Integrationen
  • MCP
  • Webhooks
  • OpenAPI 3.1.0
  • N8N
Self-Hosting
  • Get Started
  • Architektur & Sicherheit
App-Leitfaden
  • Dashboard
  • Posteingang
  • Datensätze
  • Profil
  • Unternehmen
  • API-Keys
  • Filter-Syntax
  • Zurück
  1. Einführung
  2. Webhooks

Webhooks

CRM-Events abonnieren, Signaturen verifizieren, fehlgeschlagene Deliveries prüfen und den vollständigen Event-Katalog auf einer Seite lesen.

Customermates sendet einen JSON-POST an Ihren HTTPS-Endpunkt, sobald sich abonnierte Daten ändern. Sie wählen die Events und geben die URL an. Fehlgeschlagene Deliveries können Sie aus der UI oder per MCP erneut zustellen. Deliveries werden per HMAC-SHA256 über den rohen Request-Body signiert. Jedes Event und seine Payload-Struktur stehen im Katalog am Ende dieser Seite.

Einsatzzwecke

Webhooks lassen andere Systeme auf CRM-Änderungen reagieren, ohne zu pollen.

  • Neue Contacts in einen E-Mail-Sequencer übergeben.
  • Ein Ticket im Support-Tool öffnen, wenn ein Deal seinen Zustand ändert.
  • Einen Finance-Workflow auslösen, wenn ein Deal als abgeschlossen markiert wird.
  • Records nahezu in Echtzeit in ein Data Warehouse synchronisieren.

Webhook anlegen

UI: Unternehmen, dann Webhooks, dann Neu.

MCP: manage_webhooks mit action: "create", dazu url, events[] und optional description, secret, enabled.

{
  "url": "https://hooks.example.com/customermates",
  "events": ["contact.created", "contact.updated", "deal.updated"],
  "secret": "nutze-einen-random-string-aus-einem-password-manager",
  "enabled": true
}

Die URL muss HTTPS sein. HTTP wird abgelehnt.

Was Sie bekommen

Jede Delivery ist ein POST mit Content-Type: application/json und demselben Envelope:

{
  "event": "<event-name>",
  "data": {
    "userId": "<verursacher>",
    "companyId": "<workspace>",
    "entityId": "<betroffener-record>",
    "payload": { /* event-spezifisch */ }
  },
  "timestamp": "<iso-8601>"
}

userId ist der User, der den Write verursacht hat, inklusive User, die über einen API-Key handeln. Bei Messaging-Events, die durch eingehende Provider-Aktivität statt durch eine User-Aktion ausgelöst werden, ist userId gleich null.

Bei *.updated-Events umschließt payload den vollständigen Record zusammen mit einem changes-Objekt. Bei *.created- und *.deleted-Events ist payload der Record selbst.

Beispiel, contact.updated:

{
  "event": "contact.updated",
  "data": {
    "userId": "u_123",
    "companyId": "c_abc",
    "entityId": "ct_xyz",
    "payload": {
      "contact": {
        "id": "ct_xyz",
        "firstName": "Max",
        "lastName": "Mustermann",
        "notes": { /* Tiptap-JSON */ },
        "organizations": [{ "id": "org_1", "name": "Example GmbH" }],
        "users": [],
        "deals": [{ "id": "deal_1" }, { "id": "deal_2" }],
        "customFieldValues": [
          { "columnId": "col_abc", "value": "Won" }
        ]
      },
      "changes": {
        "organizations": {
          "previous": [],
          "current": [{ "id": "org_1", "name": "Example GmbH" }]
        }
      }
    }
  },
  "timestamp": "2026-04-22T10:00:00.000Z"
}

Die Record-Felder hängen vom Entity-Typ ab. Custom-Columns erscheinen unter customFieldValues als columnId- und value-Paare. Mit get_record_schema sehen Sie die Columns, die für einen Entity-Typ in Ihrem Workspace konfiguriert sind.

Das changes-Objekt

changes existiert nur bei *.updated-Events. Jeder Key ist ein Record-Feld, dessen Wert sich geändert hat. previous ist der Wert vor dem Write, current der Wert danach.

Arrays verknüpfter Records werden per id verglichen. Objekte per Deep-Equal. Skalare Felder per Wert. createdAt und updatedAt werden nie als Änderung gemeldet.

Wenn ein Write kein Feld ändert, wird das Event unterdrückt. No-op-*.updated-Events werden nicht zugestellt.

Signatur-Verifikation

Wenn Sie ein secret setzen, enthält jede Request:

X-Webhook-Signature: <hex>

<hex> ist HMAC-SHA256(secret, rawRequestBody), Lowercase-Hex, ohne Präfix. Berechnen Sie den Wert auf Ihrer Seite neu und vergleichen Sie in konstanter Zeit.

Node.js-Beispiel:

import crypto from "crypto";

function verify(rawBody: string, received: string, secret: string) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}

Retries und fehlgeschlagene Deliveries

Jede Delivery wird protokolliert. Deliveries sehen Sie in der UI (Unternehmen, dann Webhook-Deliveries) oder per manage_webhooks mit action: "list_deliveries".

Eine Delivery gilt als fehlgeschlagen, wenn der HTTP-Status außerhalb des 2xx-Bereichs liegt oder die Request timeoutet. Der Request-Timeout beträgt 5 Sekunden.

Customermates wiederholt fehlgeschlagene Deliveries automatisch: bis zu 5 Wiederholungen bei Timeouts, 5xx-Responses und 408, 425 und 429. Dauerhafte 4xx-Responses (zum Beispiel 400, 401, 403, 404) werden nicht wiederholt, weil ein erneuter Versuch genauso scheitern würde. Die Retries laufen innerhalb des Delivery-Runs, erzeugen also keine zusätzlichen Delivery-Records; jeder Record zeigt das Endergebnis.

Sie können jede Delivery zusätzlich selbst erneut zustellen, aus der UI oder per manage_webhooks mit action: "resend_delivery" und der Delivery-id. Ein manueller Resend erzeugt einen neuen Delivery-Record; das Original bleibt unverändert.

Ordering und Concurrency

Deliveries sind über Events hinweg nicht strikt geordnet. Zwei contact.updated-Events im Millisekundenabstand können in falscher Reihenfolge ankommen. Löse die Reihenfolge über den timestamp im Payload auf oder behandle Deliveries als idempotente Messages mit entityId als Schlüssel.

Notes sind JSON, nicht Markdown

Das notes-Feld in Payloads ist Tiptap-JSON, dieselbe Struktur, die der Editor speichert. Um es auf Ihrer Seite als Markdown zu rendern, nutzen Sie einen Tiptap-kompatiblen Serializer. In MCP liefert get_records mit include: "withNotes" die Notes bereits als Markdown serialisiert.

Delete-Payloads

Delete-Events enthalten unter payload den vollständigen Record, wie er vor dem Löschen war, nicht nur die id. Die id des betroffenen Records steht zusätzlich in data.entityId.

Debugging

  • Nutzen Sie webhook.site als Einweg-Receiver beim Integrationstest.
  • Das Delivery-Log (manage_webhooks, action: "list_deliveries") unterstützt searchTerm auf URL und Event-Name.
  • Wenn Ihr Receiver einen Fehlerstatus zurückgibt, protokolliert Customermates die Antwort, sodass Sie nachvollziehen können, was passiert ist.

Event-Katalog

Sechsundzwanzig Events können Sie abonnieren: fünfzehn Record-Events über die fünf Entity-Typen und elf Messaging-Events. Alle nutzen den Envelope oben.

Record-Events

EventWann es feuertpayload
contact.createdEin Contact wird via UI, API, MCP oder Import erstelltvollständiger Contact
contact.updatedEin Contact-Feld ändert sichcontact, changes
contact.deletedEin Contact wird gelöschtvollständiger Contact
organization.createdEine Organization wird erstelltvollständige Organization
organization.updatedEin Organization-Feld ändert sichorganization, changes
organization.deletedEine Organization wird gelöschtvollständige Organization
deal.createdEin Deal wird erstelltvollständiger Deal
deal.updatedEin Deal-Feld ändert sichdeal, changes
deal.deletedEin Deal wird gelöschtvollständiger Deal
service.createdEin Service wird erstelltvollständiger Service
service.updatedEin Service-Feld ändert sichservice, changes
service.deletedEin Service wird gelöschtvollständiger Service
task.createdEin Task wird erstelltvollständiger Task
task.updatedEin Task-Feld ändert sichtask, changes
task.deletedEin Task wird gelöschtvollständiger Task

Messaging-Events

Messaging-Events feuern bei eingehender Provider-Aktivität auf verbundenen Accounts. userId ist null. Payloads referenzieren Provider-Records per id (connectedAccountId, provider, providerMessageId, threadId und ähnliche), statt CRM-Records einzubetten.

EventWann es feuert
messaging.message.receivedEine Chat-Nachricht oder E-Mail wird ingested
messaging.message.updatedEine ingestete Nachricht wird aktualisiert
messaging.message.deletedEine ingestete Nachricht wird gelöscht
messaging.message.reactionEine Reaktion wird zu einer Nachricht hinzugefügt
messaging.email.receivedEine E-Mail wird ingested
messaging.email.deletedEine ingestete E-Mail wird gelöscht
messaging.chat.updatedEin Chat-Thread wird aktualisiert
messaging.chat.deletedEin Chat-Thread wird gelöscht
messaging.calendar.changedEin verbundener Kalender ändert sich
messaging.calendar_event.changedEin Kalender-Event ändert sich
messaging.relation.createdEine neue Provider-Relation wird erstellt

Weiter

  • MCP-Tool-Katalog: Webhooks programmatisch verwalten.
  • n8n-Integration: Webhooks in visuelle Workflows einbinden.
Einsatzzwecke
Webhook anlegen
Was Sie bekommen
Das changes-Objekt
Signatur-Verifikation
Retries und fehlgeschlagene Deliveries
Ordering und Concurrency
Notes sind JSON, nicht Markdown
Delete-Payloads
Debugging
Event-Katalog
Record-Events
Messaging-Events
Weiter