API-Referenz v1
REST- + Webhooks-Integrationsreferenz (Version 2026-06-15)
Schnellstart für die CRM-Integration
Der schnellste Weg, ein CRM mit Heilo zu verbinden. Die vollständige API-Referenz finden Sie weiter unten.
Integrieren Sie webhook-first: Das Ereignis call.completed ist die primäre Datenquelle (es enthält den Aufzeichnungslink und das verarbeitete Transkript). REST /calls ist eine Ergänzung — Introspektion und Lesen ausgewählter Metadaten.
- Stellen Sie einen Webhook-Endpunkt in Ihrem CRM oder Ihrer Middleware bereit (ohne Code: verwenden Sie Zapier/Make — siehe die Anleitung unten).
- Fügen Sie in Heilo (Einstellungen → Integrationen) ein Abonnement für call.completed hinzu (optional auch call.outbound.attempted).
- Empfangen Sie call.completed und verifizieren Sie die Signatur (Heilo-Signature-Header, HMAC — siehe unten).
- Deduplizieren Sie nach event_id (heilo-event-id-Header); data.call_id gruppiert Ereignisse desselben Anrufs.
- Ordnen Sie die Felder Ihrem CRM zu: einen Kontakt anhand der Telefonnummer finden/erstellen, einen Lead/Deal erstellen und eine Aktivität/Notiz anhängen (Zusammenfassung + Aufzeichnungslink).
Kein Code? Die No-Code-Verbindungsanleitung (Zapier/Make) führt Sie Schritt für Schritt durch.
Authentifizierung
Die öffentliche API verwendet Bearer-Token. Generieren Sie einen API-Schlüssel über die Karte „API-Schlüssel“ auf der Integrationsseite und senden Sie ihn im Header:
Authorization: Bearer hk_live_AbC1MnPq...
Heilo hat drei Authentifizierungsmodi:
- Bearer (API-Schlüssel hk_live_…) — für die öffentliche API. Kein CSRF, keine Cookies.
- Session-Cookies — für die Web-App (heilo.io). NICHT für die öffentliche API verwenden.
- HMAC-SHA256 — für Webhooks, die Heilo an IHREN Endpunkt sendet (Sie verifizieren den Signatur-Header).
| Berechtigung (Scope) | Bedeutung |
|---|---|
| read.calls | Anrufe lesen: GET /api/v1/calls, GET /api/v1/calls/:id |
| write.calls, read.contacts, write.contacts, manage.webhooks, manage.api_keys | Reserviert für geplante API-Adressen — wählen Sie sie nicht auf Vorrat aus. |
Das Feld environment in der /me-Antwort hat heute immer den Wert live. Test-Schlüssel sind geplant.
Basis-URL
Alle öffentlichen Endpunkte liegen unter /api/v1/. Produktion:
https://www.heilo.io/api/v1
Endpunkte
Jeder /api/v1-Endpunkt erfordert Bearer. /me unten dient zur Schlüssel-Introspektion; das Lesen von Anrufen finden Sie im Abschnitt „Anrufe“. Behandeln Sie bei der Integration eines CRM Webhooks als primäre Datenquelle — REST dient zur Introspektion und zum Lesen ausgewählter Metadaten.
/api/v1/meAPI-Schlüssel-Introspektion — gibt die Key-ID, user_id, scopes und das Rate Limit zurück. Nützlich für den „Verbindungstest“ von Zapier/Make.
Anfrage
curl https://www.heilo.io/api/v1/me \ -H "Authorization: Bearer hk_live_AbC1MnPq..."
Antwort
{
"success": true,
"data": {
"api_key_id": "a1b2c3d4-5e6f-7081-92a3-b4c5d6e7f809",
"user_id": "5f4e3d2c-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
"organization_id": "7a8b9c0d-1e2f-4a3b-9c8d-7e6f5a4b3c2d",
"scopes": ["read.calls", "manage.webhooks"],
"rate_limit_per_hour": 1000,
"environment": "live"
},
"meta": { "timestamp": "2026-06-03T12:34:56Z" }
}Anwendungsfall: Zapier-Verbindungstest während der Einrichtung einer benutzerdefinierten Integration. Eine 200-Antwort beweist, dass Schlüssel + Netzwerk funktionieren.
Anrufe
Lese-Endpunkte für Anrufe. Erfordern den Scope read.calls.
/api/v1/callsListet die Anrufe der Organisation auf. Paginierung (page/limit≤100), Filter: direction, status, Datumsbereich (dateFrom/dateTo). Gibt has_more zurück.
Abfrageparameter
| Parameter | Typ | Werte |
|---|---|---|
| page | int | ab 1 (Standard 1) |
| limit | int | 1–100 (Standard 20) |
| direction | enum | inbound | outbound |
| status | enum | new | to_call | contacted | qualified |
| dateFrom / dateTo | string | Datum YYYY-MM-DD oder ISO 8601, z. B. 2026-06-03T12:34:56Z |
Anfrage
curl "https://www.heilo.io/api/v1/calls?limit=20&direction=inbound" \ -H "Authorization: Bearer hk_live_AbC1MnPq..."
Antwort
{
"success": true,
"data": {
"items": [
{
"call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"direction": "inbound",
"caller_phone": "+48600100200",
"customer_phone_e164": "+48600100200",
"caller_name": "Jan Kowalski",
"duration": 87,
"crm_status": "new",
"review_status": null,
"outbound_lifecycle": null,
"transcript_processed": { "caller_name": "Jan Kowalski", "summary": "...", "service_needed": "..." },
"created_at": "2026-06-03T12:34:56Z"
}
],
"has_more": false,
"page": 1,
"limit": 20
},
"meta": { "timestamp": "2026-06-03T12:34:56Z" }
}/api/v1/calls/:idRuft einen einzelnen Anruf anhand der id ab. 404, wenn er nicht zur Organisation des Schlüssels gehört oder gelöscht wurde.
Anfrage
curl https://www.heilo.io/api/v1/calls/<id> \ -H "Authorization: Bearer hk_live_AbC1MnPq..."
Aufzeichnungsdateien werden NICHT über die API bereitgestellt — sie werden gemäß der gesetzlichen Aufbewahrung (DSGVO) gelöscht. Die API gibt Anruf-Metadaten und Transkripttext zurück.
Rate Limits
Stündliche Limits pro Schlüssel und pro Benutzer (Summe aller Schlüssel). Zurücksetzung zur vollen UTC-Stunde. Jede Anfrage zählt, unabhängig vom Antwortstatus.
Pro Schlüssel
1000 req/h
Pro Konto (Summe der Schlüssel)
5000 req/h
Bei Überschreitung geben wir 429 mit dem Retry-After-Header zurück (Sekunden bis zum Zurücksetzen):
HTTP/1.1 429 Too Many Requests Retry-After: 1842 X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 2026-06-03T13:00:00Z
Fehler
Alle Fehler geben eine einheitliche JSON-Struktur mit error.code (stabil) und error.message (menschenlesbar, kann sich ändern) zurück. Protokollieren Sie den Code, nicht die Nachricht.
{
"success": false,
"error": { "code": "RATE_LIMITED", "message": "Per-key rate limit 1000/h exceeded" },
"meta": { "timestamp": "2026-06-03T12:34:56Z" }
}| HTTP | code | Bedeutung |
|---|---|---|
| 400 | BAD_REQUEST | Fehlerhafte Query- oder Body-Parameter (generische Validierung) |
| 401 | UNAUTHORIZED | Fehlender / ungültiger Bearer-Token |
| 402 | SUBSCRIPTION_INACTIVE | Abonnement inaktiv — erneuern Sie die Abrechnung, um den Schlüssel wieder zu aktivieren |
| 403 | FORBIDDEN | Der Schlüssel verfügt nicht über den erforderlichen Scope |
| 404 | NOT_FOUND | Ressource nicht gefunden (oder gehört zu einem anderen Benutzer) |
| 422 | VALIDATION_ERROR | Eine Geschäftsregel hat die Anfrage abgelehnt (z. B. ungültige Telefonnummer, Kontingent) |
| 429 | RATE_LIMITED | Stundenlimit überschritten (siehe Retry-After) |
| 500 | DATABASE_ERROR | Server-/Datenbankfehler — kann mit Backoff gefahrlos wiederholt werden |
| 503 | MAINTENANCE | Öffentliche API vorübergehend deaktiviert (Kill-Switch) |
Der Code SUBSCRIPTION_INACTIVE tritt in zwei Situationen auf: HTTP 402 — das Heilo-Abonnement ist abgelaufen (Zahlung), und HTTP 409 — das Webhook-Abonnement ist pausiert (z. B. bei der Test-Aktion); klicken Sie dann zuerst auf „Erneut verifizieren“.
Ausgehende Webhooks
Heilo sendet nach jedem Ereignis ein POST mit JSON an Ihren Endpunkt. Abonnements werden über die Karte „Webhook-Abonnements“ erstellt — bei der Aktivierung ist ein Handshake erforderlich. Jede Anfrage enthält eine HMAC-Signatur, die Sie verifizieren müssen:
POST <your URL>
content-type: application/json
heilo-signature: t=1717423396,v1=4f3a...
heilo-event-id: 1bf3a5e2-...
heilo-event-type: call.completed
{
"api_version": "2026-06-15",
"event_id": "1bf3a5e2-...",
"event_type": "call.completed",
"resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"created_at": "2026-06-03T12:34:56Z",
"data": { /* see the setup guide for the full schema */ }
}Wiederholungs- und Pausierungsrichtlinie:
- Vorübergehende Fehler (HTTP 408/429/5xx, Netzwerk) werden mit exponentiellem Backoff wiederholt (2 Min, 5 Min, 30 Min, 2 Std) — danach Dead-Letter nach 5 Versuchen.
- Permanente Fehler (HTTP 401/403/422) pausieren das Abonnement sofort — keine Wiederholungen.
- 50 aufeinanderfolgende vorübergehende Fehler oder 2 aufeinanderfolgende HTTP 410 Gone (z. B. gelöschtes Make-Szenario) pausieren das Abonnement ebenfalls.
- Setzen Sie ein pausiertes Abonnement mit „Erneut verifizieren“ fort — ein neuer Handshake reaktiviert die Warteschlange.
Wird ein Abonnement automatisch pausiert, senden wir eine E-Mail an die Adresse des Kontoinhabers. Ereignisse aus der Dead-Letter-Warteschlange können Sie mit der Schaltfläche „Erneut senden“ im Zustellungsprotokoll erneut senden — nachdem das Abonnement erneut verifiziert wurde.
Verifizierungsmodi
Heilo unterstützt zwei Aktivierungsmodelle für Webhook-Abonnements. Der Standard (permissiv) passt zu Zapier / Make / typischen CRM-Endpunkten. Strikt entspricht dem Modell der Slack Events API — nützlich für eigene Server, die die Challenge synchron zurückgeben können.
Modus permissive (Standard)
Heilo sendet ein POST von webhook.subscription.verify an Ihre URL. Jede 2xx-Antwort aktiviert das Abonnement. Der Antworttext wird ignoriert. Dies entspricht dem Modell von Stripe / GitHub / Twilio.
Modus strict (Opt-in)
Heilo sendet ein POST von webhook.subscription.verify mit einem challenge-Feld. Ihr Endpunkt MUSS mit 2xx und einem JSON-Body antworten:
{"challenge":"<echo of the challenge field from Heilo's POST>"}Sie wählen den Modus beim Erstellen des Abonnements (verification_mode in POST /api/v1/webhook-subscriptions, Standard permissiv). Eine Änderung des Modus nach der Erstellung erfordert Löschen + Neuerstellen — beabsichtigt, da sich dadurch die Vertragssemantik ändert.
Limits: max. 20 aktive Abonnements pro Konto (per Umgebungsvariable überschreibbar). Ein Abonnement wird nach 50 aufeinanderfolgenden vorübergehenden Fehlern oder 2 aufeinanderfolgenden HTTP 410 automatisch pausiert und sofort bei HTTP 401/403/422.
HMAC-Verifizierung (signing_secret)
Stripe-kompatibles Format. signed_string = "<unix_ts>.<raw_body>" (durch Punkt getrennt). Verifizieren Sie immer den ROHEN Anfragetext (vor dem JSON-Parsing) — jede Normalisierung verändert die Signatur.
signed_string = "<unix_timestamp>.<raw_request_body>" signature = HMAC-SHA256(signing_secret, signed_string).hex() header = "t=<unix_timestamp>,v1=<signature>"
import { createHmac, timingSafeEqual } from 'crypto';
// rawBody MUST be the exact received bytes — do NOT re-serialize the JSON.
function verifyHeiloSignature(rawBody, header, signingSecret, toleranceSec = 300) {
if (!header) return false;
const parts = Object.fromEntries(
header.split(',').map((p) => p.split('=').map((s) => s.trim()))
);
const t = Number(parts.t);
const sig = parts.v1;
if (!Number.isFinite(t) || !sig) return false;
// Asymmetric tolerance: reject old replays; allow only small clock skew ahead.
const now = Math.floor(Date.now() / 1000);
if (now - t > toleranceSec || t - now > 60) return false;
const expected = createHmac('sha256', signingSecret)
.update(`${t}.${rawBody}`)
.digest('hex');
const a = Buffer.from(expected, 'utf8');
const b = Buffer.from(sig, 'utf8');
// timingSafeEqual THROWS on length mismatch — length-check first.
return a.length === b.length && timingSafeEqual(a, b);
}Eine Standardtoleranz von 300 s (5 Min) verhindert Replay-Angriffe. Server-Uhren müssen NTP-synchronisiert sein.
Das Signatur-Secret zeigen wir nur einmal an — beim Erstellen des Abonnements. Wenn Sie es verlieren oder ein Leck vermuten: Löschen Sie das Abonnement und erstellen Sie es mit derselben URL neu (die Adresse in Zapier/Make ändert sich nicht). Eine Rotation des Secrets ohne Löschen ist geplant.
Ereignistypen
Wählen Sie event_types beim Erstellen eines Abonnements. Jedes Ereignis hat eine eindeutige event_id (UUID v5) und wird pro Abonnement dedupliziert.
Das erste Ereignis, das Sie erhalten, ist webhook.test — eine Testnachricht mit data._test = true. Nutzen Sie sie zum Zuordnen der Felder oder filtern Sie sie heraus.
| event_type | Beschreibung |
|---|---|
| call.completed | Anruf abgeschlossen, Transkript bereit |
| call.outbound.attempted | Ausgehender Wählversuch (vor der Verbindung) |
| call.recording.ready | Aufzeichnungsdatei zum Download verfügbar |
| call.transcribed | Transkript bereit (getrennt von call.completed) |
| call.failed | Anruf fehlgeschlagen (besetzt/keine Antwort/Fehler) |
| call.outbound.lifecycle_repaired | Korrektur des ausgehenden Lebenszyklus — Anrufstatus repariert |
| call.deletion_scheduled | Anruf zur Löschung vorgemerkt (DSGVO Art. 17, Aufbewahrung) |
| call.recording.deleted | Aufzeichnung gelöscht (DSGVO) |
| contact.created | Neuer Kontakt erstellt |
| contact.updated | Kontakt aktualisiert |
Unten das data-Objekt jedes Ereignisses. Feldnamen, Typen und Aufzählungswerte sind Teil des API-Vertrags und ändern ihre Bedeutung innerhalb von v1 nicht; mit der Zeit können neue, optionale Felder hinzukommen.
call.completed
Wird gesendet, nachdem die Aufzeichnung und das Transkript eines abgeschlossenen Anrufs verarbeitet wurden. Die primäre Datenquelle für ein CRM — vollständige Nutzdaten (einschließlich recording_url und des verarbeiteten Transkripts).
{
"api_version": "2026-06-15",
"event_id": "1bf3a5e2-...", // same value as heilo-event-id header
"event_type": "call.completed",
"resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"created_at": "2026-06-03T12:34:56Z",
"data": {
"call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"direction": "inbound",
"caller_phone": "+48600100200",
"customer_phone_e164": "+48600100200",
"duration": 87,
"recording_url": "https://www.heilo.io/api/v1/calls/.../recording.mp3?token=...&exp=...",
"transcript_processed": { "caller_name": "Jan Kowalski", "summary": "...", "service_needed": "..." },
"transcript_original": "..."
}
}| Feld | Typ | Beschreibung |
|---|---|---|
| call_id | string (uuid) | Anruf-ID in Heilo — derselbe Wert wie resource_id; verknüpft alle Ereignisse eines Anrufs. |
| direction | 'inbound' | 'outbound' | Anrufrichtung. |
| caller_phone | string | Telefonnummer der Gegenseite, wie am Anruf gespeichert. |
| customer_phone_e164 | string | Dieselbe Nummer noch einmal — ein Alias zur einfacheren Feldzuordnung. |
| duration | number | Länge der Aufzeichnung in Sekunden. |
| recording_url | string | null | Stabiler Link zur Aufzeichnung; null, wenn die Aufzeichnung zum Verarbeitungszeitpunkt noch nicht gespeichert war. |
| transcript_processed | object | Verarbeitete Anrufanalyse — siehe die transcript_processed-Feldübersicht in diesem Abschnitt. |
| transcript_original | string | null | Rohes, wörtliches Transkript; null, wenn nicht verfügbar. |
Die Zustellung erfolgt mindestens einmal und ohne Reihenfolgegarantie — speichern Sie idempotent. Dedup-Schlüssel: event_id. data.call_id verknüpft Ereignisse desselben Anrufs (z. B. call.completed nach call.recording.ready).
transcript_processed — Feldübersicht
Der stabile Teil der Felder, auf den Sie sich beim Mapping in ein CRM verlassen können. Jedes Feld ist optional — es ist null, wenn das Gespräch diese Information nicht enthielt.
| Feld | Typ | Beschreibung |
|---|---|---|
| caller_name | string | null | Name des Anrufers, sofern genannt. |
| summary | string | null | Kurze Zusammenfassung des Anrufs. |
| subject | string | null | Einzeiliger Titel des Anrufs (bis 80 Zeichen). |
| service_needed | string | null | Worum der Anrufer gebeten hat. |
| services_match | boolean | null | Ob die Anfrage zu den von Ihnen angebotenen Leistungen passt. |
| lead_score | number | null (1–10) | Einschätzung der Lead-Qualität von 1 bis 10. |
| preferred_date | string | null | Vom Anrufer genannter Termin, sofern vorhanden. |
| client_city | string | null | Stadt, sofern erwähnt. |
| client_address | string | null | Adresse, sofern erwähnt. |
| additional_details | string | null | Zusätzlicher Kontext aus dem Anruf. |
Felder, die auftreten können
| Feld | Typ | Beschreibung |
|---|---|---|
| caller_location | string | null | Im Gespräch erkannter geografischer Bezug. |
| client_country | string | null | Land, sofern erwähnt. |
| counterparty_name | string | null | Name der Gegenseite — nur ausgehende Anrufe und Gesprächsmodus. |
| detected_language | string | Sprachcode des Gesprächs (z. B. pl); der Schlüssel kann ganz fehlen. |
| proposal_items | object[] | null | Aus dem Anruf abgeleitete Vorschläge für Folgeaufgaben und Entscheidungen. |
Die Analyse kann zusätzliche Felder enthalten — behandeln Sie unbekannte Felder als optional und setzen Sie ihr Vorhandensein nie voraus.
call.outbound.attempted
Wird gesendet, wenn ein ausgehender Wählversuch einen Endzustand erreicht — auch bei Fehlschlägen. completed bedeutet, dass der Anruf zustande kam und normal endete; Aufzeichnung und Transkript folgen als separate Ereignisse.
| Feld | Typ | Beschreibung |
|---|---|---|
| call_id | string (uuid) | Anruf-ID in Heilo — derselbe Wert wie resource_id; verknüpft alle Ereignisse eines Anrufs. |
| agent_user_id | string (uuid) | ID des Heilo-Nutzers, der den Anruf gestartet hat. |
| customer_phone | string | Die gewählte Kundennummer. |
| customer_phone_e164 | string | Dieselbe Nummer noch einmal — ein Alias zur einfacheren Feldzuordnung. |
| outbound_lifecycle | 'completed' | 'agent_no_answer' | 'customer_no_answer' | 'failed_to_initiate' | Endzustand, der das Ereignis ausgelöst hat; completed bedeutet, dass der Anruf zustande kam und normal endete. |
| duration | number | null | Gesprächsdauer in Sekunden; null, wenn der Anruf beim Aufbau scheiterte oder die Dauer noch nicht bekannt ist. |
| attempted_at | string (ISO 8601) | Zeitpunkt der Ereignis-Erzeugung (ISO 8601). |
| has_recording | boolean | true nur, wenn outbound_lifecycle completed ist — die Aufzeichnung folgt dann als call.recording.ready. |
call.recording.ready
Wird gesendet, wenn die Aufzeichnungsdatei verfügbar ist. Verwenden Sie es, um die Audiodatei abzurufen oder zu archivieren.
| Feld | Typ | Beschreibung |
|---|---|---|
| call_id | string (uuid) | Anruf-ID in Heilo — derselbe Wert wie resource_id; verknüpft alle Ereignisse eines Anrufs. |
| recording_url | string | null | Stabiler Link zur Aufzeichnung; in seltenen Fällen null, wenn der Link nicht erzeugt werden konnte. |
| duration | number | null | Dauer in Sekunden; null, wenn noch nicht bekannt. |
call.transcribed
Wird im selben Verarbeitungslauf wie call.completed gesendet — enthält nur das Transkript, ohne Anrufdaten und ohne Aufzeichnungslink.
| Feld | Typ | Beschreibung |
|---|---|---|
| call_id | string (uuid) | Anruf-ID in Heilo — derselbe Wert wie resource_id; verknüpft alle Ereignisse eines Anrufs. |
| transcript_original | string | null | Rohes, wörtliches Transkript; null, wenn nicht verfügbar. |
| transcript_processed | object | Verarbeitete Anrufanalyse — siehe die transcript_processed-Feldübersicht in diesem Abschnitt. |
call.failed
Wird gesendet, wenn ein ausgehender Anruf nicht zustande kam (keine Antwort, besetzt, Fehler beim Aufbau). Betrifft nur ausgehende Anrufe. Meist lohnt sich kein neuer Lead — protokollieren Sie stattdessen einen Kontaktversuch.
| Feld | Typ | Beschreibung |
|---|---|---|
| call_id | string (uuid) | Anruf-ID in Heilo — derselbe Wert wie resource_id; verknüpft alle Ereignisse eines Anrufs. |
| outbound_lifecycle | 'agent_no_answer' | 'customer_no_answer' | 'failed_to_initiate' | Welche Phase des ausgehenden Anrufs fehlgeschlagen ist. |
| failure_reason | string | null | Maschinenlesbarer Fehlercode (z. B. customer_busy, agent_no_confirmation); kann null sein. |
call.outbound.lifecycle_repaired
Wird gesendet, wenn Heilo den Zustand eines ausgehenden Anrufs nachträglich korrigiert (eine späte Rückmeldung des Anbieters hat bestätigt, dass der Anruf doch zustande kam). Aktualisieren Sie den Anrufzustand auf Ihrer Seite.
| Feld | Typ | Beschreibung |
|---|---|---|
| call_id | string (uuid) | Anruf-ID in Heilo — derselbe Wert wie resource_id; verknüpft alle Ereignisse eines Anrufs. |
| previous_lifecycle | 'agent_only' | Zustand vor der Korrektur; derzeit immer agent_only. |
| new_lifecycle | 'completed' | Zustand nach der Korrektur; derzeit immer completed. |
| repaired_at | string (ISO 8601) | Zeitpunkt der Korrektur (ISO 8601). |
call.deletion_scheduled
DSGVO Art. 17: Der Anruf ist zur Löschung vorgemerkt. Ihr CRM sollte die Aufzeichnung nicht mehr verwenden und sich auf die Löschung der Daten vorbereiten.
| Feld | Typ | Beschreibung |
|---|---|---|
| call_id | string (uuid) | Anruf-ID in Heilo — derselbe Wert wie resource_id; verknüpft alle Ereignisse eines Anrufs. |
| pending_deletion_at | string (ISO 8601) | Wann die Daten endgültig gelöscht werden (ISO 8601). |
| reason | 'consent_not_asked' | 'consent_withdrawn' | 'retention_expired' | 'user_erasure' | Grund für die geplante Löschung. |
call.recording.deleted
DSGVO: Die Aufzeichnung wurde gelöscht — recording_url gibt 410 zurück. Entfernen oder deaktivieren Sie den Aufzeichnungslink auf Ihrer Seite.
| Feld | Typ | Beschreibung |
|---|---|---|
| call_id | string (uuid) | Anruf-ID in Heilo — derselbe Wert wie resource_id; verknüpft alle Ereignisse eines Anrufs. |
| reason | string | null | Beim Planen der Löschung erfasster Grund; kann null sein. |
| recording_sid | string | null | Twilio-Aufzeichnungs-ID; null, wenn sie nicht ermittelt werden konnte. |
| deletion_kind | 'hard_deleted' | 'twilio_404' | hard_deleted = von Heilo gelöscht; twilio_404 = die Datei war auf Twilio-Seite bereits verschwunden. |
| deleted_at | string (ISO 8601) | Zeitpunkt der Löschung der Aufzeichnung (ISO 8601). |
contact.created
Wird gesendet, wenn in Heilo ein neuer Kontakt angelegt wird. data.contact ist eine vollständige Momentaufnahme des neuen Kontakts; Notizen und Tags sind nicht enthalten.
| Feld | Typ | Beschreibung |
|---|---|---|
| contact | object | Vollständige Momentaufnahme des neuen Kontakts (Felder unten). |
| contact.id | string (uuid) | Kontakt-ID in Heilo. |
| contact.phone | string | Telefonnummer des Kontakts. |
| contact.first_name | string | null | null, wenn nicht angegeben. |
| contact.last_name | string | null | null, wenn nicht angegeben. |
| contact.email | string | null | null, wenn nicht angegeben. |
| contact.company | string | null | null, wenn nicht angegeben. |
contact.updated
Wird gesendet, wenn ein Kontakt bearbeitet wird. Anders als bei contact.created ist dies keine Momentaufnahme: data.diff enthält nur die geänderten Felder.
| Feld | Typ | Beschreibung |
|---|---|---|
| contact_id | string (uuid) | ID des aktualisierten Kontakts. |
| diff | object (partial) | Nur die geänderten Felder — Schlüssel, die in diff fehlen, wurden nicht geändert. |
Mögliche Schlüssel in diff: first_name, last_name, email, phone, company, notes, tags
webhook.test
Die erste Nachricht nach dem Anlegen eines Abonnements und bei jedem manuellen Test. resource_id ist die Abonnement-ID (keine Anruf-ID); die übrigen data-Felder spiegeln das call.completed-Beispiel mit Beispielwerten.
| Feld | Typ | Beschreibung |
|---|---|---|
| _test | true | Immer true — unterscheidet die Testnachricht von echten Ereignissen. |
| _message | string | Lesbarer Hinweis, dass es sich um einen Test handelt. |
| _sent_at | string (ISO 8601) | Zeitpunkt des Testversands (ISO 8601). |
Versionierung & Roadmap
Versionierung
Die Heilo-API verwendet eine datumsbasierte Version. Nur Breaking Changes erhöhen die Hauptversion (v1 → v2). Das Hinzufügen von Feldern oder Endpunkten ist nicht breaking.
Aktuelle Version
v1 · 2026-06-15
Das Datum ist die API-Versionskennung (datumsbasiert), nicht das heutige Datum.
Status
Beta
Abwärtskompatibel: neue Antwortfelder, neue event_types, neue Endpunkte. Breaking Change = neue Hauptversion (v2). Die alte Version wird mind. 12 Monate nach Ankündigung von v2 unterstützt.
Roadmap (v1.1+)
Endpunkte, die für kommende v1.X-Releases geplant sind. Keine feste Zusage — die Richtung hängt vom Feedback ab.
- GET /contacts — Kontakte auflisten
- POST /contacts — Kontakt erstellen (Synchronisierung vom CRM nach Heilo)
Brauchen Sie einen Endpunkt? Schreiben Sie mit Ihrem Anwendungsfall an support@heilo.io — wir priorisieren die Roadmap nach tatsächlichem Bedarf.
Schlüssel und Webhooks im Panel verwalten
Nach der Anmeldung generieren Sie API-Schlüssel, fügen Webhook-Abonnements hinzu und sehen das Zustellungsprotokoll ein.