Zum Inhalt springen
XICBOT

Einstellungen

English
Dokumentation · Werkzeuge und Aktionen

Werkzeugbausatz für eigene Anbindungen

Klient, Signaturprüfung und Stromleser in Node, PHP und Python: die Schnittstelle ansprechen, Webhooks prüfen und Aufrufe von XICBOT an Ihr System beantworten.

In einfacher Sprache

Diese Seite ist für Entwickler. Der Bausatz ist Programmcode für Ihre eigene Anbindung. Es gibt ihn in drei Programmiersprachen. Mit ihm sprechen Sie die Schnittstelle an. Sie können damit eine Antwort lesen, während sie entsteht. Sie können prüfen, ob eine Meldung an Ihr System echt ist. Die Seite erklärt auch den umgekehrten Weg. Dann ruft der Assistent Ihr System auf.

Stand

Alle Themen der Dokumentation

Der Werkzeugbausatz ist Quelltext für Ihre eigene Anbindung an XICBOT, in drei Fassungen: Node (js/), PHP (php/) und Python (python/) mit je vier Dateien. Er enthält einen Klienten für die Schnittstelle mit API-Schlüssel, einen Leser für den Ereignisstrom einer Chat-Antwort, die Prüfung der Signatur eines Webhooks und die Listen der Ereignisarten. Er braucht keine weiteren Pakete: Node ruft über fetch, PHP über die curl-Erweiterung, Python über die Standardbibliothek. Der letzte Abschnitt beschreibt die Gegenrichtung: was Ihr System beantworten muss, wenn ein Assistent es als Werkzeug aufruft.

Was im Bausatz liegt

AufgabeNode (js/)PHP (php/)Python (python/)
Klient für die Schnittstelleklient.mjs: Klasse Klientklient.php: Klasse XicbotKlientklient.py: Klasse Klient
Leser für den Ereignisstromstrom.mjs: Klasse Stromstrom.php: Klasse XicbotStromstrom.py: Klasse Strom
Prüfung der Webhook-Signatursignatur.mjs: signaturPruefen()signatur.php: xicbot_signatur_pruefen()signatur.py: signatur_pruefen()
Name des SignaturkopfsSIGNATURKOPFXICBOT_SIGNATURKOPFSIGNATURKOPF
Ereignisartenereignisse.mjs: STROM_EREIGNISSE, RUECKRUF_EREIGNISSEereignisse.php: XICBOT_STROM_EREIGNISSE, XICBOT_RUECKRUF_EREIGNISSEereignisse.py: STROM_EREIGNISSE, RUECKRUF_EREIGNISSE
Aufruf überfetch, Signatur mit node:cryptocurl-Erweiterungurllib.request, Signatur mit hmac

Jede Datei nennt im Kopf die Fassung der Schnittstellenbeschreibung, aus der sie erzeugt ist; daran sehen Sie, welchen Stand der Schnittstelle Ihre Kopie abbildet. Der Klient lädt den Stromleser aus demselben Verzeichnis (./strom.mjs, strom.php, from strom import Strom); legen Sie die Dateien einer Sprache darum gemeinsam ab. Die Signaturprüfung und die Ereignislisten stehen für sich und lassen sich einzeln übernehmen, etwa in einen Empfänger, der nur Webhooks annimmt.

Adresse und Schlüssel

Der Klient bekommt zwei Angaben: die Basisadresse https://app.xicbot.de und einen API-Schlüssel. Schrägstriche am Ende der Basisadresse werden entfernt, die Pfade (/api/v1/integration/…) hängt der Klient selbst an. Fehlt die Basisadresse, brechen alle drei Fassungen schon beim Anlegen mit Basisadresse fehlt ab. Den Schlüssel sendet der Klient im Kopf X-Api-Key. Er beginnt mit xbot_; ein Wert ohne diesen Anfang gilt als fehlend.

StatusFeld errorBedeutung
400key_in_urlSchlüssel als Parameter in der Adresse
401key_missingKopf X-Api-Key fehlt, ist leer oder beginnt nicht mit xbot_
401invalid_keySchlüssel unbekannt, zurückgezogen oder abgelaufen; die drei Fälle antworten gleich
402plan_feature_missingDas Paket des Kontos enthält die Funktion für Schlüssel und Webhooks nicht, etwa nach einem Tarifwechsel; available_in nennt die Pakete, die sie enthalten
403tenant_suspendedDas Konto zum Schlüssel ist nicht aktiv
403scope_missingDem Schlüssel fehlt der nötige Bereich, etwa leads oder chat; das Feld required nennt ihn
403read_onlyDem Schlüssel fehlt der schreibende Bereich (leads.write, knowledge.write); required nennt ihn
429too_many_requestsMinuten- oder Tagesdeckel erreicht, siehe Grenzen

