Postcall Webhook
Empfangen Sie Transkripte und Analysedaten nach jedem Anruf
Postcall Webhook – Dokumentation
Nach jedem Anruf sendet VOISA automatisch eine HTTP-POST-Anfrage mit dem Transkript und den Analysedaten an Ihre konfigurierte Webhook-URL.
Einrichtung
- Öffnen Sie die Agent-Einstellungen unter Erweitert > Postcall Webhook
- Geben Sie Ihre HTTPS-URL ein (z.B.
https://ihre-domain.de/api/voisa-webhook) - Speichern Sie den Agenten
- Kopieren Sie das angezeigte Webhook Secret – Sie benötigen es zur Signaturprüfung
Anforderungen an die URL
- Muss HTTPS verwenden
- Darf nicht
localhostoder eine interne IP-Adresse sein - Darf nicht auf
*.voisa.aizeigen
Payload
Jeder Webhook-Aufruf ist eine POST-Anfrage mit Content-Type: application/json.
{
"type": "post_call_transcription",
"event_timestamp": 1739537297,
"data": {
"agent_id": "agent_abc123",
"conversation_id": "conv_xyz789",
"transcript": [
{
"role": "agent",
"message": "Hallo, vielen Dank für Ihren Anruf. Wie kann ich Ihnen helfen?",
"time_in_call_secs": 0
},
{
"role": "user",
"message": "Ich möchte einen Termin vereinbaren.",
"time_in_call_secs": 3
},
{
"role": "agent",
"message": "Gerne! Für wann hätten Sie es denn gerne?",
"time_in_call_secs": 5
}
],
"metadata": {
"start_time_unix_secs": 1739537200,
"call_duration_secs": 45
},
"analysis": {
"call_successful": "true",
"transcript_summary": "Der Anrufer hat einen Termin für Freitag um 14 Uhr vereinbart.",
"evaluation_criteria_results": {},
"data_collection_results": {}
},
"conversation_initiation_client_data": {
"dynamic_variables": {
"caller_name": "Max Mustermann",
"caller_number": "+4917612345678"
}
}
},
"voisa": {
"forwarded_at": "2026-03-04T15:30:00.000Z",
"agent_name": "Praxis Dr. Müller"
}
}
Felder
| Feld | Typ | Beschreibung |
|---|---|---|
type | string | Immer "post_call_transcription" |
event_timestamp | number | Unix-Timestamp des Events |
data.agent_id | string | ID des VOISA-Agenten |
data.conversation_id | string | Eindeutige ID des Gesprächs |
data.transcript | array | Liste der Gesprächsnachrichten |
data.transcript[].role | string | "agent" oder "user" |
data.transcript[].message | string | Gesprochener Text |
data.transcript[].time_in_call_secs | number | Sekunden seit Gesprächsbeginn |
data.metadata.start_time_unix_secs | number | Unix-Timestamp des Gesprächsstarts |
data.metadata.call_duration_secs | number | Gesamtdauer in Sekunden |
data.analysis.call_successful | string | "true", "false" oder "unknown" |
data.analysis.transcript_summary | string | KI-generierte Zusammenfassung |
data.analysis.evaluation_criteria_results | object | Ergebnisse der Bewertungskriterien (falls konfiguriert) |
data.analysis.data_collection_results | object | Erfasste Daten (falls konfiguriert) |
data.conversation_initiation_client_data.dynamic_variables | object | Dynamische Variablen, die beim Anrufstart übergeben wurden |
voisa.forwarded_at | string | ISO-8601 Zeitstempel der Weiterleitung |
voisa.agent_name | string | Name des Agenten |
Hinweis: Audio-URLs, Kosten und interne Metadaten werden aus Datenschutzgründen nicht weitergeleitet.
Signaturprüfung
Jede Anfrage enthält einen X-Voisa-Signature Header zur Verifizierung:
X-Voisa-Signature: t=1709537300,v0=5a2f...c3e1
t– Unix-Timestamp der Signaturerstellungv0– HMAC-SHA256 Signatur
Signatur berechnen
Die Signatur wird über den String <timestamp>.<body> mit Ihrem Webhook Secret berechnet:
HMAC-SHA256(secret, "<timestamp>.<json-body>")
Beispiel (Node.js)
const crypto = require('crypto');
function verifyWebhook(req, secret) {
const signature = req.headers['x-voisa-signature'];
if (!signature) return false;
// Header parsen
const parts = {};
signature.split(',').forEach(part => {
const [key, value] = part.split('=');
parts[key] = value;
});
const timestamp = parts['t'];
const receivedHmac = parts['v0'];
// Eigene Signatur berechnen
const body = JSON.stringify(req.body); // oder raw body als String
const hmac = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${body}`)
.digest('hex');
// Vergleichen (timing-safe)
return crypto.timingSafeEqual(
Buffer.from(hmac, 'hex'),
Buffer.from(receivedHmac, 'hex')
);
}
Beispiel (Python)
import hmac
import hashlib
def verify_webhook(headers, body, secret):
signature = headers.get('X-Voisa-Signature', '')
if not signature:
return False
parts = dict(p.split('=', 1) for p in signature.split(','))
timestamp = parts.get('t', '')
received_hmac = parts.get('v0', '')
expected = hmac.new(
secret.encode(),
f"{timestamp}.{body}".encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, received_hmac)
Antwort
Ihr Endpoint sollte mit einem HTTP 200 Status antworten. Der Response-Body wird ignoriert.
Bei fehlgeschlagenen Anfragen (Timeout, 5xx) wird kein automatischer Retry durchgeführt.
FAQ
Kann ich den Webhook für mehrere Agenten nutzen?
Ja, jeder Agent kann seine eigene URL haben, oder Sie verwenden dieselbe URL und unterscheiden anhand der data.agent_id.
Welche Daten werden nicht weitergeleitet? Audio-Aufnahmen, Audio-URLs, Kostenaufstellungen und interne Metadaten werden aus Datenschutz- und Sicherheitsgründen entfernt.
Was passiert, wenn mein Endpoint nicht erreichbar ist? Der Webhook-Aufruf wird einmalig versucht. Es gibt keinen automatischen Retry. Wir empfehlen, eingehende Webhooks in eine Queue zu schreiben und asynchron zu verarbeiten.
Kann ich die URL nachträglich ändern? Ja, ändern Sie einfach die URL in den Agent-Einstellungen. Das Secret bleibt gleich.
Was passiert, wenn ich die URL entferne? Der Webhook wird vollständig deaktiviert und die zugehörige Konfiguration wird automatisch bereinigt.