Skip to main content

API-Referenz v1

REST- + Webhooks-Integrationsreferenz (Version 2026-06-15)

v1 · 2026-06-15Beta

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.

  1. Stellen Sie einen Webhook-Endpunkt in Ihrem CRM oder Ihrer Middleware bereit (ohne Code: verwenden Sie Zapier/Make — siehe die Anleitung unten).
  2. Fügen Sie in Heilo (Einstellungen → Integrationen) ein Abonnement für call.completed hinzu (optional auch call.outbound.attempted).
  3. Empfangen Sie call.completed und verifizieren Sie die Signatur (Heilo-Signature-Header, HMAC — siehe unten).
  4. Deduplizieren Sie nach event_id (heilo-event-id-Header); data.call_id gruppiert Ereignisse desselben Anrufs.
  5. 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.callsAnrufe lesen: GET /api/v1/calls, GET /api/v1/calls/:id
read.recordingsErstellt über `GET /calls/{id}/recording-url` en Link zum Audio vom ene Aaruef. Getrennt vo `read.calls`, wil Audio en anderi Iwilligung isch als Metadate — en bestehende Schlüssel überchunnt en nöd, du machsch en neue mit usdrücklichem Ufnahmszuegriff.
write.calls, read.contacts, write.contacts, manage.webhooks, manage.api_keysReserviert 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 und Version

Alle öffentlichen Endpunkte liegen unter /api/v1/. Produktion:

https://www.heilo.io/api/v1

Aktuelle Version

v1 · 2026-06-15

Das Datum ist die API-Versionskennung (datumsbasiert), nicht das heutige Datum.

Status

Beta

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.

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.

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" }
}
HTTPcodeBedeutung
400BAD_REQUESTFehlerhafte Query- oder Body-Parameter (generische Validierung)
401UNAUTHORIZEDFehlender / ungültiger Bearer-Token
402SUBSCRIPTION_INACTIVEAbonnement inaktiv — erneuern Sie die Abrechnung, um den Schlüssel wieder zu aktivieren
403FORBIDDENDer Schlüssel verfügt nicht über den erforderlichen Scope
404NOT_FOUNDDie Ressource existiert nicht oder liegt ausserhalb der Organisation des API-Schlüssels.
422VALIDATION_ERROREine Geschäftsregel hat die Anfrage abgelehnt (z. B. ungültige Telefonnummer, Kontingent)
429RATE_LIMITEDStundenlimit überschritten (siehe Retry-After)
500DATABASE_ERRORServer-/Datenbankfehler — kann mit Backoff gefahrlos wiederholt werden
503MAINTENANCEÖ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“.

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-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.

Anwendungsfall: Zapier-Verbindungstest während der Einrichtung einer benutzerdefinierten Integration. Eine 200-Antwort beweist, dass Schlüssel + Netzwerk funktionieren.

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" }
}

Lese-Endpunkte für Anrufe. Erfordern den Scope read.calls.

Listet die Anrufe der Organisation auf. Paginierung (page/limit≤100), Filter: direction, status, Datumsbereich (dateFrom/dateTo). Gibt has_more zurück.

Abfrageparameter

ParameterTypWerte
pageintab 1 (Standard 1)
limitint1–100 (Standard 20)
directionenuminbound | outbound
statusenumnew | to_call | contacted | qualified
dateFrom / dateTostringDatum YYYY-MM-DD oder ISO 8601, z. B. 2026-06-03T12:34:56Z
phonestringd Chundenummere vom Gspröch; Läärschläg, Bindestrich und s füehrende + sind optional, z. B. 600 100 200
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",
        "customer_phone_national": "600 100 200",
        "company_phone_e164": "+48222630000",
        "app_url": "https://www.heilo.io/calls/3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "caller_name": "Jan Kowalski",
        "duration": 87,
        "crm_status": "new",
        "review_status": null,
        "outbound_lifecycle": null,
        "transcript_processed": { "caller_name": "Jan Kowalski", "summary": "...", "service_needed": "...", "followup_email": null },
        "created_at": "2026-06-03T12:34:56Z"
      }
    ],
    "has_more": false,
    "page": 1,
    "limit": 20
  },
  "meta": { "timestamp": "2026-06-03T12:34:56Z" }
}

Ruft 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..."