Schlüssel anlegen

  1. Schritt 1

    Seite öffnen

    Schlüssel und Webhooks liegen unter Verwaltung › Schnittstellen (app.xicbot.de/schnittstellen). Der Menüpunkt erscheint für die Rollen Verwaltung und Inhaber; nur diese Rollen legen Schlüssel an und ziehen sie zurück. Die Rollen beschreibt Team, Rollen und Protokoll.

  2. Schritt 2

    Name und Bereiche wählen

    Im Abschnitt API-Schlüssel geben Sie einen Name mit höchstens 80 Zeichen ein und kreuzen unter Bereiche mindestens einen Bereich an; vorher bleibt Neuen Schlüssel anlegen gesperrt. Unter den Bereichen steht: „Schreiben ist ein eigener Bereich. Ohne ihn liest ein Schlüssel nur.“

  3. Schritt 3

    Grenze und Ablauf setzen

    Anfragen pro Minute ist ein Pflichtfeld von 1 bis 6000, vorbelegt mit 120. Läuft ab in Tagen nimmt 1 bis 3650 an; darunter steht „Leer bedeutet ohne Ablauf.“ Das Ablaufdatum wird beim Anlegen aus der Zahl der Tage berechnet.

  4. Schritt 4

    Schlüssel übernehmen

    Nach Neuen Schlüssel anlegen erscheint die Karte Ihr neuer Schlüssel mit dem Wert: xbot_ und 48 Zeichen. Darunter steht „Jetzt kopieren. Nach dem Schließen ist er nicht wieder abrufbar.“ Der Knopf Schlüssel kopieren legt ihn in die Zwischenablage; geht das nicht, erscheint „Die Zwischenablage ist hier nicht verfügbar. Markieren Sie den Wert und kopieren Sie ihn von Hand.“ Vom Schlüssel selbst speichert XICBOT nur einen SHA-256-Abdruck und die Kennung, die ersten 12 Zeichen.

Die Liste der Schlüssel zeigt Name, Kennung, Bereiche, Zuletzt benutzt, Läuft ab (bei Schlüsseln ohne Ablauf ohne Frist), Status mit gültig, abgelaufen oder zurückgezogen und Aktion. Zuletzt benutzt wird höchstens einmal je Minute nachgetragen. Neben dem Knopf zum Anlegen steht der Zähler der gültigen Schlüssel, etwa 3 / 10. Höchstens zehn Schlüssel sind gleichzeitig gültig; der elfte wird mit 422, too_many_keys und der Meldung „Die Höchstzahl gleichzeitiger Schlüssel ist erreicht.“ abgelehnt. Zurückgezogene und abgelaufene Schlüssel zählen nicht mit.

Zurückziehen fragt in der Zeile nach: „Schlüssel zurückziehen? Anfragen mit diesem Schlüssel werden danach abgewiesen.“ Bestätigen Sie mit Zurückziehen oder brechen Sie mit Abbrechen ab. Danach antwortet die Schnittstelle auf diesen Schlüssel mit 401 und invalid_key; die Zeile bleibt mit dem Status zurückgezogen in der Liste. Einen Schlüssel ändern können Sie nicht. Für andere Bereiche oder eine andere Grenze legen Sie einen neuen an, stellen Ihr System um und ziehen den alten zurück. Mehr zur Verwaltung steht unter API-Schlüssel und Webhooks.

Bereiche

BereichIn der AppErlaubt
conversationsGespräche lesenGespräche auflisten und ein Gespräch mit seinen Nachrichten im Klartext lesen
leadsAnfragen lesenAnfragen auflisten
leads.writeAnfragen anlegenEine Anfrage anlegen
appointmentsTermine lesenTermine auflisten
analyticsAuswertung lesenKennzahlen für 7, 30 oder 90 Tage abrufen
knowledge.writeWissensquellen anlegenEine Wissensquelle aus Text oder Adresse anlegen
chatChat verwendenEinem Assistenten eine Frage stellen und die Antwort als Strom lesen
ohne–GET /api/v1/integration/status beantwortet jeder gültige Schlüssel

Ein schreibender Bereich schließt den lesenden nicht ein: leads.write legt Anfragen an, liest sie aber nicht. GET /api/v1/integration/status liefert alive, die Kennung des Kontos in tenant, die Bereiche des Schlüssels in scopes und seine Minutengrenze in limit_per_min. So prüfen Sie eine Anbindung, ohne Daten zu lesen. Die einzelnen Vorgänge beschreibt Schnittstelle: Integration.

Grenzen

Jeder Schlüssel hat einen eigenen Deckel je Minute, den Wert aus Anfragen pro Minute. Dazu kommt ein Tagesdeckel aus Ihrem Konto. Er wird je Schlüssel und Kalendertag gezählt und verfällt um Mitternacht, nicht 24 Stunden nach der ersten Anfrage; ein Tagesdeckel von 0 bedeutet: kein Tagesdeckel. Beide Deckel werden geprüft, bevor einer von beiden zählt, eine am Deckel abgewiesene Anfrage verbraucht also nichts. Auch GET /api/v1/integration/status zählt mit. Die Höhe des Tagesdeckels nennt eine 429-Antwort mit scope day im Feld limit; GET /api/v1/integration/status meldet nur den Minutendeckel als limit_per_min.

Feld der Antwort 429Inhalt
errortoo_many_requests
scopeminute oder day: welcher Deckel gegriffen hat
limitWert dieses Deckels
retry_afterSekunden bis zum nächsten sinnvollen Versuch; derselbe Wert steht im Kopf Retry-After
limit_per_minMinutendeckel des Schlüssels, auch wenn der Tagesdeckel gegriffen hat
waitgleicher Wert wie retry_after

Der Klient wirft bei 429 einen Fehler mit Status und Text der Antwort; ein Wiederholen nach retry_after bauen Sie selbst. Das Kontingent an Antworten ist davon getrennt: ist es für den Monat verbraucht, antwortet der Chat mit 429 und quota_exhausted, siehe Chat und Ereignisstrom. Übersicht aller Grenzen: Schnittstelle: Paketsperren und Drosseln.

