EndpointsAlle Endpoints liefern JSON, alle Listen-Endpoints unterstützen Cursor-Pagination via cursor + limit. Schreib-Endpoints akzeptieren JSON-Bodies und antworten mit 201 (POST) oder 200 (PATCH).
GET
/api/v1/anrufe
anrufe:readListet Anrufe Ihres Teams (alle Mitglieder), neueste zuerst. Cursor-Pagination über die Anruf-ID — stabil auch bei kontinuierlichem Polling, da neu eintreffende Anrufe nicht zu Skips führen.
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| limit | integer | 1 bis 200 | 50 |
| cursor | string | Anruf-ID, ab der weiterpaginiert wird | — |
| since | ISO-8601 | createdAt >= since | — |
| score | integer | Mindest-Lead-Score (1–5) | — |
Response (gekürzt)
{
"data": [
{
"id": "clz1abcdef0123",
"anruferNummer": "+491701234567",
"anruferName": "Familie Schmidt",
"zusammenfassung": "Sucht 3-Zimmer-Wohnung in Eppendorf, max. 350 k€.",
"leadScore": 4,
"dauer": 142,
"anrufTyp": "inbound",
"createdAt": "2026-05-08T14:32:01.000Z",
"kontaktId": "clz1ktnxyz9876"
}
],
"nextCursor": "clz1abcdef0123"
}
cURL-Beispiel
curl -X GET 'https://heyannika.de/api/v1/anrufe?limit=20&score=3' \
-H 'Authorization: Bearer ha_live_…'
GET
/api/v1/anrufe/{id}
anrufe:readLiefert einen einzelnen Anruf mit Detaildaten — Transkript und nächste Schritte inklusive. Das Transkript wird nur zurückgegeben, wenn der Anrufer der Speicherung eingewilligt hat (DSGVO/§7 UWG).
Query-Parameter
Keine Query-Parameter — der Endpoint liefert immer denselben Snapshot.
Response (gekürzt)
{
"id": "clz1abcdef0123",
"anruferNummer": "+491701234567",
"anruferName": "Familie Schmidt",
"dauer": 142,
"anrufTyp": "inbound",
"leadScore": 4,
"zusammenfassung": "Sucht 3-Zimmer-Wohnung in Eppendorf …",
"naechsteSchritte": "Exposé senden, Termin Mo 10:00 bestätigen.",
"transkript": "Annika: Guten Tag, hier spricht …",
"createdAt": "2026-05-08T14:32:01.000Z",
"kontakt": {
"id": "clz1ktnxyz9876",
"name": "Familie Schmidt",
"telefon": "+491701234567",
"email": "schmidt@example.de"
}
}
cURL-Beispiel
curl -X GET 'https://heyannika.de/api/v1/anrufe/clz1abcdef0123' \
-H 'Authorization: Bearer ha_live_…'
GET
/api/v1/kontakte
kontakte:readListet alle Kontakte Ihres Teams. Cursor-Pagination, gelöschte Kontakte (Soft-Delete) sind ausgeschlossen.
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| limit | integer | 1 bis 200 | 50 |
| cursor | string | Kontakt-ID, ab der weiterpaginiert wird | — |
Response (gekürzt)
{
"data": [
{
"id": "clz1ktnxyz9876",
"name": "Familie Schmidt",
"telefon": "+491701234567",
"email": "schmidt@example.de",
"leadScore": 4,
"consentErteilt": true,
"createdAt": "2026-05-08T14:32:01.000Z"
}
],
"nextCursor": null
}
cURL-Beispiel
curl -X GET 'https://heyannika.de/api/v1/kontakte?limit=50' \
-H 'Authorization: Bearer ha_live_…'
GET
/api/v1/objekte
objekte:readListet die Objekte Ihres Teams. Optional gefiltert nach Status. preis und groesse werden als Number geliefert (kein Decimal-String).
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| limit | integer | 1 bis 200 | 50 |
| cursor | string | Objekt-ID, ab der weiterpaginiert wird | — |
| status | enum | aktiv | verkauft | reserviert | deaktiviert | — |
Response (gekürzt)
{
"data": [
{
"id": "clz1obj4567abc",
"titel": "3-Zi-ETW Eppendorf, Balkon, EBK",
"adresse": "Eppendorfer Landstr. 12, 20249 Hamburg",
"preis": 349000,
"zimmer": 3,
"groesse": 78.5,
"status": "aktiv",
"exposeUrl": "https://…/expose/clz1obj4567abc.pdf"
}
],
"nextCursor": null
}
cURL-Beispiel
curl -X GET 'https://heyannika.de/api/v1/objekte?status=aktiv' \
-H 'Authorization: Bearer ha_live_…'
GET
/api/v1/statistiken
statistiken:readAggregierte KPIs über einen Zeitraum: Gesamtanrufe, Hot-Leads (Score ≥ 4), Durchschnittsdauer und eine Tagesreihe. Tagesgrenzen werden in Europe/Berlin gerechnet, damit DE-Statistiken auch nahe Mitternacht sauber sind.
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| zeitraum | enum | 7 | 30 | 90 (Tage) | 30 |
Response (gekürzt)
{
"zeitraum": 30,
"anrufeGesamt": 248,
"hotLeadsGesamt": 41,
"durchschnittsdauer": 134,
"anrufeProTag": [
{ "datum": "2026-04-09", "anzahl": 6 },
{ "datum": "2026-04-10", "anzahl": 9 }
]
}
cURL-Beispiel
curl -X GET 'https://heyannika.de/api/v1/statistiken?zeitraum=7' \
-H 'Authorization: Bearer ha_live_…'
POST
/api/v1/kontakte
kontakte:writeLegt einen neuen Kontakt im Team an. Body als JSON. Triggert den Outgoing-Webhook kontakt.created, falls Sie eine aktive Webhook-Subscription für dieses Event haben.
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| name | string | Pflicht — 1 bis 200 Zeichen | — |
| telefon | string | Pflicht — 5 bis 30 Zeichen, internationales Format empfohlen | — |
| email | string | Optional — gültige E-Mail-Adresse | — |
| leadScore | integer | Optional — 0 bis 5 | 0 |
| consentErteilt | boolean | Optional — DSGVO-Einwilligung | false |
| notiz | string | Optional — freie Notiz | — |
| kontaktTyp | enum | kaufinteressent | mietinteressent | verkaufsinteressent | vermieter | sonstig | — |
Response (gekürzt)
{
"id": "clz1ktnxyz9876",
"name": "Familie Schmidt",
"telefon": "+491701234567",
"email": "schmidt@example.de",
"leadScore": 4,
"createdAt": "2026-05-10T14:32:01.000Z"
}
cURL-Beispiel
curl -X POST 'https://heyannika.de/api/v1/kontakte' \
-H 'Authorization: Bearer ha_live_…' \
-H 'Content-Type: application/json' \
-d '{
"name": "Familie Schmidt",
"telefon": "+491701234567",
"email": "schmidt@example.de",
"leadScore": 4,
"consentErteilt": true,
"kontaktTyp": "kaufinteressent"
}'
PATCH
/api/v1/kontakte/{id}
kontakte:writeAktualisiert einen vorhandenen Kontakt teilweise. Senden Sie nur die Felder, die geändert werden sollen — alles andere bleibt erhalten. Body-Felder identisch zu POST, alle optional.
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| name | string | Optional — 1 bis 200 Zeichen | — |
| telefon | string | Optional — 5 bis 30 Zeichen | — |
| email | string | Optional — gültige E-Mail-Adresse | — |
| leadScore | integer | Optional — 0 bis 5 | — |
| consentErteilt | boolean | Optional — DSGVO-Einwilligung | — |
| notiz | string | Optional — freie Notiz | — |
| kontaktTyp | enum | kaufinteressent | mietinteressent | verkaufsinteressent | vermieter | sonstig | — |
Response (gekürzt)
{
"id": "clz1ktnxyz9876",
"name": "Familie Schmidt",
"telefon": "+491701234567",
"email": "schmidt-neu@example.de",
"leadScore": 5,
"createdAt": "2026-05-10T14:32:01.000Z"
}
cURL-Beispiel
curl -X PATCH 'https://heyannika.de/api/v1/kontakte/clz1ktnxyz9876' \
-H 'Authorization: Bearer ha_live_…' \
-H 'Content-Type: application/json' \
-d '{
"email": "schmidt-neu@example.de",
"leadScore": 5
}'
POST
/api/v1/objekte
objekte:writeLegt ein neues Objekt im Team an. Adresse wird aus den Einzelfeldern strasse + hausnummer + plz + ort + land zusammengesetzt.
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| titel | string | Pflicht — Kurzbeschreibung des Objekts | — |
| strasse | string | Pflicht | — |
| hausnummer | string | Pflicht | — |
| plz | string | Pflicht | — |
| ort | string | Pflicht | — |
| land | string | Optional | Deutschland |
| preis | number | Optional — in Euro | — |
| zimmer | number | Optional — Anzahl Zimmer | — |
| groesse | number | Optional — Wohnfläche in m² | — |
| beschreibung | string | Optional — freier Beschreibungstext | — |
| status | enum | aktiv | verkauft | reserviert | deaktiviert | aktiv |
Response (gekürzt)
{
"id": "clz1obj4567abc",
"titel": "3-Zi-ETW Eppendorf, Balkon, EBK",
"adresse": "Eppendorfer Landstr. 12, 20249 Hamburg",
"preis": 349000,
"zimmer": 3,
"groesse": 78.5,
"status": "aktiv",
"exposeUrl": null
}
cURL-Beispiel
curl -X POST 'https://heyannika.de/api/v1/objekte' \
-H 'Authorization: Bearer ha_live_…' \
-H 'Content-Type: application/json' \
-d '{
"titel": "3-Zi-ETW Eppendorf, Balkon, EBK",
"strasse": "Eppendorfer Landstr.",
"hausnummer": "12",
"plz": "20249",
"ort": "Hamburg",
"preis": 349000,
"zimmer": 3,
"groesse": 78.5,
"status": "aktiv"
}'
PATCH
/api/v1/objekte/{id}
objekte:writeAktualisiert ein vorhandenes Objekt teilweise. Senden Sie nur die Felder, die geändert werden sollen. Alle Felder identisch zu POST, alle optional.
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| titel | string | Optional | — |
| strasse | string | Optional | — |
| hausnummer | string | Optional | — |
| plz | string | Optional | — |
| ort | string | Optional | — |
| land | string | Optional | — |
| preis | number | Optional — in Euro | — |
| zimmer | number | Optional | — |
| groesse | number | Optional — Wohnfläche in m² | — |
| beschreibung | string | Optional | — |
| status | enum | aktiv | verkauft | reserviert | deaktiviert | — |
Response (gekürzt)
{
"id": "clz1obj4567abc",
"titel": "3-Zi-ETW Eppendorf, Balkon, EBK",
"adresse": "Eppendorfer Landstr. 12, 20249 Hamburg",
"preis": 339000,
"zimmer": 3,
"groesse": 78.5,
"status": "reserviert",
"exposeUrl": null
}
cURL-Beispiel
curl -X PATCH 'https://heyannika.de/api/v1/objekte/clz1obj4567abc' \
-H 'Authorization: Bearer ha_live_…' \
-H 'Content-Type: application/json' \
-d '{
"preis": 339000,
"status": "reserviert"
}'
POST
/api/v1/outbound/rufe
outbound:writePlant einen ausgehenden Anruf. Setzt nur den DB-Record. Der existierende Outbound-Cron pickt geplante Calls auf und initiiert sie. Voraussetzungen: Kontakt gehört zum Team, consentErteilt=true, kein DNC-Eintrag — sonst 403 mit Begründung.
Query-Parameter
| Name | Typ | Beschreibung | Default |
|---|
| kontaktId | string | Pflicht — ID des Zielkontakts | — |
| objektTitel | string | Optional — Objekt-Titel als Gesprächskontext | — |
| scenario | string | Optional — Gesprächs-Szenario-ID | — |
Response (gekürzt)
{
"outboundCallId": "clz1out7788xy",
"scheduledFor": "2026-05-10T15:00:00.000Z"
}
cURL-Beispiel
curl -X POST 'https://heyannika.de/api/v1/outbound/rufe' \
-H 'Authorization: Bearer ha_live_…' \
-H 'Content-Type: application/json' \
-d '{
"kontaktId": "clz1ktnxyz9876",
"objektTitel": "3-Zi-ETW Eppendorf",
"scenario": "expose-followup"
}'