Es frisch signierts Link zum Audio vom Aaruef, 15 Minute gültig. Es isch e Download-Bereichtigung mit eme Ablauf, kei dauerhafti Referenz: speicher d `call_id` und frag nomal, wil en Link, wo im CRM-Fäld liit, i weniger als ere Stund tot isch. De Link im Webhook `call.recording.ready` isch sibe Täg signiert — über dää Endpunkt chunnsch du nachher as Audio.

  • 200 — de Link und de Moment, wo er ufhört z funktioniere.
  • 409 `RECORDING_NOT_READY` — de Aaruef ghört dir und s Audio isch no nöd da. Frag glii nomal.
  • 409 `RECORDING_WITHHELD` — de Aaruef isch im Abfall oder zum Lösche vorgmerkt. Beides cha rückgängig gmacht werde, also frag wiiter, statt d Ufnahm bi dir abzschriibe.
  • 410 `RECORDING_DELETED` — de Ufbewahrigslauf hät s Audio entfernt, es isch nöd meh z rette. Hör uf z frage und uf z queue.
  • 410 `RECORDING_NOT_CAPTURED` — dä usgehend Aaruef isch nie ufgno worde und es wird nie e Ufnahm dafür gäh: s Capture-Gate hät en bim Start abglehnt, er isch im Modus no_recording gloffe oder hät ohni Gspröch ufghört. Hör uf z frage — es gits kei Grund zum nomal probiere. En iigehende Aaruef, wo d Ufnahm abglehnt worde isch, git wiiterhin 409, will no e Ufnahm cho cha.

D Antwort chunnt mit `Cache-Control: no-store`, wil de Body e Bereichtigung treit. D Bereichtigung wird bim Abhole vo de Datei nomal prüeft, nöd nu bim Erstelle vom Link — en zwüschedure glöschte Aaruef isch sofort nüme läsbar.

Anfrage
curl https://www.heilo.io/api/v1/calls/<id>/recording-url \
  -H "Authorization: Bearer hk_live_AbC1MnPq..."
Antwort
{
  "success": true,
  "data": {
    "url": "https://www.heilo.io/api/v1/calls/<id>/recording.mp3?token=...&exp=...",
    "expires_at": "2026-09-15T12:15:00.000Z"
  }
}

D Endpunkt für d Aaruef-Liste und s Aaruef-Detail gänd kei Ufnahmsdatei zrugg. De Link zur Ufnahm überchunnsch im Webhook und nach sim Ablauf über `GET /calls/{id}/recording-url`. Ufnahme chönd nach Ufbewahrigs- und DSGVO-Regle glöscht werde.

Was REST liefert und was nur ein Webhook liefert

Die beiden Kanäle tragen nicht dasselbe, und der Unterschied entscheidet die Wahl. REST ist dauerhaft: Ein Gespräch lesen Sie daraus jederzeit. Ein Webhook ist reichhaltiger, kommt aber einmal, und ein Teil seines Inhalts verfällt.

DatenRESTWebhook
Gesprächsmetadaten: Richtung, Nummern, Dauer, Datumjaja
CRM-Status und Prüfstatusjanein
Zusammenfassung, Anrufername, Kundenbedarfjaja
Der Rest der Analyse: Stadt, Adresse, Lead-Score, Wunschtermin, Spracheneinja
Das wortwörtliche Transkriptneinja
Aufnahme-Linkja, über /calls/{id}/recording-urlja, 7 Tage gültig

Drum d praktischi Regle: d ganzi Analyse usem Webhook neh, wenn er achunnt, wil REST si nie treit het. D Ufzeichnig isch s einzige, wo me jetzt nochträglich hole cha — frog /calls/{id}/recording-url um en frische Link für 15 Minute, statt de sibetägig us em Payload z spichere.

Spezifikation und en echti Aafrog

Die glyche drü Operatione, für Maschine gschribe: OpenAPI 3.1. In Postman oder Insomnia importiere oder en Client i dyner Sprach generiere.

OpenAPI 3.1 abelade

Spezifikation und en echti Aafrog

Schick vo do us ei Aafrog und prüef dyn Schlüssel, bevor du Code schrybsch.

Das rüeft di echti API mit dym echte Schlüssel uf und git dyni eigene Date zrugg. De Schlüssel bliibt i dem Browser-Tab — mir speichered en nie.

Ausgehende Webhooks

Heilo sendet signierte JSON-Ereignisse an Ihren Endpunkt. Erstellen Sie Abonnements in der Karte Webhook-Abonnements. Die Aktivierung verwendet einen separaten, unsignierten Handshake webhook.subscription.verify, der keine Geschäftsdaten anlegen darf.

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:

  • Bei vorübergehenden Fehlern gibt es insgesamt höchstens 5 Versuche: nach 2 Min., 5 Min., 30 Min. und 2 Std., mit zufälliger Zeitverschiebung (Jitter) bei späteren Versuchen. Nach dem fünften Fehler endet die Zustellung als Dead Letter.
  • 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.