Der Klient

Der Klient bildet jeden Vorgang der Schnittstelle als eigene Methode ab, benannt nach Verfahren und Pfad. Sie legen ihn mit Basisadresse, Schlüssel und Frist an; die Frist begrenzt jeden Aufruf, dessen Antwort in einem Stück kommt.

AngabeNodePHPPython
Anlegennew Klient(basis, schluessel, frist)new XicbotKlient($basis, $schluessel, $frist)Klient(basis, schluessel, frist, stream_timeout)
Voreinstellung der Frist15000 Millisekunden15 Sekunden15 Sekunden
Lesefrist im Chatkeinekeinestream_timeout, voreingestellt 120 Sekunden je Lesevorgang
Leere BasisadresseError mit Basisadresse fehltInvalidArgumentException mit Basisadresse fehltValueError mit Basisadresse fehlt
Schreibweise der MethodengetStatus(), postLeads(daten)getStatus(), postLeads($daten)get_status(), post_leads(daten)
Rückgabe (außer Chat)Promise mit dem gelesenen JSONArrayDictionary

Für den Chat setzen die Node- und die PHP-Fassung keine Frist: der Strom läuft, solange die Antwort entsteht. Die Python-Fassung liest den Strom Zeile für Zeile und bricht ab, wenn ein einzelner Lesevorgang länger als stream_timeout auf Daten wartet, voreingestellt 120 Sekunden. Jede Anfrage trägt Content-Type: application/json, Accept: application/json und den Schlüssel in X-Api-Key; beim Chat bittet der Klient um text/event-stream.

Methode (Node, PHP)Methode (Python)VorgangBereichPflichtfelder im Klienten
getStatus()get_status()GET /api/v1/integration/statusohne–
getConversations(page)get_conversations(page)GET /api/v1/integration/conversationsconversations–
getConversationsId(id)get_conversations_id(id)GET /api/v1/integration/conversations/{id}conversations–
getLeads(page)get_leads(page)GET /api/v1/integration/leadsleads–
postLeads(daten)post_leads(daten)POST /api/v1/integration/leadsleads.writesubject
getAppointments(page)get_appointments(page)GET /api/v1/integration/appointmentsappointments–
getAnalytics(period, zone)get_analytics(period, zone)GET /api/v1/integration/analyticsanalytics–
postKnowledgeSources(daten)post_knowledge_sources(daten)POST /api/v1/integration/knowledge/sourcesknowledge.writetitle; text oder url
postChat(daten, leser)post_chat(daten, leser)POST /api/v1/integration/chatchatassistant_id, text

Fehlt ein Pflichtfeld, bricht der Klient vor dem Senden ab, mit der Meldung Pflichtfeld fehlt: <Feld> als Error (Node), InvalidArgumentException (PHP) oder ValueError (Python). Beim Anlegen einer Wissensquelle verlangt er außerdem text oder url und meldet sonst Eines der Felder fehlt: text oder url. Alle übrigen Regeln prüft XICBOT und antwortet bei einem Verstoß mit 422. Gespräche und Anfragen kommen neueste zuerst, Termine nach Beginn, der späteste zuerst. Die drei Listen liefern 50 Einträge je Aufruf; page wählt die Seite, gezählt ab 1, ein fehlender oder kleinerer Wert gilt als 1. Lesen Sie weiter, bis eine Seite weniger als 50 Einträge hat. getAnalytics nimmt mit zone eine Zeitzone nach IANA, Vorgabe Europe/Berlin; eine unbekannte Zone beantwortet XICBOT mit 422 und unknown_timezone. Ein einzelnes Gespräch liefert bis zu 200 Nachrichten in zeitlicher Folge mit role, text und time; eine unbekannte Kennung beantwortet XICBOT mit 404 und not_found.

Was XICBOT prüft

VorgangFeldRegel
Anfrage anlegensubjectPflicht, höchstens 1000 Zeichen
Anfrage anlegennamehöchstens 120 Zeichen
Anfrage anlegenemailgültige E-Mail-Adresse, höchstens 190 Zeichen
Anfrage anlegenphonehöchstens 60 Zeichen
Anfrage anlegensourcehöchstens 60 Zeichen; ohne Angabe api
Anfrage anlegenexternal_idhöchstens 100 Zeichen; verhindert doppelte Einträge
Wissensquelle anlegentitlePflicht, höchstens 200 Zeichen
Wissensquelle anlegentextPflicht, wenn url fehlt; höchstens 400000 Zeichen
Wissensquelle anlegenurlPflicht, wenn text fehlt; gültige Adresse, höchstens 500 Zeichen
Wissensquelle anlegendraft, published_atnur zusammen mit text; draft ist wahr oder falsch, published_at ein Datum
Auswertungperiod7d, 30d oder 90d; ohne Angabe 30d
Chatassistant_idPflicht, höchstens 64 Zeichen
Chatconversation_idhöchstens 64 Zeichen; setzt ein Gespräch fort
ChattextPflicht, 1 bis 4000 Zeichen; das Konto kann eine kürzere Grenze setzen

