scoco.ai

Webhooks: Ereignisse aus scoco in Ihre Systeme

scoco schickt jedes Ereignis, etwa einen beendeten Anruf oder einen gebuchten Termin, als signierte JSON-Nachricht an eine HTTPS-Adresse Ihrer Wahl.

Für Inhaber, Admin

Im Dashboard öffnen
Auf dieser Seite

Mit Webhooks meldet scoco Ihren eigenen Systemen in Echtzeit, was passiert, zum Beispiel „Anruf beendet" oder „Termin gebucht". Sie hinterlegen dafür eine HTTPS-Adresse, und scoco schickt jedes Ereignis als signierte JSON-Nachricht dorthin. Auch Zapier, Make und n8n verbinden Sie auf diesem Weg.

Einen Endpunkt anlegen

  1. Öffnen Sie EinstellungenIntegrationen.
  2. Klicken Sie in der Karte Automatisierung auf Webhook-Endpunkt.
  3. Tragen Sie die Adresse ein. Sie muss mit https:// beginnen.
  4. Wählen Sie bei Bedarf Ereignisse aus. Ohne Auswahl bekommen Sie alle.
  5. Klicken Sie auf Anlegen.
  6. Das Fenster Signaturschlüssel zeigt den Schlüssel (whsec_…) genau einmal. Sichern Sie ihn mit Schlüssel kopieren und schließen Sie mit Ich habe den Schlüssel gesichert.

Der Schlüssel lässt sich danach nicht mehr abrufen. Haben Sie ihn verloren, entfernen Sie den Endpunkt über sein Menü mit Entfernen und legen ihn neu an.

Ereignisse

EreignisAusgelöst, wenn
call.completedein Anruf beendet ist, mit Ergebnis, Dauer und Anrufernummer
call.summary_readydie KI-Zusammenfassung eines Anrufs vorliegt
conversation.completedeine WhatsApp-Unterhaltung abgeschlossen ist, mit Ergebnis und Kundennummer; nur mit aktivem WhatsApp
conversation.summary_readydie KI-Zusammenfassung einer WhatsApp-Unterhaltung vorliegt; nur mit aktivem WhatsApp
ticket.status_changedsich der Status eines Anrufs oder einer WhatsApp-Unterhaltung ändert: einmal automatisch nach jedem Gespräch (mit initial: true), danach bei jeder Änderung in der Inbox, auch beim Markieren als Spam
ticket.assignedein Anruf oder eine WhatsApp-Unterhaltung jemandem zugewiesen, neu zugewiesen oder die Zuweisung entfernt wird (dann to: null)
message.sms_receivedeine SMS an Ihre scoco-Nummer eingeht
message.sms_sentscoco eine SMS verschickt oder es versucht: Prüfen Sie data.status, er kann failed sein
appointment.bookedIhre Assistenz einen Termin bucht
appointment.cancelledein Termin abgesagt wird: vom Anrufer am Telefon, vom Kunden auf WhatsApp oder von Ihrem Team im Dashboard
appointment.rescheduledein Termin verschoben wird: vom Anrufer am Telefon, vom Kunden auf WhatsApp oder von Ihrem Team im Dashboard
contact.createdein Kontakt angelegt wird, von Hand oder automatisch aus einem Gespräch; ein Import meldet nichts

Neue Ereignisse kommen nur hinzu, es fällt keines weg. Ihr Empfänger sollte Ereignisse, die er nicht kennt, einfach ignorieren.

Testanrufe aus dem Dashboard lösen keine Ereignisse aus. Eine Änderung, die Sie direkt in Ihrem Kalender machen, auch nicht.

So sieht eine Nachricht aus

Jede Zustellung ist ein POST mit Content-Type: application/json. Der Header X-Scoco-Event nennt den Typ, hier ein call.completed:

{
  "id": "5f0c…",
  "type": "call.completed",
  "created_at": "2025-08-06T11:58:39+00:00",
  "tenant_id": "a319…",
  "data": {
    "call_id": "…",
    "channel": "voice",
    "assistant_id": "…",
    "caller_e164": "+4930123456",
    "started_at": "2025-08-06T11:56:01+00:00",
    "ended_at": "2025-08-06T11:58:33+00:00",
    "duration_seconds": 151.48,
    "result": "message_taken",
    "contact_id": null
  }
}

Was in data steht, hängt vom Ereignis ab. Es enthält immer die passenden IDs, alle Einzelheiten zeigt das Dashboard. Auch in data kommen Felder nur hinzu. Ein Feld kann null sein, wenn der Wert fehlt, und duration_seconds ist eine Kommazahl.