2xx bestätigt den HTTP-Empfang, nicht den Abschluss einer Automatisierung oder das Speichern im CRM. Zustellungen können sich wiederholen oder in anderer Reihenfolge eintreffen. Heilo gleicht aktuelle Lücken in einem begrenzten Zeitfenster aus, nicht die gesamte Historie. Prüfen Sie Zustellprotokoll und CRM getrennt.

Verifizierungsmodi

Der unsignierte Handshake enthält nur event_type = webhook.subscription.verify und challenge. Bestätigen Sie nur den Endpunkt; starten Sie keine Geschäftsverarbeitung. Beide Modi verwenden dieselbe Anfrage:

{
  "event_type": "webhook.subscription.verify",
  "challenge": "example-verification-token"
}

Modus permissive (Standard)

Jede 2xx-Antwort aktiviert das Abonnement; der Antwortinhalt wird ignoriert. Dies ist der Standardmodus für No-Code-Empfänger.

Modus strict (Opt-in)

Antworten Sie mit 2xx und JSON mit exakt dem von Heilo empfangenen challenge-Wert:

{"challenge":"<echo of the challenge field from Heilo's POST>"}

Wählen Sie den Modus beim Erstellen. Eine Änderung erfordert Löschen und Neuerstellen des Abonnements. Verwaltungsrouten erfordern eine angemeldete Sitzung und CSRF-Schutz; sie sind nicht mit einem API-Schlüssel zugänglich.

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)

Signierte Ereignisse einschliesslich des manuellen webhook.test verwenden Heilo-Signature mit HMAC-SHA256 über Zeitstempel + Punkt + ursprüngliche Anfragebytes. Prüfen Sie die Signatur vor dem Parsen der Geschäftsdaten. Nur der Handshake zur Endpunktbestätigung ist unsigniert.

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 'node:crypto';

// Pass the exact received Buffer (e.g. Express raw parser), never JSON.stringify(req.body).
// signingSecrets: every secret you currently trust, tried in constant time each.
// During a secret rotation pass [newSecret, oldSecret]; remove the old one once
// Heilo's grace window ends. Heilo itself always sends exactly ONE v1 signature —
// this list is what lets your receiver accept it under either secret while both
// are live, never a second signature to parse.
function verifyHeiloSignature(rawBody, header, signingSecrets) {
  const match = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header || '');
  if (!match) return false;
  const timestamp = Number(match[1]);
  const now = Math.floor(Date.now() / 1000);
  // Receiver policy: at most 10 minutes old or 5 minutes ahead (clock skew).
  if (!Number.isSafeInteger(timestamp) || now - timestamp > 600 || timestamp - now > 300) return false;
  // One string is accepted too. Empty entries are dropped: an HMAC key of ''
  // is valid, so a blanked env var (OLD_SECRET=) would let anyone sign events.
  const secrets = [].concat(signingSecrets).filter((s) => typeof s === 'string' && s.length > 0);
  if (secrets.length === 0) return false;
  const actual = Buffer.from(match[2], 'hex');
  return secrets.some((signingSecret) => {
    const expected = createHmac('sha256', signingSecret)
      .update(match[1] + '.')
      .update(rawBody)
      .digest();
    return actual.length === expected.length && timingSafeEqual(actual, expected);
  });
}

function receiveHeiloWebhook(rawBody, signatureHeader, signingSecrets) {
  if (!signatureHeader) {
    // The ONLY unsigned exception confirms the endpoint; never enqueue it for CRM writes.
    const probe = JSON.parse(rawBody.toString('utf8'));
    if (probe && typeof probe === 'object' && !Array.isArray(probe)
      && Object.keys(probe).length === 2
      && probe.event_type === 'webhook.subscription.verify'
      && typeof probe.challenge === 'string') {
      return { kind: 'verification', response: { challenge: probe.challenge } };
    }
    throw new Error('Missing Heilo-Signature');
  }
  if (!verifyHeiloSignature(rawBody, signatureHeader, signingSecrets)) throw new Error('Invalid Heilo-Signature');
  return { kind: 'event', event: JSON.parse(rawBody.toString('utf8')) };
}

// HTTP adapter: limit body size; map verification to 200 JSON response.
// Signature errors -> 401 (pauses delivery; fix the secret, then Reverify). JSON errors -> 400.
// For kind=event: validate the envelope and chosen event_type, ignore webhook.test
// in business flows, then durably deduplicate/enqueue by event_id BEFORE returning 2xx.
// Enqueue failure: return 503. An HTTP acknowledgement is not proof of a CRM write.

Die Beispiele akzeptieren Signaturen bis zu 600 Sekunden (10 Minuten) alt und 300 Sekunden (5 Minuten) in der Zukunft, entsprechend dem bestehenden Heilo-Prüfer. Synchronisieren Sie Serveruhren. Zeitprüfungen begrenzen das Replay-Fenster; Deduplizierung nach event_id bleibt erforderlich.