Eine neue Anfrage beantwortet XICBOT mit 201, dem Eintrag unter lead und duplicate_prevented: false; zugleich geht der Webhook lead.created hinaus. Kommt dieselbe external_id ein zweites Mal, entsteht kein zweiter Eintrag: die Antwort ist 200 mit dem vorhandenen Eintrag und duplicate_prevented: true. Senden Sie deshalb nach einer Zeitüberschreitung mit derselben external_id erneut. Wie Anfragen in der App weiterlaufen, steht unter Termine und Vorgänge.

Eine Wissensquelle mit text nimmt XICBOT sofort auf und antwortet mit 201; unter source stehen id, type (text), status und chunks; dazu geht knowledge.indexed oder knowledge.failed hinaus. Die 201 kommt auch dann, wenn die Aufnahme gescheitert ist – ob sie gelungen ist, sagt status (ready). Eine Quelle mit url legt XICBOT mit 202 an, unter source mit id, type website und status new, und holt die Seite im Hintergrund ab. Wie beim Anlegen in der App reiht XICBOT für beide Arten zusätzlich einen Hintergrundauftrag ein, der die Abschnitte anreichert und ihre Vektoren bildet; danach findet die Suche die Quelle in der Regel auch nach der Bedeutung und nicht nur über gleiche Wörter. Adressen, die nicht ins offene Netz zeigen, weist XICBOT mit 422 ab und nennt den Grund in error, etwa target_not_allowed. Mehr zu Quellen steht unter Wissen pflegen.

Fehler im Klienten

FallNodePHPPython
Status 400 oder höherError: Antwort <Status>: <Text>RuntimeException: Antwort <Status>: <Text>RuntimeError: Antwort <Status>: <Text>
Keine Verbindung oder Frist abgelaufenFehler von fetch, bei der Frist ein TimeoutErrorRuntimeException: Aufruf fehlgeschlagen: …RuntimeError: Aufruf fehlgeschlagen: …
Antwort ist kein JSONleeres Objekt {}leeres Array []leeres Dictionary {}
Chat mit Status 400 oder höherError: Antwort <Status>: <Text>RuntimeException: Antwort <Status>: <Text>RuntimeError: Antwort <Status>: <Text>
Chat-Übertragung abgebrochenFehler des Stroms; ohne Körper Antwort ohne StromRuntimeException: Strom abgebrochen: …RuntimeError: Strom abgebrochen: …, auch wenn die Lesefrist abläuft

Der Text nach dem Status ist der Körper der Fehlerantwort, bei XICBOT ein JSON mit error. Die Bedeutung der Werte steht in der Tabelle unter Adresse und Schlüssel und beim Chat.

Chat und Ereignisstrom

POST /api/v1/integration/chat

Stellt einem Assistenten eine Frage und liefert die Antwort als Ereignisstrom (text/event-stream). Ohne conversation_id beginnt ein neues Gespräch; mit ihr geht ein Gespräch weiter, das derselbe Assistent über die Schnittstelle begonnen hat.

Anmeldung
Kopf X-Api-Key, Bereich chat
Begrenzung
Minuten- und Tagesdeckel des Schlüssels, dazu das Monatskontingent des Kontos

Jedes Ereignis besteht aus einer Zeile event: <Art>, einer oder mehreren Zeilen data: <JSON> und einer Leerzeile. Der Stromleser des Bausatzes gibt ein Ereignis erst heraus, wenn die Leerzeile da ist, fügt mehrere data-Zeilen mit Zeilenumbruch zusammen, entfernt ein \r am Zeilenende und reicht Art und Daten an Ihre Funktion weiter. Ist der Inhalt kein gültiges JSON, kommen die Daten als null (Python: None) an.

StatusFeld errorBedeutung
404not_foundAssistent unbekannt, oder conversation_id ist kein Schnittstellengespräch dieses Assistenten
409reply_in_progressFür dieses Gespräch entsteht gerade eine Antwort
413input_too_longText länger als die Grenze des Kontos; limit und length nennen beide Werte. Ein neues Gespräch entsteht dabei nicht
422no_versionDer Assistent hat noch keine veröffentlichte Fassung
429quota_exhaustedMonatskontingent verbraucht; scope ist month, retry_after und der Kopf Retry-After nennen die Sekunden bis zum Monatswechsel. Ein Gespräch, das erst dieser Aufruf begonnen hat, entfernt XICBOT in der Regel wieder

Ein Gespräch aus dem Widget oder aus einem Testgespräch lässt sich über die Schnittstelle nicht fortsetzen, auch nicht mit dem Bereich conversations: XICBOT antwortet dann mit 404. Wie viel das Konto im Monat beantworten darf, steht unter Pakete, Kontingente und Abrechnung.

Ereignisarten

