API Reference v1
Integratiereferentie voor REST + Webhooks (versie 2026-06-15)
Quickstart CRM-integratie
De snelste route om een CRM met Heilo te verbinden. De volledige API-referentie staat hieronder.
Integreer webhook-first: het event call.completed is de primaire gegevensbron (het bevat de opnamekoppeling en het verwerkte transcript). REST /calls is een aanvulling — introspectie en het lezen van geselecteerde metadata.
- Stel een webhook-endpoint beschikbaar in uw CRM of middleware (zonder code: gebruik Zapier/Make — zie de handleiding hieronder).
- Voeg een abonnement toe in Heilo (Instellingen → Integraties) voor call.completed (optioneel ook call.outbound.attempted).
- Ontvang call.completed en verifieer de handtekening (Heilo-Signature-header, HMAC — zie hieronder).
- Ontdubbel op event_id (heilo-event-id-header); data.call_id groepeert events van hetzelfde gesprek.
- Map de velden naar uw CRM: vind/maak een contact op telefoonnummer, maak een lead/deal aan en koppel een activiteit/notitie (samenvatting + opnamekoppeling).
Geen code? De no-code verbindingshandleiding (Zapier/Make) leidt u er stap voor stap doorheen.
Authenticatie
De publieke API gebruikt Bearer-tokens. Genereer een API-sleutel via de kaart "API-sleutels" op de pagina Integraties en stuur deze mee in de header:
Authorization: Bearer hk_live_AbC1MnPq...
Heilo heeft drie authenticatiemodi:
- Bearer (API-sleutels hk_live_…) — voor de publieke API. Geen CSRF, geen cookies.
- Sessiecookies — voor de webapp (heilo.io). NIET gebruiken voor de publieke API.
- HMAC-SHA256 — voor Webhooks die Heilo naar UW endpoint stuurt (u verifieert de signature-header).
| Recht (scope) | Betekenis |
|---|---|
| read.calls | Gesprekken lezen: GET /api/v1/calls, GET /api/v1/calls/:id |
| read.recordings | Maakt via `GET /calls/{id}/recording-url` een link naar de audio van een gesprek. Los van `read.calls`, omdat audio een andere toestemming is dan metadata — een bestaande sleutel krijgt hem niet, je maakt een nieuwe met expliciete opnametoegang. |
| write.calls, read.contacts, write.contacts, manage.webhooks, manage.api_keys | Gereserveerd voor geplande API-endpoints — vink ze niet alvast aan. |
Het veld environment in het /me-antwoord heeft vandaag altijd de waarde live. Testsleutels zijn gepland.
Base-URL en versie
Alle publieke endpoints bevinden zich onder /api/v1/. Productie:
https://www.heilo.io/api/v1
Huidige versie
v1 · 2026-06-15
De datum is de versie-identificatie van de API (datumgestempeld), niet de datum van vandaag.
Status
Beta
De Heilo API gebruikt een datumgestempelde versie. Alleen breaking changes verhogen de hoofdversie (v1 → v2). Velden of endpoints toevoegen is niet-brekend.
Achterwaarts compatibel: nieuwe responsvelden, nieuwe event_types, nieuwe endpoints. Breaking change = nieuwe hoofdversie (v2). Oude versie minimaal 12 maanden ondersteund na aankondiging van v2.
Rate limits
Uurlimieten per sleutel en per gebruiker (som van alle sleutels). Reset op het hele UTC-uur. Elk verzoek telt mee, ongeacht de responsstatus.
Per sleutel
1000 req/h
Per account (som van sleutels)
5000 req/h
Bij overschrijding geven we 429 terug met een Retry-After-header (seconden tot reset):
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
Fouten
Alle fouten geven een uniforme JSON-vorm terug met error.code (stabiel) en error.message (leesbaar, kan wijzigen). Log de code, niet het bericht.
{
"success": false,
"error": { "code": "RATE_LIMITED", "message": "Per-key rate limit 1000/h exceeded" },
"meta": { "timestamp": "2026-06-03T12:34:56Z" }
}| HTTP | code | Betekenis |
|---|---|---|
| 400 | BAD_REQUEST | Onjuist gevormde query- of body-parameters (algemene validatie) |
| 401 | UNAUTHORIZED | Ontbrekend / ongeldig Bearer-token |
| 402 | SUBSCRIPTION_INACTIVE | Abonnement inactief — verleng de betaling om de sleutel weer in te schakelen |
| 403 | FORBIDDEN | Sleutel heeft niet de vereiste scope |
| 404 | NOT_FOUND | De bron bestaat niet of valt buiten de organisatie van de API-sleutel. |
| 422 | VALIDATION_ERROR | Een bedrijfsregel heeft het verzoek geweigerd (bijv. ongeldig telefoonnummer, quota) |
| 429 | RATE_LIMITED | Uurlimiet overschreden (controleer Retry-After) |
| 500 | DATABASE_ERROR | Server-/databasefout — veilig om opnieuw te proberen met backoff |
| 503 | MAINTENANCE | Publieke API tijdelijk uitgeschakeld (kill switch) |
De code SUBSCRIPTION_INACTIVE komt in twee situaties voor: HTTP 402 — het Heilo-abonnement is verlopen (betaling), en HTTP 409 — het webhook-abonnement is gepauzeerd (bijv. bij de actie Test); klik in dat geval eerst op "Opnieuw verifiëren".
Elk /api/v1-endpoint vereist Bearer. /me hieronder dient voor introspectie van de sleutel; het lezen van gesprekken staat in de sectie "Calls". Behandel webhooks als de primaire gegevensbron bij het integreren van een CRM — REST is voor introspectie en het lezen van geselecteerde metadata.
Introspectie van de API-sleutel — geeft de key id, user_id, scopes en rate limit terug. Handig voor een "connection test" in Zapier/Make.
Toepassing: Zapier-verbindingstest tijdens het opzetten van een eigen integratie. Een 200-respons bewijst dat de sleutel + het netwerk werken.
curl https://www.heilo.io/api/v1/me \ -H "Authorization: Bearer hk_live_AbC1MnPq..."
{
"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" }
}Lees-endpoints voor gesprekken. Vereisen de scope read.calls.
Geef de gesprekken van de organisatie weer. Paginering (page/limit≤100), filters: direction, status, datumbereik (dateFrom/dateTo). Geeft has_more terug.
Queryparameters
| Parameter | Type | Waarden |
|---|---|---|
| page | int | vanaf 1 (standaard 1) |
| limit | int | 1–100 (standaard 20) |
| direction | enum | inbound | outbound |
| status | enum | new | to_call | contacted | qualified |
| dateFrom / dateTo | string | datum YYYY-MM-DD of ISO 8601, bijv. 2026-06-03T12:34:56Z |
| phone | string | het klantnummer van het gesprek; spaties, streepjes en de voorloop-+ zijn optioneel, bijv. 600 100 200 |
curl "https://www.heilo.io/api/v1/calls?limit=20&direction=inbound" \ -H "Authorization: Bearer hk_live_AbC1MnPq..."
{
"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" }
}Haal één gesprek op via id. 404 als het niet bij de organisatie van de sleutel hoort of is verwijderd.
curl https://www.heilo.io/api/v1/calls/<id> \ -H "Authorization: Bearer hk_live_AbC1MnPq..."
Een vers ondertekende link naar de audio van het gesprek, 15 minuten geldig. Het is een downloadtoestemming met een deadline, geen duurzame verwijzing: bewaar de `call_id` en vraag opnieuw, want een link in een CRM-veld is binnen een uur dood. De link in de webhook `call.recording.ready` is zeven dagen ondertekend — via dit endpoint bereik je de audio daarna.
- 200 — de link en het moment waarop hij stopt te werken.
- 409 `RECORDING_NOT_READY` — het gesprek is van jou en de audio is er nog niet. Vraag zo meteen opnieuw.
- 409 `RECORDING_WITHHELD` — het gesprek staat in de prullenbak of is ingepland voor verwijdering. Beide zijn terug te draaien, dus blijf vragen in plaats van de opname bij jou af te schrijven.
- 410 `RECORDING_DELETED` — de bewaartermijnsweep heeft de audio verwijderd en die is niet terug te halen. Stop met vragen en stop met in de wachtrij zetten.
- 410 `RECORDING_NOT_CAPTURED` — dit uitgaande gesprek is nooit opgenomen en er komt nooit een opname voor: de capture-gate weigerde het bij de start, het liep in de modus no_recording of het eindigde zonder dat er gesproken werd. Stop met vragen — er is geen reden om het opnieuw te proberen. Een inkomend gesprek waarvan de opname werd geweigerd, blijft 409 geven, omdat er nog een opname kan volgen.
Het antwoord wordt geserveerd met `Cache-Control: no-store`, omdat de body een credential bevat. De toestemming wordt opnieuw gecontroleerd bij het ophalen van het bestand, niet alleen bij het aanmaken van de link, dus een intussen verwijderd gesprek is meteen niet meer leesbaar.
curl https://www.heilo.io/api/v1/calls/<id>/recording-url \ -H "Authorization: Bearer hk_live_AbC1MnPq..."
{
"success": true,
"data": {
"url": "https://www.heilo.io/api/v1/calls/<id>/recording.mp3?token=...&exp=...",
"expires_at": "2026-09-15T12:15:00.000Z"
}
}De endpoints voor de gesprekkenlijst en het gespreksdetail geven geen opnamebestanden terug. De link naar de opname krijg je in een webhook en na het verlopen ervan via `GET /calls/{id}/recording-url`. Opnamen kunnen worden verwijderd volgens bewaar- en AVG-regels.
Wat REST levert en wat alleen een webhook levert
De twee kanalen dragen niet hetzelfde, en het verschil bepaalt je keuze. REST is duurzaam: je kunt een gesprek er altijd uit lezen. Een webhook is rijker, maar komt één keer en een deel van de inhoud verloopt.
| Gegevens | REST | Webhook |
|---|---|---|
| Gespreksmetadata: richting, nummers, duur, datum | ja | ja |
| CRM-status en beoordelingsstatus | ja | nee |
| Samenvatting, naam van de beller, klantbehoefte | ja | ja |
| De rest van de analyse: stad, adres, leadscore, voorkeursdatum, taal | nee | ja |
| Het woordelijke transcript | nee | ja |
| Opnamelink | ja, via /calls/{id}/recording-url | ja, 7 dagen geldig |
Vandaar de praktische regel: haal de volledige analyse uit de webhook op het moment dat hij binnenkomt, want REST heeft die nooit gedragen. De opname is het enige dat je nu alsnog kunt ophalen — vraag /calls/{id}/recording-url om een verse link van 15 minuten in plaats van de zevendaagse uit de payload te bewaren.
Specificatie en een echte aanvraag
Dezelfde drie operaties, geschreven voor machines: OpenAPI 3.1. Importeer het in Postman of Insomnia, of genereer een client in je eigen taal.
Specificatie en een echte aanvraag
Stuur hier één aanvraag en controleer je sleutel voordat je code schrijft.
Dit roept de echte API aan met je echte sleutel en geeft je eigen gegevens terug. De sleutel blijft in dit browsertabblad — wij slaan hem nooit op.
Uitgaande Webhooks
Heilo stuurt ondertekende JSON-events naar je endpoint. Maak abonnementen in de kaart Webhook-abonnementen. Activering gebruikt een afzonderlijke, niet-ondertekende handshake webhook.subscription.verify, die nooit zakelijke records mag aanmaken.
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 */ }
}Beleid voor opnieuw proberen en pauzeren:
- Bij tijdelijke fouten volgen maximaal 5 pogingen in totaal: na 2 min, 5 min, 30 min en 2 uur, met willekeurige tijdsvariatie (jitter) bij latere pogingen. Na de vijfde fout eindigt de levering als dead-letter.
- Permanente fouten (HTTP 401/403/422) pauzeren het abonnement onmiddellijk — geen nieuwe pogingen.
- 50 opeenvolgende tijdelijke fouten, of 2 opeenvolgende HTTP 410 Gone (bijv. een verwijderd Make-scenario), pauzeren het abonnement eveneens.
- Hervat een gepauzeerd abonnement met "Opnieuw verifiëren" — een nieuwe handshake reactiveert de wachtrij.
Wordt een abonnement automatisch gepauzeerd, dan sturen we een e-mail naar het adres van de accounteigenaar. Dead-letter-events kunt u opnieuw versturen met de knop "Opnieuw versturen" in het Afleverlog — nadat het abonnement opnieuw is geverifieerd.
2xx bevestigt HTTP-ontvangst, niet het afronden van een automatisering of een CRM-opslag. Leveringen kunnen herhaald of in een andere volgorde aankomen. Heilo herstelt recente hiaten binnen een beperkt tijdvenster, niet de volledige geschiedenis. Controleer leveringslog en CRM afzonderlijk.
Verificatiemodi
De niet-ondertekende handshake bevat alleen event_type = webhook.subscription.verify en challenge. Bevestig alleen het endpoint; start geen zakelijke verwerking. Beide modi gebruiken hetzelfde verzoek:
{
"event_type": "webhook.subscription.verify",
"challenge": "example-verification-token"
}Modus permissive (standaard)
Elke 2xx-respons activeert het abonnement; de inhoud wordt genegeerd. Dit is de standaardmodus voor een no-code-ontvanger.
Modus strict (opt-in)
Antwoord met 2xx en JSON met precies de van Heilo ontvangen challenge-waarde:
{"challenge":"<echo of the challenge field from Heilo's POST>"}Kies de modus bij het aanmaken. Wijzigen vereist verwijderen en opnieuw aanmaken. Beheerroutes vereisen een ingelogde sessie en CSRF-bescherming; ze zijn niet toegankelijk met een API-sleutel.
Limieten: max. 20 actieve abonnementen per account (te overschrijven via env). Een abonnement wordt automatisch gepauzeerd na 50 opeenvolgende tijdelijke fouten of 2 opeenvolgende HTTP 410, en onmiddellijk bij HTTP 401/403/422.
HMAC-verificatie (signing_secret)
Ondertekende events, inclusief de handmatige webhook.test, gebruiken Heilo-Signature met HMAC-SHA256 over tijdstempel + punt + oorspronkelijke verzoekbytes. Controleer de handtekening voordat je zakelijke JSON verwerkt. Alleen de endpoint-handshake is niet ondertekend.
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.Deze voorbeelden accepteren handtekeningen tot 600 seconden (10 minuten) oud en 300 seconden (5 minuten) vooruit, zoals de bestaande Heilo-verificatie. Synchroniseer serverklokken. Tijdcontroles beperken het replay-venster; deduplicatie op event_id blijft nodig.
Het ondertekeningsgeheim tonen we maar één keer — bij het aanmaken van het abonnement. Kwijt, of denkt u aan een lek? Open het abonnement onder Instellingen → Integraties → Webhooks en roteer het daar — zie "Geheimrotatie" hieronder. U hoeft het abonnement niet te verwijderen en opnieuw aan te maken.
Geheimrotatie
Heilo stuurt altijd precies één v1-handtekening, nooit twee tegelijk. Rotatie werkt via installatievolgorde, niet doordat uw ontvanger meerdere handtekeningen leert verwerken.
- Bereid een nieuw geheim voor in de instellingen van het abonnement. Het wordt één keer getoond en wacht tot 24 uur op activering.
- Installeer het nieuwe geheim NAAST het huidige — uw ontvanger moet een handtekening accepteren die met een van beide is gemaakt.
- Stuur eventueel een test ondertekend met het nieuwe geheim. Deze bevat de header Heilo-Secret-Rotation-Id en een gewone webhook.test-body; een 2xx-antwoord bewijst niet dat uw ontvanger de handtekening heeft gecontroleerd — bevestig dat in uw eigen log.
- Activeer de rotatie.
- Houd het oude geheim nog 1 uur na activering geïnstalleerd en verwijder het daarna.
Heilo verandert niets aan uw ontvanger. In dat tijdvenster moet uw ontvanger een handtekening accepteren die met een van beide geheimen is gemaakt.
Noodgeval: het geheim is gelekt
Een noodrotatie pauzeert het verzenden onmiddellijk. Installeer ALLEEN het nieuwe geheim — beschouw het oude als gecompromitteerd — en activeer daarna; er is geen coulanceperiode. Hervat het verzenden daarna met Opnieuw verifiëren. Leveringen die al in de wachtrij stonden toen het pauzeerde, worden overgeslagen; verstuur ze opnieuw vanuit het bezorglogboek.
Geheim kwijt zonder lek? Een gewone rotatie werkt ook — u hoeft het abonnement niet te verwijderen.
Eventtypes
Kies event_types bij het aanmaken van een abonnement. Elk event heeft een uniek event_id (UUID v5) en wordt per abonnement ontdubbeld.
webhook.test wordt handmatig met Test verzonden en bevat data._test = true. Gebruik het voor veldkoppeling en sluit het daarna uit van zakelijke verwerking. De afzonderlijke activeringshandshake is webhook.subscription.verify.
| event_type | Omschrijving |
|---|---|
| call.completed | Gesprek afgerond, transcript gereed |
| call.outbound.attempted | Uitgaande belpoging heeft een eindstatus bereikt (verbonden of mislukt) |
| call.recording.ready | Opnamebestand beschikbaar om te downloaden |
| call.transcribed | Transcript gereed (los van call.completed) |
| call.failed | Gesprek mislukt (in gesprek/niet beantwoord/fout) |
| call.outbound.lifecycle_repaired | Correctie van uitgaande levenscyclus — gespreksstatus hersteld |
| call.deletion_scheduled | Gesprek ingepland voor verwijdering (AVG art. 17, bewaartermijn) |
| call.recording.deleted | Opname verwijderd (AVG) |
| call.followup_email.drafted | Concept follow-up-e-mail klaar |
| call.tracker.matched | Tracker gematcht |
| contact.created | Nieuw contact aangemaakt |
| contact.updated | Contact bijgewerkt |
Hieronder het data-object van elk event. Veldnamen, types en enum-waarden maken deel uit van het API-contract en veranderen binnen v1 niet van betekenis; er kunnen in de loop van de tijd nieuwe, optionele velden bijkomen.
call.completed
Verstuurd nadat de opname en het transcript van een afgerond gesprek zijn verwerkt. De primaire gegevensbron voor een CRM — volledige payload (inclusief recording_url en het verwerkte transcript).
{
"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."
}
}| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| direction | 'inbound' | 'outbound' | Gespreksrichting. |
| caller_phone | string | null | Opgeslagen nummer van de beller; null indien niet beschikbaar in call.completed. |
| customer_phone_e164 | string | null | Klantnummer voor CRM-contactkoppeling; null indien niet beschikbaar in call.completed. |
| customer_phone_national | string | null | Hetzelfde klantnummer in nationale notatie, klaar om in een CRM-telefoonveld te plakken; null wanneer de opgeslagen waarde geen bruikbaar nummer is, bijvoorbeeld bij een afgeschermd nummer. |
| company_phone_e164 | string | null | Het nummer waarop dit gesprek binnenkwam of waarvandaan het uitging. Meestal uw Heilo-nummer; bij doorschakeling is het uw eigen nummer dat het gesprek doorstuurde. Handig om notities te routeren als u meerdere nummers gebruikt; null als het niet is vastgelegd. |
| call_created_at | string (ISO 8601) | null | Wanneer het gesprek in Heilo is vastgelegd (ISO 8601). Niet hetzelfde als de created_at van de envelop, die het verzendmoment is en bij een hersteld event dagen later kan liggen. |
| app_url | string | null | Permanente link naar het gesprek in Heilo. Anders dan recording_url verloopt hij niet, dus hij kan in een CRM-record blijven staan. Openen vereist een Heilo-login. |
| duration | number | Lengte van de opname in seconden. |
| recording_url | string | null | Stabiele link naar de opname; null wanneer de opname op het moment van verwerking nog niet was opgeslagen. |
| transcript_processed | object | Verwerkte gespreksanalyse — zie het transcript_processed-veldoverzicht in deze sectie. |
| transcript_original | string | null | Ruw, letterlijk transcript; null wanneer niet beschikbaar. |
Aflevering is at-least-once en niet gegarandeerd in volgorde — sla idempotent op. Dedup-sleutel: event_id. data.call_id koppelt events van hetzelfde gesprek (bijv. call.completed na call.recording.ready).
call.outbound.attemptedVerstuurd wanneer een uitgaande belpoging een eindstatus bereikt — ook bij mislukkingen. completed betekent dat het gesprek tot stand kwam en normaal eindigde; de opname en het transcript volgen als aparte events.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| agent_user_id | string (uuid) | ID van de Heilo-gebruiker die het gesprek startte. |
| customer_phone | string | Het gebelde klantnummer. |
| customer_phone_e164 | string | Klantnummer voor CRM-contactkoppeling; null indien niet beschikbaar in call.completed. |
| outbound_lifecycle | 'completed' | 'agent_no_answer' | 'customer_no_answer' | 'failed_to_initiate' | Eindstatus die het event veroorzaakte; completed betekent dat het gesprek tot stand kwam en normaal eindigde. |
| duration | number | null | Gespreksduur in seconden; null wanneer het gesprek bij het opzetten mislukte of de duur nog niet bekend is. |
| attempted_at | string (ISO 8601) | Moment waarop het event is verstuurd (ISO 8601). |
| has_recording | boolean | true alleen wanneer outbound_lifecycle completed is en het gesprek niet in de modus no_recording stond — de opname volgt dan als call.recording.ready. |
{
"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.readyVerstuurd zodra het opnamebestand beschikbaar is. Gebruik het om de audio op te halen of te archiveren.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| recording_url | string | null | Stabiele link naar de opname; in zeldzame gevallen null wanneer de link niet kon worden gegenereerd. |
| duration | number | null | Duur in seconden; null wanneer nog niet bekend. |
{
"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.transcribedVerstuurd in dezelfde verwerkingsronde als call.completed — bevat alleen het transcript, zonder gespreksgegevens of opnamelink.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| transcript_original | string | null | Ruw, letterlijk transcript; null wanneer niet beschikbaar. |
| transcript_processed | object | Verwerkte gespreksanalyse — zie het transcript_processed-veldoverzicht in deze sectie. |
{
"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.failedVerstuurd wanneer een uitgaand gesprek niet tot stand kwam (geen antwoord, bezet, fout bij opzetten). Geldt alleen voor uitgaande gesprekken. Meestal is een nieuwe lead niet nodig — leg een contactpoging vast.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| outbound_lifecycle | 'agent_no_answer' | 'customer_no_answer' | 'failed_to_initiate' | Welke fase van het uitgaande gesprek mislukte. |
| failure_reason | string | null | Machineleesbare foutcode (bijv. customer_busy, agent_no_confirmation); kan null zijn. |
{
"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_repairedVerstuurd wanneer Heilo de status van een uitgaand gesprek achteraf corrigeert (een late bevestiging van de provider toonde aan dat het gesprek toch tot stand kwam). Werk de gespreksstatus aan uw kant bij.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| previous_lifecycle | 'agent_only' | Status vóór de correctie; momenteel altijd agent_only. |
| new_lifecycle | 'completed' | Status na de correctie; momenteel altijd completed. |
| repaired_at | string (ISO 8601) | Moment van de correctie (ISO 8601). |
{
"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_scheduledAVG art. 17: het gesprek is ingepland voor verwijdering. Uw CRM moet stoppen met het gebruik van de opname en zich voorbereiden op het verwijderen van de gegevens. U wordt alleen over een gesprek geïnformeerd als Heilo vastgelegd heeft dat de inhoud ervan uw endpoint bereikt kan hebben. Alleen op de verwijderingsgebeurtenissen abonneren maakt u geen ontvanger — er valt niets te verwijderen als u nooit iets ontvangen hebt.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| pending_deletion_at | string (ISO 8601) | Wanneer de gegevens definitief worden verwijderd (ISO 8601). |
| reason | 'consent_not_asked' | 'consent_withdrawn' | 'retention_expired' | 'user_erasure' | Reden voor de geplande verwijdering. |
{
"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.deletedAVG: de opname is verwijderd — recording_url geeft 410 terug. Verwijder of deactiveer de opnamelink aan uw kant. U wordt alleen over een gesprek geïnformeerd als Heilo vastgelegd heeft dat de inhoud ervan uw endpoint bereikt kan hebben, dus dit is geen volledig overzicht van alle verwijderingen in uw organisatie. Een 2xx van u betekent dat de instructie is aangekomen, nooit dat de kopie weg is.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| reason | string | null | Reden vastgelegd bij het inplannen van de verwijdering; kan null zijn. |
| recording_sid | string | null | Twilio-opname-ID; null wanneer deze niet kon worden bepaald. |
| deletion_kind | 'hard_deleted' | 'twilio_404' | hard_deleted = verwijderd door Heilo; twilio_404 = het bestand was aan de kant van Twilio al verdwenen. |
| deleted_at | string (ISO 8601) | Moment van verwijdering van de opname (ISO 8601). |
{
"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.draftedWordt verzonden nadat een tweezijdig gesprek is verwerkt en Heilo op basis van de afspraken een concept-follow-upmail heeft opgesteld. Niet bij voicemail en niet wanneer er geen concept kon worden opgesteld. Heilo stuurt deze mail NOOIT naar de beller — het concept is voor je verkoper om te bekijken en te versturen.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| subject | string | Onderwerp van de mail, klaar om te plakken. |
| body | string | Berichttekst als platte tekst, ZONDER ondertekening — die voegt de verkoper zelf toe bij het versturen. |
| language | string | Taal van het concept: de gedetecteerde gesprekstaal, anders de in Heilo ingestelde accounttaal (geen instelling per nummer). |
{
"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.matchedWordt verzonden wanneer minstens één ingestelde trefwoordtracker overeenkomt met het verwerkte transcript. Treffergegevens bevatten termen en fragmenten; ontbrekende fragmenten geven een lege lijst.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| matches | object[] | Trackers gevonden in dit gesprek. |
| matches[].tracker_id | string (uuid) | ID van de ingestelde tracker. |
| matches[].name | string | Naam van de tracker. |
| matches[].matched_terms | string[] | Gevonden termen. |
| matches[].excerpts | string[] | Transcriptfragmenten; kan leeg zijn. |
{
"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.createdVerstuurd wanneer in Heilo een nieuw contact wordt aangemaakt. data.contact is een volledige momentopname van het nieuwe contact; notities en tags zitten er niet in.
| Veld | Type | Omschrijving |
|---|---|---|
| contact | object | Volledige momentopname van het nieuwe contact (velden hieronder). |
| contact.id | string (uuid) | Contact-ID in Heilo. |
| contact.phone | string | Telefoonnummer van het contact. |
| contact.first_name | string | null | null wanneer niet opgegeven. |
| contact.last_name | string | null | null wanneer niet opgegeven. |
| contact.email | string | null | null wanneer niet opgegeven. |
| contact.company | string | null | null wanneer niet opgegeven. |
{
"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.updatedVerstuurd wanneer een contact wordt bewerkt. Anders dan bij contact.created is dit geen momentopname: data.diff bevat alleen de gewijzigde velden.
| Veld | Type | Omschrijving |
|---|---|---|
| contact_id | string (uuid) | ID van het bijgewerkte contact. |
| diff | object (partial) | Alleen de gewijzigde velden — sleutels die in diff ontbreken, zijn niet gewijzigd. |
{
"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"
]
}
}
}Mogelijke sleutels in diff: first_name, last_name, email, phone, company, notes, tags
webhook.testWordt alleen verzonden als je bij een abonnement op Test klikt. resource_id is de abonnements-ID, niet een gespreks-ID. data bevat synthetische call.completed-gegevens en de drie testmarkeringen hieronder. Dit bewijst niet dat echte audio beschikbaar is.
| Veld | Type | Omschrijving |
|---|---|---|
| call_id | string (uuid) | Gespreks-ID in Heilo. Gelijk aan resource_id bij zakelijke gespreksevents; bij webhook.test is het een synthetische ID. |
| direction | 'inbound' | 'outbound' | Gespreksrichting. |
| caller_phone | string | null | Opgeslagen nummer van de beller; null indien niet beschikbaar in call.completed. |
| customer_phone_e164 | string | null | Klantnummer voor CRM-contactkoppeling; null indien niet beschikbaar in call.completed. |
| customer_phone_national | string | null | Hetzelfde klantnummer in nationale notatie, klaar om in een CRM-telefoonveld te plakken; null wanneer de opgeslagen waarde geen bruikbaar nummer is, bijvoorbeeld bij een afgeschermd nummer. |
| company_phone_e164 | string | null | Het nummer waarop dit gesprek binnenkwam of waarvandaan het uitging. Meestal uw Heilo-nummer; bij doorschakeling is het uw eigen nummer dat het gesprek doorstuurde. Handig om notities te routeren als u meerdere nummers gebruikt; null als het niet is vastgelegd. |
| call_created_at | string (ISO 8601) | null | Wanneer het gesprek in Heilo is vastgelegd (ISO 8601). Niet hetzelfde als de created_at van de envelop, die het verzendmoment is en bij een hersteld event dagen later kan liggen. |
| app_url | string | null | Permanente link naar het gesprek in Heilo. Anders dan recording_url verloopt hij niet, dus hij kan in een CRM-record blijven staan. Openen vereist een Heilo-login. |
| duration | number | Lengte van de opname in seconden. |
| recording_url | string | null | Stabiele link naar de opname; null wanneer de opname op het moment van verwerking nog niet was opgeslagen. |
| transcript_processed | object | Verwerkte gespreksanalyse — zie het transcript_processed-veldoverzicht in deze sectie. |
| transcript_original | string | null | Ruw, letterlijk transcript; null wanneer niet beschikbaar. |
| _test | true | Altijd true — onderscheidt het testbericht van echte events. |
| _message | string | Leesbare melding dat dit een test is. |
| _sent_at | string (ISO 8601) | Moment waarop de test is verstuurd (ISO 8601). |
{
"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 — veldoverzicht
De stabiele subset waarop u kunt vertrouwen bij het mappen naar een CRM. Elk veld is optioneel — het is null wanneer het gesprek die informatie niet bevatte.
| Veld | Type | Omschrijving |
|---|---|---|
| caller_name | string | null | Naam van de beller, indien opgegeven. |
| summary | string | null | Korte samenvatting van het gesprek. |
| subject | string | null | Titel van één regel voor het gesprek (max. 80 tekens). |
| service_needed | string | null | Waar de beller om vroeg. |
| services_match | boolean | null | Of het verzoek past bij de diensten die u aanbiedt. |
| lead_score | number | null (1–10) | Inschatting van de leadkwaliteit van 1 tot 10. |
| preferred_date | string | null | Door de beller genoemde datum of tijd, indien genoemd. |
| client_city | string | null | Stad, indien genoemd. |
| client_address | string | null | Adres, indien genoemd. |
| additional_details | string | null | Extra context uit het gesprek. |
Velden die kunnen voorkomen
| Veld | Type | Omschrijving |
|---|---|---|
| caller_location | string | null | In het gesprek gedetecteerde geografische verwijzing. |
| client_country | string | null | Land, indien genoemd. |
| counterparty_name | string | null | Naam van de andere partij — alleen bij uitgaande gesprekken en live gesprekken waarbij Heilo stil meeluistert (meeluistermodus). |
| detected_language | string | Taalcode van het gesprek (bijv. pl); de sleutel kan volledig ontbreken. |
| proposal_items | object[] | null | Voorgestelde vervolgacties en beslissingen uit het gesprek. |
De analyse kan extra velden bevatten — behandel onbekende velden als optioneel en ga er nooit van uit dat ze aanwezig zijn.
Roadmap (v1.1+)
Endpoints gepland voor komende v1.X-releases. Geen harde toezegging — de richting hangt af van feedback.
- GET /contacts — contacten opvragen
- POST /contacts — contact aanmaken (synchroniseren vanuit CRM naar Heilo)
- POST /calls — start een uitgaand gesprek via uw Heilo-nummer; het wordt opgenomen, getranscribeerd en net als elk ander gesprek aan uw CRM geleverd
Heeft u een endpoint nodig? Mail support@heilo.io met uw use-case — we prioriteren de roadmap op basis van werkelijke vraag.
Roadmap (v1.1+)
Heeft u een endpoint nodig? Mail support@heilo.io met uw use-case — we prioriteren de roadmap op basis van werkelijke vraag.
Beheer sleutels en webhooks in het paneel
Na het inloggen genereert u API-sleutels, voegt u webhook-abonnementen toe en bekijkt u het verzendlogboek.