Das Signatur-Secret zeigen wir nur einmal an — beim Erstellen des Abonnements. Haben Sie es verloren oder vermuten Sie ein Leck? Öffnen Sie das Abonnement unter Einstellungen → Integrationen → Webhooks und rotieren Sie es dort — siehe „Rotation des Secrets“ unten. Das Abonnement muss dafür nicht gelöscht und neu erstellt werden.

Rotation des Secrets

Heilo sendet immer genau eine v1-Signatur, nie zwei gleichzeitig. Die Rotation funktioniert über die Installationsreihenfolge, nicht dadurch, dass Ihr Empfänger mehrere Signaturen parsen lernt.

  1. Bereiten Sie ein neues Secret in den Abonnement-Einstellungen vor. Es wird einmal angezeigt und wartet bis zu 24 Stunden auf die Aktivierung.
  2. Installieren Sie das neue Secret NEBEN dem aktuellen — Ihr Empfänger muss eine Signatur akzeptieren, die mit einem von beiden erstellt wurde.
  3. Senden Sie optional einen mit dem neuen Secret signierten Test. Er trägt den Header Heilo-Secret-Rotation-Id und einen gewöhnlichen webhook.test-Body; eine 2xx-Antwort beweist nicht, dass Ihr Empfänger die Signatur geprüft hat — bestätigen Sie das in Ihrem eigenen Log.
  4. Aktivieren Sie die Rotation.
  5. Behalten Sie das alte Secret noch 1 Stunde nach der Aktivierung bei, dann entfernen Sie es.

Heilo ändert nichts an Ihrem Empfänger. In diesem Zeitfenster muss Ihr Empfänger eine Signatur akzeptieren, die mit einem der beiden Secrets erstellt wurde.

Notfall: das Secret ist durchgesickert

Eine Notfall-Rotation pausiert den Versand sofort. Installieren Sie NUR das neue Secret — behandeln Sie das alte als kompromittiert — und aktivieren Sie dann; es gibt keine Karenzzeit. Setzen Sie den Versand danach mit „Erneut verifizieren“ fort. Bereits in der Warteschlange stehende Zustellungen werden beim Pausieren übersprungen; senden Sie sie aus dem Zustellprotokoll erneut.

Secret verloren, aber kein Leck? Eine normale Rotation funktioniert trotzdem — das Abonnement muss nicht gelöscht werden.

Ereignistypen

Wählen Sie event_types beim Erstellen eines Abonnements. Jedes Ereignis hat eine eindeutige event_id (UUID v5) und wird pro Abonnement dedupliziert.

webhook.test wird manuell über Test gesendet und enthält data._test = true. Nutzen Sie es zur Feldzuordnung und schliessen Sie es danach von der Geschäftsverarbeitung aus. Der separate Aktivierungs-Handshake ist webhook.subscription.verify.

event_typeBeschreibung
call.completedAnruf abgeschlossen, Transkript bereit
call.outbound.attemptedAusgehender Anrufversuch hat einen Endzustand erreicht (verbunden oder fehlgeschlagen)
call.recording.readyAufzeichnungsdatei zum Download verfügbar
call.transcribedTranskript bereit (getrennt von call.completed)
call.failedAnruf fehlgeschlagen (besetzt/keine Antwort/Fehler)
call.outbound.lifecycle_repairedKorrektur des ausgehenden Lebenszyklus — Anrufstatus repariert
call.deletion_scheduledAnruf zur Löschung vorgemerkt (DSGVO Art. 17, Aufbewahrung)
call.recording.deletedAufzeichnung gelöscht (DSGVO)
call.followup_email.draftedE-Mail-Entwurf fürs Follow-up parat
call.tracker.matchedTracker troffe
contact.createdNeuer Kontakt erstellt
contact.updatedKontakt 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 (einschliesslich recording_url und des verarbeiteten Transkripts).