ArtFelderBedeutung
startconversation_id, question_idDie Antwort beginnt; conversation_id brauchen Sie zum Fortsetzen
texttEin Stück Antworttext; die Stücke ergeben aneinandergereiht die Antwort
redactiontext, reason, count (nur bei claims)Ersetzt den bisher gesammelten Text durch text; reason ist claims (Berichtigung ungedeckter Aussagen) oder notice. Danach folgende text-Stücke hängen Sie an
citationscitationsDie in der Antwort genutzten Belege
verificationstate, claims, totalErgebnis der Prüfung gegen das Wissen
enforcementstate, topics, handoverErgebnis der Prüfung gegen die Assistentenregeln
follow_upsquestions, dropped, checked, reasonVorgeschlagene Anschlussfragen
contact_offerofferedDie Antwort bietet eine Kontaktaufnahme an
handoffhandoff, reasonÜbergabe an einen Menschen; reason ist etwa assistant, conversation_limit oder enforcement
livelive, sinceEin Mensch hat das Gespräch übernommen; es folgt end mit live
fallbackreason, transientDie Antwort ist gescheitert; es folgt die hinterlegte Notfallantwort als text
revokedreasonDie Einwilligung wurde widerrufen (consent_revoked); der Text wird verworfen
errorcode, scope, retry_after, limitDas Gespräch ist gesperrt oder am Deckel; bei conversation_limit folgen ein Hinweistext und handoff
toolAngaben zum WerkzeugaufrufEin Werkzeugaufruf des Assistenten
model_switchreason, from, toInterner Wechsel während der Antwort, für Ihre Anbindung ohne Bedeutung
endstate, message_id, duration_ms und weitereLetztes Ereignis; state ist done, aborted, fallback, revoked, live oder blocked

Der Hinweistext bei conversation_limit lautet auf Deutsch: „Dieses Gespräch hat die vereinbarte Länge erreicht. Ich übergebe an einen Menschen – bitte hinterlassen Sie Ihre Frage zusammen mit einer Kontaktmöglichkeit, oder beginnen Sie ein neues Gespräch.“ Ist das Gespräch aus einem anderen Grund gesperrt, folgt auf error die Notfallantwort des Assistenten und end mit blocked.

chat.mjs javascript

import { Klient } from './klient.mjs';

const klient = new Klient('https://app.xicbot.de', process.env.XICBOT_KEY);
let antwort = '';

await klient.postChat({ assistant_id: 'ASSISTENT_ID', text: 'Wann haben Sie geöffnet?' }, (art, daten) => {
	if (art === 'start') console.log('Gespräch', daten.conversation_id);
	else if (art === 'text') antwort += daten.t;
	else if (art === 'redaction') antwort = daten.text;
	else if (art === 'error') console.error('Gesperrt:', daten.code);
	else if (art === 'end') console.log(antwort, daten.state);
	// alle anderen Arten: überspringen
});

anfrage.py python

import os
from klient import Klient

klient = Klient('https://app.xicbot.de', os.environ['XICBOT_KEY'])
ergebnis = klient.post_leads({
    'subject': 'Rückruf zum Angebot',
    'email': 'kunde@example.com',
    'external_id': 'crm-4711',
})
# 201 beim ersten Mal, 200 mit duplicate_prevented bei Wiederholung
print(ergebnis['lead']['id'], ergebnis['duplicate_prevented'])

Den Aufbau aller Vorgänge beschreibt Schnittstelle: Integration; wie Gespräche in der App erscheinen, steht unter Gespräche.

Webhooks prüfen

Ein Webhook schickt Ereignisse aus Ihrem Konto an eine Adresse Ihres Systems. Sie richten ihn auf derselben Seite ein wie die Schlüssel, unter Verwaltung › Schnittstellen im Abschnitt Webhooks: „Jede Sendung trägt eine Unterschrift im Kopf X-XICBOT-Signature. Fehlgeschlagene Sendungen werden wiederholt.“

  1. Schritt 1

    Adresse eintragen

    Unter Zieladresse tragen Sie eine Adresse mit höchstens 2048 Zeichen ein. Sie muss ins offene Netz zeigen; sonst erscheint „Diese Adresse ist als Ziel nicht zugelassen.“

  2. Schritt 2

    Ereignisse wählen

    Unter Ereignisse kreuzen Sie mindestens eines an. Webhook anlegen bleibt gesperrt, bis Adresse und ein Ereignis gesetzt sind.

  3. Schritt 3

    Geheimnis übernehmen

    Nach dem Anlegen zeigt die Seite Ihr Signaturgeheimnis einmalig: whsec_ und 48 Zeichen, darunter „Damit prüfen Sie die Unterschrift der eingehenden Sendung.“ Mit Geheimnis kopieren übernehmen Sie es in Ihr System.

Jede Sendung ist ein POST mit einem JSON-Körper aus vier Feldern: event (die Ereignisart), at (Zeitpunkt des Ereignisses im ISO-8601-Format, in jeder Wiederholung derselbe), tenant (Kennung Ihres Kontos) und data (die Nutzdaten des Ereignisses). Dazu kommen diese Köpfe:

KopfInhalt
X-XICBOT-EventDie Ereignisart, etwa lead.created
X-XICBOT-DeliveryEine UUID je Ereignis und Empfänger; jede Wiederholung trägt dieselbe
X-XICBOT-AttemptNummer des Versuchs, beginnend bei 1
X-XICBOT-Signaturet=<Unix-Zeit>,v1=<HMAC-SHA256 in Hex>
User-AgentXICBOT-Webhook/1