Die id bleibt bei jeder Wiederholung dieselbe. Haben Sie eine Nachricht schon verarbeitet, erkennen Sie die Wiederholung daran.

call.summary_ready und conversation.summary_ready enthalten language und original. Lief das Gespräch in einer anderen Sprache als der Ihrer Assistenz, ist language deren Kürzel, etwa ar, sonst null. Name, Firma und Anliegen kommen in der Sprache Ihres Kontos, Namen in lateinischer Schrift. Wo das von den Worten des Anrufers abweicht, stehen diese in original, unter denselben Schlüsseln, etwa der Name in arabischer Schrift unter caller_name. Sonst ist original null.

call.summary_ready enthält caller_silent. Es ist true, wenn der Anrufer aufgelegt hat, ohne etwas zu sagen. summary ist dann ein fester Satz statt einer KI-Zusammenfassung, und die Felder, die sonst aus dem Gespräch kommen, sind null.

Die beiden Terminänderungen tragen dieselbe appointment_id wie das appointment.booked des Termins. appointment.cancelled enthält starts_at, ends_at und cancelled_by (caller oder user). appointment.rescheduled enthält previous_starts_at, die neuen starts_at und ends_at und rescheduled_by (caller oder user). Beide kommen erst, wenn die Änderung in Ihrem Kalender angekommen ist.

Die Signatur prüfen

Jede Zustellung trägt den Header X-Scoco-Signature: t=1754481521,v1=5257a869e7…. v1 ist ein HMAC-SHA256 (hexadezimal) über die Zeichenkette <t>.<roher Request-Body>. Der Schlüssel ist Ihr Signaturschlüssel, genau so, wie er angezeigt wurde, mit whsec_ am Anfang. Bibliotheken für „Standard Webhooks" entfernen whsec_ und dekodieren den Rest; mit ihnen schlägt die Prüfung fehl.

t ist der Zeitpunkt der Signatur, nicht created_at: Jede Wiederholung wird neu signiert. Weisen Sie Nachrichten ab, deren t mehr als etwa 5 Minuten zurückliegt. Das schützt vor wiederholt eingespielten Nachrichten.

Prüfen Sie die Bytes, die ankommen, nicht ein neu erzeugtes JSON: Schon ein anderes Leerzeichen ändert die Signatur. In Node.js liefert etwa express.raw({ type: "application/json" }) den rohen Body, in PHP file_get_contents('php://input').

import hashlib, hmac, time

def verify(secret: str, body: bytes, header: str, tolerance: int = 300) -> bool:
    try:
        parts = dict(p.split("=", 1) for p in header.split(","))
        t, v1 = int(parts["t"]), parts["v1"]
    except (KeyError, ValueError):
        return False
    if abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected.encode(), v1.encode())

Zustellung, Wiederholung, Abschalten

  • Eine Zustellung gilt als erfolgreich, wenn Ihr Endpunkt innerhalb von 10 Sekunden mit einem 2xx-Status antwortet. Antworten Sie am besten sofort und verarbeiten Sie die Nachricht danach.
  • Schlägt eine Zustellung fehl, versucht scoco es erneut: insgesamt bis zu 5 Versuche, den ersten eingerechnet, mit Pausen von etwa 1 Minute, 5 Minuten, 15 Minuten und 1 Stunde.
  • Schlagen 20 Zustellungen nacheinander fehl und liegt die erste davon mindestens 24 Stunden zurück, schaltet scoco den Endpunkt ab und schreibt den Inhabern eine E-Mail. Mit Aktivieren schalten Sie ihn wieder ein. Was in der Zwischenzeit passiert ist, wird nicht nachgeliefert.
  • Unter Protokoll sehen Sie die neuesten 50 Zustellungen. Nach 30 Tagen wird eine Zustellung gelöscht, und wenn Sie den Endpunkt entfernen, auch sein Protokoll.
  • Mit Testen schicken Sie ein signiertes ping-Ereignis an Ihren Endpunkt. Es erscheint nicht im Protokoll und zählt nicht als Fehlschlag.

Datenschutz

Die Nachrichten enthalten personenbezogene Daten wie Anrufernummern, Namen und Zusammenfassungen. Mit einem Endpunkt beauftragen Sie scoco, diese Daten an das von Ihnen genannte System zu schicken. Sorgen Sie dort für angemessenen Schutz.