{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.completed",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "direction": "inbound",
    "caller_phone": "+447700900123",
    "customer_phone_e164": "+447700900123",
    "customer_phone_national": "07700 900123",
    "company_phone_e164": "+48222630000",
    "call_created_at": "2026-09-08T10:00:00Z",
    "app_url": "https://www.heilo.io/calls/3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "duration": 87,
    "recording_url": "https://www.heilo.io/api/v1/calls/3fa85f64-5717-4562-b3fc-2c963f66afa6/recording.mp3?token=EXAMPLE&exp=1789466400",
    "transcript_processed": {
      "caller_name": "Alicja Testowa",
      "counterparty_name": null,
      "caller_location": "Warszawa, Mokotów",
      "client_address": "ul. Przykładowa 10",
      "client_city": "Warszawa",
      "client_country": "Poland",
      "service_needed": "Tynki gipsowe w mieszkaniu 65m²",
      "services_match": true,
      "preferred_date": "w przyszłym tygodniu",
      "additional_details": "Klient wspomniał o terminie do końca czerwca. Druga rozmowa po wycenie.",
      "lead_score": 7,
      "summary": "Prośba o wycenę tynków gipsowych w mieszkaniu 65 m² na Mokotowie.",
      "subject": "Wycena tynków — Warszawa, 65 m²",
      "detected_language": "pl"
    },
    "transcript_original": "Proszę o ofertę w przyszłym tygodniu."
  }
}
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
direction'inbound' | 'outbound'Anrufrichtung.
caller_phonestring | nullGespeicherte Anrufernummer; null, falls in call.completed nicht verfügbar.
customer_phone_e164string | nullKundennummer zum CRM-Kontaktabgleich; null, falls in call.completed nicht verfügbar.
customer_phone_nationalstring | nullDieselbe Kundennummer im nationalen Format, direkt für ein CRM-Telefonfeld; null, wenn der gespeicherte Wert keine nutzbare Nummer ist, etwa bei unterdrückter Rufnummer.
company_phone_e164string | nullDie Nummer, über die dieses Gespräch einging oder ausging. In der Regel Ihre Heilo-Nummer; bei einer Weiterleitung Ihre eigene Nummer, die das Gespräch weitergeleitet hat. Damit lassen sich Notizen zuordnen, wenn Sie mehrere Nummern nutzen; null, wenn nicht erfasst.
call_created_atstring (ISO 8601) | nullWann das Gespräch in Heilo erfasst wurde (ISO 8601). Nicht identisch mit created_at im Umschlag, das den Versandzeitpunkt angibt und bei einem reparierten Ereignis Tage später liegen kann.
app_urlstring | nullDauerhafter Link zum Gespräch in Heilo. Anders als recording_url läuft er nicht ab und kann im CRM-Datensatz bleiben. Zum Öffnen ist eine Heilo-Anmeldung nötig.
durationnumberLänge der Aufzeichnung in Sekunden.
recording_urlstring | nullStabiler Link zur Aufzeichnung; null, wenn die Aufzeichnung zum Verarbeitungszeitpunkt noch nicht gespeichert war.
transcript_processedobjectVerarbeitete Anrufanalyse — siehe die transcript_processed-Feldübersicht in diesem Abschnitt.
transcript_originalstring | nullRohes, 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).