Signatur prüfen

  1. Schritt 1

    Rohkörper lesen

    Unterschrieben ist der Körper genau so, wie er ankommt. Lesen Sie ihn vor jeder JSON-Verarbeitung; ein Körper, der erst gelesen und dann neu geschrieben wird, ergibt eine andere Zeichenkette und eine abweichende Signatur.

  2. Schritt 2

    Kopf zerlegen

    Der Kopf X-XICBOT-Signature enthält durch Komma getrennt t und v1. Fehlt eines davon oder enthält t etwas anderes als Ziffern, ist die Sendung abzulehnen.

  3. Schritt 3

    Alter prüfen

    Weicht t um mehr als 300 Sekunden von Ihrer Uhr ab, lehnt der Bausatz ab. Der Wert ist der Parameter hoechstalter; 0 schaltet die Prüfung ab, womit eine mitgelesene Sendung beliebig oft eingespielt werden kann.

  4. Schritt 4

    Signatur berechnen

    HMAC-SHA256 über t, einen Punkt und den Rohkörper, mit dem Signaturgeheimnis als Schlüssel, als Hex-Zeichenkette.

  5. Schritt 5

    In gleichbleibender Zeit vergleichen

    Der Bausatz vergleicht mit timingSafeEqual (Node), hash_equals (PHP) oder hmac.compare_digest (Python). Ein abbrechender Vergleich verrät über die Laufzeit, wie viele Zeichen schon stimmen.

SpracheAufrufErgebnis
NodesignaturPruefen(koerper, kopf, geheimnis, hoechstalter = 300)true oder false; koerper als Zeichenkette oder Buffer
PHPxicbot_signatur_pruefen($koerper, $kopf, $geheimnis, $hoechstalter = 300)true oder false
Pythonsignatur_pruefen(koerper, kopf, geheimnis, hoechstalter=300)True oder False, auch bei einem Körper, der kein gültiges UTF-8 ist; koerper als bytes oder str

webhook.php php

<?php
require_once __DIR__.'/signatur.php';

$koerper = file_get_contents('php://input');
$kopf = $_SERVER['HTTP_X_XICBOT_SIGNATURE'] ?? '';
$geheimnis = (string) getenv('XICBOT_WEBHOOK_SECRET');

if (! xicbot_signatur_pruefen($koerper, $kopf, $geheimnis)) {
    http_response_code(401);
    exit;
}

$sendung = json_decode($koerper, true);
// $sendung['event'] und $sendung['data'] auswerten
http_response_code(204);

Zustellung und Wiederholung

  • XICBOT wartet bis zu 8 Sekunden auf Ihre Antwort. Jeder Status von 200 bis 299 gilt als zugestellt; Weiterleitungen verfolgt XICBOT nicht.
  • Zugestellt wird an jeden Webhook, der eingeschaltet ist und das Ereignis abonniert hat.
  • Die Adresse wird beim Anlegen und vor jedem Versand erneut geprüft.
  • Scheitert ein Versuch, folgen bis zu drei Versuche insgesamt, in der Regel nach 30 und nach 120 Sekunden. Jede Wiederholung trägt dieselbe X-XICBOT-Delivery und dasselbe at, eine höhere X-XICBOT-Attempt und eine neu berechnete Signatur mit aktuellem t.
  • Fehler in Folge zählt jeden gescheiterten Versuch, auch eine Sendung, die schon die Prüfung der Adresse vor dem Versand aufhält, und fällt nach einer gelungenen Zustellung auf 0. Ein Signaturgeheimnis, das sich nicht lesen ließ (secret_unreadable), zählt nicht mit. Bei 20 schaltet XICBOT den Webhook ab; die Zeile zeigt dann abgeschaltet. Schalten Sie ihn wieder ein, beginnt die Zählung bei 0.
  • Die Schaltfläche in der Zeile nennt die Handlung: Abschalten bei einem laufenden Webhook, Einschalten bei einem abgeschalteten.
  • Zustellungen zeigt die letzten 50 Versuche mit Zeit, Ereignisse, Versuch, Status und Dauer in Millisekunden. Löschen fragt zuerst nach: „Diesen Webhook löschen? Zustellungen an diese Adresse enden sofort, und das Signaturgeheimnis lässt sich nicht wiederherstellen.“ Darunter steht die Adresse des Webhooks. Gelöscht wird erst mit Löschen im Dialog; Abbrechen lässt ihn bestehen.

Die Spalte Status zeigt den Status Ihrer Antwort oder einen dieser Gründe:

GrundAnzeige
redirect_not_followedDas Ziel hat umgeleitet. Umleitungen werden nicht verfolgt – bitte die endgültige Adresse eintragen.
secret_unreadableDas Signaturgeheimnis ließ sich nicht lesen.
webhook_inactiveDer Empfänger ist abgeschaltet.
webhook_deletedDer Empfänger ist gelöscht.
url_unreadableDie Adresse ist nicht lesbar.
scheme_not_allowedDiese Adressart wird nicht unterstützt.
name_unresolvableDer Name der Adresse lässt sich nicht auflösen.
target_not_allowedDieses Ziel ist nicht erlaubt, etwa eine interne Adresse.

Ereignisse

EreignisIn der App
conversation.startedGespräch begonnen
conversation.endedGespräch beendet
handoff.triggeredÜbergabe ausgelöst
lead.createdAnfrage erstellt
appointment.requestedTermin angefragt
appointment.confirmedTermin bestätigt
knowledge.indexedWissensquelle aufgenommen
knowledge.failedWissensquelle fehlgeschlagen
gap.detectedWissenslücke erkannt
budget.exhaustedBudget erschöpft

RUECKRUF_EREIGNISSE im Bausatz enthält dieselben zehn Arten. Schlüssel und Webhooks aus Sicht der Verwaltung beschreibt API-Schlüssel und Webhooks.

Wenn XICBOT Ihr System aufruft

Ein Assistent kann Ihr System als Werkzeug aufrufen. Werkzeuge richten Sie je Assistent unter Auslöser › Werkzeuge ein: mit der Bauform Eigene Schnittstelle für einen freien Aufruf, oder mit einer Bauform, die ein festes Format spricht, etwa Freie Zeiten lesen. Alles zu Freigabe, Mindestrolle und Pflichtangaben steht unter Werkzeuge anlegen und freigeben.

FeldRegel
SchlüsselKleinbuchstabe am Anfang, danach Kleinbuchstaben, Ziffern und Unterstrich; 3 bis 64 Zeichen, je Assistent einmalig
BezeichnungPflicht, bis 120 Zeichen
Wann soll der Assistent es benutzen?Pflicht, bis 600 Zeichen
Adresse der Schnittstellehttp:// oder https://, ins offene Netz; geprüft beim Speichern und vor jedem Aufruf. Eigene Schnittstelle und die Bauformen mit festem Format verlangen sie: ohne Adresse lässt sich das Werkzeug nicht speichern, und am Feld steht „Diese Bauform spricht mit einem fremden System. Ohne Adresse der Schnittstelle kann sie nicht arbeiten.“ Lehnt der Dienst die Adresse ab, nennt der Satz am Feld den Grund, etwa „Der Name dieser Adresse lässt sich nicht auflösen. Bitte prüfen Sie die Schreibweise.“; alle Sätze stehen unter Welche Adressen erlaubt sind.
ZugangsmarkeGeht als authorization: Bearer <Marke> mit; ein leeres Feld lässt eine hinterlegte Marke unverändert
Felder der EingabeNur bei Eigene Schnittstelle: bis zu 20 Felder; Name mit Kleinbuchstabe am Anfang, danach a–z, 0–9 und _, bis 40 Zeichen
Typstring, integer, number oder boolean; andere Angaben werden zu string
Beschreibung eines FeldsBis 200 Zeichen

Felder mit den Namen tenant_id, mandant, mandant_id und konto_id nimmt XICBOT nicht an: Ein Werkzeug mit einem solchen Feld lässt sich nicht speichern. Ihr System erhält nur Felder, die im Werkzeug erklärt sind; was der Assistent darüber hinaus mitschickt, entfällt.

Eigene Schnittstelle

Bei der Bauform Eigene Schnittstelle sendet XICBOT einen POST mit content-type: application/json und accept: application/json an die hinterlegte Adresse. Der Körper hat drei Felder: tool (der Schlüssel des Werkzeugs), input (die erklärten Felder) und conversation_id. Zeichenketten in input kürzt XICBOT auf 2000 Zeichen, Listen auf 50 Einträge und die Verschachtelung auf drei Ebenen. Ein Kopf idempotency-key kommt bei diesem Aufruf nicht mit.

anfrage.json json

{
  "tool": "lieferzeit",
  "input": { "postleitzahl": "10115" },
  "conversation_id": "9d1c…"
}

Den Status Ihrer Antwort reicht XICBOT als status an den Assistenten weiter. Ist die Antwort ein JSON-Objekt oder eine JSON-Liste, kommt sie als data an; jede andere Antwort geht als text weiter, gekürzt auf 2000 Zeichen. Welche Felder Ihr JSON trägt, bestimmen Sie.

Bauformen mit festem Format

Die übrigen Bauformen, die ein fremdes System ansprechen, senden einen festen Umschlag mit sieben Feldern und erwarten eine feste Antwort. Schreibende Vorgänge tragen zusätzlich den Kopf idempotency-key: 64 Hex-Zeichen, gebildet aus Gespräch, Werkzeug und Eingabe. Ein wiederholter Aufruf mit gleicher Eingabe im selben Gespräch trägt denselben Wert, sodass Ihr System ihn als Wiederholung erkennen kann. Lesende Vorgänge tragen ihn nicht.

FeldInhaltBeispiel Freie Zeiten lesen
adapterKennung der Bauformcalendar_availability
domainBereichkalender
operationArt des Vorgangs: read oder writeread
actionVorgangavailability.list
toolSchlüssel des Werkzeugswie eingetragen
conversation_idKennung des Gesprächs–
inputDie Felder der Bauformfrom (Pflicht), to, kind, duration_min

antwort.json json

{
  "ok": true,
  "data": {
    "slots": ["2026-10-06T09:00", "2026-10-06T10:30"],
    "timezone": "Europe/Berlin",
    "note": "Samstags nur vormittags"
  }
}

Aus data übernimmt XICBOT nur die Ergebnisfelder der Bauform, bei Freie Zeiten lesen slots, timezone und note. Zeichenketten werden auf 600 Zeichen gekürzt, Listen auf 20 Einträge, die Verschachtelung auf zwei Ebenen. Lehnt Ihr System ab, antwortet es mit "ok": false und einem Grund in error; XICBOT übernimmt davon bis zu 200 Zeichen. Fehlt ok, gilt die Antwort als Verstoß gegen das Format.

Grenzen des Aufrufs

GrenzeWert
Wartezeit auf die Antwortin der Regel 8 Sekunden
Verbindungsaufbauhöchstens 5 Sekunden
Größe der Antworthöchstens 64 KB, sonst verworfen
Weiterleitungenwerden nicht verfolgt
Erfolgreiche AntwortStatus 200 bis 299
Werkzeugaufrufe je Antworthöchstens 5