call.outbound.attemptedWird 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.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
agent_user_idstring (uuid)ID des Heilo-Nutzers, der den Anruf gestartet hat.
customer_phonestringDie gewählte Kundennummer.
customer_phone_e164stringKundennummer zum CRM-Kontaktabgleich; null, falls in call.completed nicht verfügbar.
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.
durationnumber | nullGesprächsdauer in Sekunden; null, wenn der Anruf beim Aufbau scheiterte oder die Dauer noch nicht bekannt ist.
attempted_atstring (ISO 8601)Zeitpunkt der Ereignis-Erzeugung (ISO 8601).
has_recordingbooleantrue nur, wenn outbound_lifecycle completed ist und der Anruf nicht im Modus no_recording lief — die Aufzeichnung folgt dann als call.recording.ready.
call.outbound.attempted
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.outbound.attempted",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "agent_user_id": "2ce127a0-c621-483d-b576-e68f69d95e84",
    "customer_phone": "+447700900123",
    "customer_phone_e164": "+447700900123",
    "outbound_lifecycle": "completed",
    "duration": 95,
    "attempted_at": "2026-09-08T10:00:00Z",
    "has_recording": true
  }
}
call.recording.readyWird gesendet, wenn die Aufzeichnungsdatei verfügbar ist. Verwenden Sie es, um die Audiodatei abzurufen oder zu archivieren.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
recording_urlstring | nullStabiler Link zur Aufzeichnung; in seltenen Fällen null, wenn der Link nicht erzeugt werden konnte.
durationnumber | nullDauer in Sekunden; null, wenn noch nicht bekannt.
call.recording.ready
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.recording.ready",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "recording_url": "https://www.heilo.io/api/v1/calls/3fa85f64-5717-4562-b3fc-2c963f66afa6/recording.mp3?token=EXAMPLE&exp=1789466400",
    "duration": 87
  }
}
call.transcribedWird im selben Verarbeitungslauf wie call.completed gesendet — enthält nur das Transkript, ohne Anrufdaten und ohne Aufzeichnungslink.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
transcript_originalstring | nullRohes, wörtliches Transkript; null, wenn nicht verfügbar.
transcript_processedobjectVerarbeitete Anrufanalyse — siehe die transcript_processed-Feldübersicht in diesem Abschnitt.
call.transcribed
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.transcribed",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "transcript_original": "Proszę o ofertę w przyszłym tygodniu.",
    "transcript_processed": {
      "caller_name": "Alicja Testowa",
      "counterparty_name": null,
      "caller_location": "Warszawa, Mokotów",
      "client_address": "ul. Przykładowa 10",
      "client_city": "Warszawa",
      "client_country": "Poland",
      "service_needed": "Tynki gipsowe w mieszkaniu 65m²",
      "services_match": true,
      "preferred_date": "w przyszłym tygodniu",
      "additional_details": "Klient wspomniał o terminie do końca czerwca. Druga rozmowa po wycenie.",
      "lead_score": 7,
      "summary": "Prośba o wycenę tynków gipsowych w mieszkaniu 65 m² na Mokotowie.",
      "subject": "Wycena tynków — Warszawa, 65 m²",
      "detected_language": "pl"
    }
  }
}
call.failedWird 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.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
outbound_lifecycle'agent_no_answer' | 'customer_no_answer' | 'failed_to_initiate'Welche Phase des ausgehenden Anrufs fehlgeschlagen ist.
failure_reasonstring | nullMaschinenlesbarer Fehlercode (z. B. customer_busy, agent_no_confirmation); kann null sein.
call.failed
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.failed",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "outbound_lifecycle": "customer_no_answer",
    "failure_reason": "customer_busy"
  }
}
call.outbound.lifecycle_repairedWird 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.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
previous_lifecycle'agent_only'Zustand vor der Korrektur; derzeit immer agent_only.
new_lifecycle'completed'Zustand nach der Korrektur; derzeit immer completed.
repaired_atstring (ISO 8601)Zeitpunkt der Korrektur (ISO 8601).
call.outbound.lifecycle_repaired
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.outbound.lifecycle_repaired",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "previous_lifecycle": "agent_only",
    "new_lifecycle": "completed",
    "repaired_at": "2026-09-08T10:00:00Z"
  }
}
call.deletion_scheduledDSGVO 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. Sie werden über einen Anruf nur informiert, wenn Heilo einen Nachweis hat, dass dessen Inhalt Ihren Endpunkt erreicht haben könnte. Ein Abonnement allein auf die Löschereignisse macht Sie nicht zum Empfänger — es gibt nichts zu löschen, wenn Sie nie etwas erhalten haben.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
pending_deletion_atstring (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.deletion_scheduled
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.deletion_scheduled",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "pending_deletion_at": "2026-09-09T10:00:00Z",
    "reason": "user_erasure"
  }
}
call.recording.deletedDSGVO: Die Aufzeichnung wurde gelöscht — recording_url gibt 410 zurück. Entfernen oder deaktivieren Sie den Aufzeichnungslink auf Ihrer Seite. Sie werden über einen Anruf nur informiert, wenn Heilo einen Nachweis hat, dass dessen Inhalt Ihren Endpunkt erreicht haben könnte; dies ist also keine vollständige Übersicht aller Löschungen in Ihrer Organisation. Ein 2xx von Ihnen bedeutet, dass die Anweisung angekommen ist, niemals dass die Kopie gelöscht wurde.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
reasonstring | nullBeim Planen der Löschung erfasster Grund; kann null sein.
recording_sidstring | nullTwilio-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_atstring (ISO 8601)Zeitpunkt der Löschung der Aufzeichnung (ISO 8601).
call.recording.deleted
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.recording.deleted",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "user_erasure",
    "recording_sid": null,
    "deletion_kind": "twilio_404",
    "deleted_at": "2026-09-08T10:00:00Z"
  }
}
call.followup_email.draftedWird gesendet, nachdem ein beidseitiges Gespräch verarbeitet wurde und Heilo aus den Absprachen einen Follow-up-E-Mail-Entwurf erstellt hat. Nicht bei Voicemail und nicht, wenn kein Entwurf erstellt werden konnte. Heilo sendet diese E-Mail NIEMALS an den Anrufer — der Entwurf ist für Ihren Vertriebsmitarbeiter zum Prüfen und Versenden.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
subjectstringE-Mail-Betreff, fertig zum Einfügen.
bodystringE-Mail-Text als reiner Text, OHNE Signatur — die Signatur fügt der Mitarbeiter beim Senden hinzu.
languagestringSprache des Entwurfs: die erkannte Gesprächssprache, ersatzweise die in Heilo eingestellte Kontosprache (keine Einstellung pro Nummer).
call.followup_email.drafted
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.followup_email.drafted",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "subject": "Oferta po rozmowie",
    "body": "Dzień dobry, przesyłam ustalenia naszej rozmowy.",
    "language": "pl"
  }
}
call.tracker.matchedWird gesendet, wenn mindestens ein konfigurierter Keyword-Tracker zum verarbeiteten Transkript passt. Treffer enthalten Begriffe und Auszüge; fehlende Auszüge ergeben ein leeres Array.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
matchesobject[]In diesem Anruf gefundene Tracker.
matches[].tracker_idstring (uuid)Kennung des konfigurierten Trackers.
matches[].namestringTrackername.
matches[].matched_termsstring[]Gefundene Begriffe.
matches[].excerptsstring[]Transkriptauszüge; kann leer sein.
call.tracker.matched
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "call.tracker.matched",
  "resource_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "matches": [
      {
        "tracker_id": "cd794362-6117-44d1-b487-c5e7e1ea9082",
        "name": "Oferta",
        "matched_terms": [
          "ofertę"
        ],
        "excerpts": [
          "Proszę o ofertę w przyszłym tygodniu."
        ]
      }
    ]
  }
}
contact.createdWird 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.
FeldTypBeschreibung
contactobjectVollständige Momentaufnahme des neuen Kontakts (Felder unten).
contact.idstring (uuid)Kontakt-ID in Heilo.
contact.phonestringTelefonnummer des Kontakts.
contact.first_namestring | nullnull, wenn nicht angegeben.
contact.last_namestring | nullnull, wenn nicht angegeben.
contact.emailstring | nullnull, wenn nicht angegeben.
contact.companystring | nullnull, wenn nicht angegeben.
contact.created
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "contact.created",
  "resource_id": "86c68698-d54c-43e7-bbbc-328499b98d12",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "contact": {
      "id": "86c68698-d54c-43e7-bbbc-328499b98d12",
      "phone": "+447700900123",
      "first_name": "Alicja",
      "last_name": "Testowa",
      "email": "alicja@example.com",
      "company": null
    }
  }
}
contact.updatedWird gesendet, wenn ein Kontakt bearbeitet wird. Anders als bei contact.created ist dies keine Momentaufnahme: data.diff enthält nur die geänderten Felder.
FeldTypBeschreibung
contact_idstring (uuid)ID des aktualisierten Kontakts.
diffobject (partial)Nur die geänderten Felder — Schlüssel, die in diff fehlen, wurden nicht geändert.
contact.updated
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "contact.updated",
  "resource_id": "86c68698-d54c-43e7-bbbc-328499b98d12",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "contact_id": "86c68698-d54c-43e7-bbbc-328499b98d12",
    "diff": {
      "company": "Example",
      "notes": "Oddzwonić",
      "tags": [
        "oferta"
      ]
    }
  }
}