Ein Aufruf, der gelingt, steht im Verlauf als ausgeführt. Läuft die Wartezeit ab, steht er als Zeitgrenze überschritten da, jeder andere Fehler als fehlgeschlagen mit der Meldung, gekürzt auf 500 Zeichen. Zu jedem Aufruf hält XICBOT die Dauer in Millisekunden fest. Auch eine Weiterleitung endet als fehlgeschlagen. Einen gescheiterten Aufruf wiederholt XICBOT nicht von sich aus. Diese Meldungen können erscheinen:

MeldungAnlass
Für dieses Werkzeug ist keine gültige Adresse hinterlegt.Adresse fehlt oder beginnt nicht mit http:// oder https://
Die hinterlegte Adresse zeigt nicht ins offene Netz.Prüfung unmittelbar vor dem Aufruf
Das Werkzeug hat innerhalb von 8 Sekunden nicht geantwortet.Wartezeit abgelaufen
Das Werkzeug war nicht erreichbar.Verbindung gescheitert
Das Werkzeug hat mehr als 64 KB geliefert. Die Antwort wurde verworfen.Antwort zu groß
Das Werkzeug hat weitergeleitet (Status 302). Einer Weiterleitung folgt es nicht.Status 300 bis 399, hier am Beispiel 302
Das Werkzeug hat mit Status 500 geantwortet.Anderer Status außerhalb von 200 bis 299, hier 500
Das angebundene System hat nicht nach dem Anbindungsvertrag geantwortet.Bauform mit festem Format: kein JSON oder kein Feld ok
Das angebundene System hat den Vorgang abgelehnt: <Grund>Bauform mit festem Format: ok ist nicht true
Dieses Werkzeug gibt es für diesen Assistenten nicht.Der Assistent ruft einen unbekannten Schlüssel auf
Dieses Werkzeug ist für diesen Zugang nicht freigegeben.Die Rolle im Gespräch liegt unter der Mindestrolle
Der Deckel von 5 Werkzeugaufrufen je Antwort ist erreicht.Sechster Aufruf in einer Antwort

Ob ein Aufruf sofort läuft oder erst nach Bestätigung durch den Besucher, legt die Freigabe fest: ohne Rückfrage oder mit Bestätigung. Eigene Schnittstelle ist mit mit Bestätigung vorbelegt. Sofort läuft ein lesendes Werkzeug mit ohne Rückfrage, außerdem die Abfrage freier Zeiten bei Termin vereinbaren; ein schreibendes speichert XICBOT mit mit Bestätigung, gleich was gewählt ist. Fehlt ein Pflichtfeld der Eingabe, endet der Aufruf als fehlgeschlagen, bevor Ihr System angesprochen wird. Details stehen unter Werkzeuge anlegen und freigeben.

Häufige Fragen

Warum schlägt die Signaturprüfung fehl, obwohl das Geheimnis stimmt?

Meist wurde der Körper vor der Prüfung als JSON gelesen und neu geschrieben, statt den Rohkörper zu verwenden. Weitere Ursachen: das Geheimnis eines anderen Webhooks, eine Serveruhr, die mehr als 300 Sekunden abweicht, oder ein Proxy, der den Körper verändert.

Wie erkenne ich, dass eine Webhook-Sendung wiederholt wurde?

Am Kopf X-XICBOT-Attempt, der ab dem zweiten Versuch größer als 1 ist. X-XICBOT-Delivery behält in jeder Wiederholung dieselbe UUID; an ihr erkennen Sie eine Sendung, die Sie schon verarbeitet haben. Für Anfragen hilft außerdem der Inhalt von data, etwa die id.

Warum bekomme ich 401 trotz Schlüssel?

key_missing heißt: der Kopf X-Api-Key fehlt oder der Wert beginnt nicht mit xbot_. invalid_key heißt: der Schlüssel ist unbekannt, zurückgezogen oder abgelaufen. Ob ein Schlüssel zurückgezogen oder abgelaufen ist, zeigt die Spalte Status in der Liste unter Schnittstellen.

Kann ich ein Gespräch aus dem Widget über die Schnittstelle fortsetzen?

Nein. Mit conversation_id geht nur ein Gespräch weiter, das derselbe Assistent über die Schnittstelle begonnen hat; alle anderen beantwortet XICBOT mit 404 und not_found.

Mein System braucht länger als 8 Sekunden. Was passiert?

Der Aufruf endet als Zeitgrenze überschritten, und der Assistent erhält kein Ergebnis. Liefern Sie eine schnelle Antwort, etwa eine Vorgangsnummer, und erledigen Sie die lange Arbeit danach.

Eine Stelle ist unklar geblieben?

Schreiben Sie uns, welche Seite und welcher Schritt gemeint ist. Wir antworten persönlich.

Anfrage in drei Schritten

  1. 1. Anliegen
  2. 2. Ihr Fall
  3. 3. Kontakt

Worum geht es?

Ein Klick genügt, alles Weitere ist freiwillig.

Erzählen Sie kurz von Ihrem Fall

Alle Angaben in diesem Schritt sind freiwillig. Sie helfen uns, gleich mit etwas Konkretem zu antworten statt mit Rückfragen.

Anfragen im Monat, ungefähr (optional)
Wann soll es losgehen? (optional)
Wie erreichen wir Sie?

Name und E-Mail-Adresse genügen. Wir antworten persönlich.

Wir verwenden Ihre Angaben, um Ihre Anfrage zu bearbeiten. Mehr dazu in der Datenschutzerklärung.