Mögliche Schlüssel in diff: first_name, last_name, email, phone, company, notes, tags

webhook.testWird nur beim Klick auf Test am Abonnement gesendet. resource_id ist die Abonnement-ID, nicht die Anruf-ID. data enthält synthetische call.completed-Daten und die drei unten beschriebenen Testmarker. Dies bestätigt keine Verfügbarkeit echter Audiodaten.
FeldTypBeschreibung
call_idstring (uuid)Anruf-ID in Heilo. Bei geschäftlichen Anrufereignissen identisch mit resource_id; bei webhook.test eine synthetische Anruf-ID.
direction'inbound' | 'outbound'Anrufrichtung.
caller_phonestring | nullGespeicherte Anrufernummer; null, falls in call.completed nicht verfügbar.
customer_phone_e164string | nullKundennummer zum CRM-Kontaktabgleich; null, falls in call.completed nicht verfügbar.
customer_phone_nationalstring | nullDieselbe Kundennummer im nationalen Format, direkt für ein CRM-Telefonfeld; null, wenn der gespeicherte Wert keine nutzbare Nummer ist, etwa bei unterdrückter Rufnummer.
company_phone_e164string | nullDie Nummer, über die dieses Gespräch einging oder ausging. In der Regel Ihre Heilo-Nummer; bei einer Weiterleitung Ihre eigene Nummer, die das Gespräch weitergeleitet hat. Damit lassen sich Notizen zuordnen, wenn Sie mehrere Nummern nutzen; null, wenn nicht erfasst.
call_created_atstring (ISO 8601) | nullWann das Gespräch in Heilo erfasst wurde (ISO 8601). Nicht identisch mit created_at im Umschlag, das den Versandzeitpunkt angibt und bei einem reparierten Ereignis Tage später liegen kann.
app_urlstring | nullDauerhafter Link zum Gespräch in Heilo. Anders als recording_url läuft er nicht ab und kann im CRM-Datensatz bleiben. Zum Öffnen ist eine Heilo-Anmeldung nötig.
durationnumberLänge der Aufzeichnung in Sekunden.
recording_urlstring | nullStabiler Link zur Aufzeichnung; null, wenn die Aufzeichnung zum Verarbeitungszeitpunkt noch nicht gespeichert war.
transcript_processedobjectVerarbeitete Anrufanalyse — siehe die transcript_processed-Feldübersicht in diesem Abschnitt.
transcript_originalstring | nullRohes, wörtliches Transkript; null, wenn nicht verfügbar.
_testtrueImmer true — unterscheidet die Testnachricht von echten Ereignissen.
_messagestringLesbarer Hinweis, dass es sich um einen Test handelt.
_sent_atstring (ISO 8601)Zeitpunkt des Testversands (ISO 8601).
webhook.test
{
  "api_version": "2026-06-15",
  "event_id": "1bf3a5e2-4f82-4335-988e-4e044fa648d4",
  "event_type": "webhook.test",
  "resource_id": "c2d38cc8-bc1d-4336-91ea-51b8a549a882",
  "created_at": "2026-09-08T10:00:00Z",
  "data": {
    "call_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "direction": "inbound",
    "caller_phone": "+447700900123",
    "customer_phone_e164": "+447700900123",
    "customer_phone_national": "07700 900123",
    "company_phone_e164": "+48222630000",
    "call_created_at": "2026-09-08T10:00:00Z",
    "app_url": "https://www.heilo.io/calls/3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "duration": 87,
    "recording_url": "https://www.heilo.io/api/v1/calls/3fa85f64-5717-4562-b3fc-2c963f66afa6/recording.mp3?token=EXAMPLE&exp=1789466400",
    "transcript_processed": {
      "caller_name": "Alicja Testowa",
      "counterparty_name": null,
      "caller_location": "Warszawa, Mokotów",
      "client_address": "ul. Przykładowa 10",
      "client_city": "Warszawa",
      "client_country": "Poland",
      "service_needed": "Tynki gipsowe w mieszkaniu 65m²",
      "services_match": true,
      "preferred_date": "w przyszłym tygodniu",
      "additional_details": "Klient wspomniał o terminie do końca czerwca. Druga rozmowa po wycenie.",
      "lead_score": 7,
      "summary": "Prośba o wycenę tynków gipsowych w mieszkaniu 65 m² na Mokotowie.",
      "subject": "Wycena tynków — Warszawa, 65 m²",
      "detected_language": "pl"
    },
    "transcript_original": "Proszę o ofertę w przyszłym tygodniu.",
    "_test": true,
    "_message": "Synthetic webhook test; do not create CRM records.",
    "_sent_at": "2026-09-08T10:00:00Z"
  }
}

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.

FeldTypBeschreibung
caller_namestring | nullName des Anrufers, sofern genannt.
summarystring | nullKurze Zusammenfassung des Anrufs.
subjectstring | nullEinzeiliger Titel des Anrufs (bis 80 Zeichen).
service_neededstring | nullWorum der Anrufer gebeten hat.
services_matchboolean | nullOb die Anfrage zu den von Ihnen angebotenen Leistungen passt.
lead_scorenumber | null (1–10)Einschätzung der Lead-Qualität von 1 bis 10.
preferred_datestring | nullVom Anrufer genannter Termin, sofern vorhanden.
client_citystring | nullStadt, sofern erwähnt.
client_addressstring | nullAdresse, sofern erwähnt.
additional_detailsstring | nullZusätzlicher Kontext aus dem Anruf.

Felder, die auftreten können

FeldTypBeschreibung
caller_locationstring | nullIm Gespräch erkannter geografischer Bezug.
client_countrystring | nullLand, sofern erwähnt.
counterparty_namestring | nullName der Gegenseite — nur bei ausgehenden Anrufen und Live-Anrufen, bei denen Heilo still mithört (Zuhörer-Modus).
detected_languagestringSprachcode des Gesprächs (z. B. pl); der Schlüssel kann ganz fehlen.
proposal_itemsobject[] | nullAus 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.

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)
  • POST /calls — Einen ausgehenden Anruf über Ihre Heilo-Nummer starten; er wird aufgezeichnet, transkribiert und wie jeder andere Anruf an Ihr CRM übermittelt

Brauchen Sie einen Endpunkt? Schreiben Sie mit Ihrem Anwendungsfall an support@heilo.io — wir priorisieren die Roadmap nach tatsächlichem Bedarf.

Roadmap (v1.1+)

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 verwalte

Nach der Anmeldig generieren Sie API-Schlüssel, fügen Webhook-Abonnemente hinzu und sehen das Zustelligsprotokoll ii.