Kunden
Endpoints für die Verwaltung von Kunden — Anlegen, Lesen, Aktualisieren und Löschen — plus alle direkt am Kunden hängenden Unterressourcen (Adressen, Bankverbindungen, Verträge, Schäden, Dokumente …).
Zuletzt geprüft: 12. Mai 2026
Übersicht
Ein Customer ist der zentrale Datensatz für eine Person oder Firma in
Das Customer-Schema ist organisationsspezifisch konfigurierbar: Welche Felder dein Tenant für einen Kunden pflegt, definiert die Form-Konfiguration in den Account-Einstellungen. Die API liefert auf Wunsch (with_schema=true) das aktuelle Feld-Schema deiner Organisation mit zurück, damit Integratoren keine Felder hart verdrahten müssen, die ggf. nicht existieren.
Scopes
Jede Ressource-Familie hat ihren eigenen Scope nach dem Schema v3:<resource>:<action>. Der URL-Pfad spielt für die Berechtigung keine Rolle — entscheidend ist, welche Daten angefasst werden.
Customer-Stammdaten (Name, Anrede, Geburtsdatum, Kommentar etc.):
v3:customers:read—GET /v3/customers,GET /v3/customers/<id>v3:customers:write—POST /v3/customers,PATCH /v3/customers/<id>,DELETE /v3/customers/<id>
Unterressourcen teilen sich entweder den Customer-Scope (direkt am Customer-Datensatz) oder haben eine eigene Scope-Familie (eigenständige Daten-Domäne):
| Unterressource | Scope | Domäne |
|---|---|---|
| Addresses | v3:customers:read · v3:customers:write | direkt am Customer |
| Contacts | v3:customers:read · v3:customers:write | direkt am Customer |
| Banking | v3:customers:read · v3:customers:write | direkt am Customer |
| Nummern | v3:customers:read · v3:customers:write | direkt am Customer |
| Identity | v3:customers:read · v3:customers:write | direkt am Customer |
| Jobs | v3:customers:read · v3:customers:write | direkt am Customer |
| Tags | v3:customers:read · v3:customers:write | direkt am Customer |
| Comments | v3:customers:read · v3:customers:write | direkt am Customer |
| Followers | v3:customers:read · v3:customers:write | direkt am Customer |
| Contracts | v3:contracts:read · v3:contracts:write | eigene Scope-Familie + globally-unique id |
| Damages | v3:damages:read · v3:damages:write | eigene Scope-Familie + globally-unique id |
| Finances | v3:finances:read · v3:finances:write | eigene Scope-Familie + globally-unique id |
| Goals | v3:goals:read · v3:goals:write | eigene Scope-Familie + globally-unique id |
| Documents | v3:documents:read · v3:documents:write | eigene Scope-Familie + globally-unique id |
Praxisbeispiel — Geburtstags-Newsletter-Tool braucht:
v3:customers:read ✓ (Name, Anrede, Geburtsdatum, E-Mail-Adresse)
Mehr nicht. Verträge, Schäden, Finanzen, Dokumente bleiben für dieses Tool unsichtbar — kein versehentlicher Daten-Leak möglich.
Wie die Authentifizierung über Bearer-Token grundsätzlich funktioniert und welche Fehler-Bodies bei fehlendem oder ungültigem Token kommen, siehe Authentication.
Pagination & Limits
Listen-Endpoints sind paginiert. Die Parameter:
page— 1-basierter Seitenindex. Default1.limit— Items pro Seite. Default50, Hard-Cap5000.
Verhalten bei ungültigen Werten: Die API klemmt ungültige Pagination-Parameter still auf einen sicheren Wert ab, statt mit 400 zu antworten — das hält Listing-Calls auch bei Tipp- oder Encoding-Fehlern stabil:
limitnicht-numerisch (abc), leer,0, negativ → Default (50)limit>5000→ auf5000geklemmtlimitmit Dezimalstellen (1.5) → auf den Integer-Anteil geparst (1)pagenicht-numerisch, leer,0, negativ →1pagejenseits der letzten Seite →200mititems: []
Strikt validiert werden hingegen Pfad-Parameter (kid, id) und die meisten Body-Felder — siehe Errors.
Die Antwort enthält immer page, page_size, total und items. Es gibt keine Cursor-Pagination; Clients berechnen Folgeseiten anhand total / page_size.
Beispiel — Seite 2 mit 50 Items pro Seite:
curl 'https://www.api.i-planner.app/v3/customers?page=2&limit=50' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Folgeseiten berechnen:
- Gesamtseitenzahl:
Math.ceil(total / page_size)— im Beispiel:Math.ceil(4217 / 50) = 85 - Letzte Seite hat oft weniger Items:
total - (page - 1) * page_size - Wenn
items.length < page_size, ist die aktuelle Seite die letzte.
Schema
Die Response-Struktur eines einzelnen Customers (mit allen Unterressourcen-Includes aktiviert). Welche tenant-konfigurierbaren Felder dein Customer-Datensatz im Detail hat, kannst du jederzeit über with_schema=true aus der API selbst lernen — siehe GET /v3/customers unten.
{
// ─── System & Identifikation ─────────────────────────────────
"id": 838, // Row-Primary-Key (Postgres-PK)
"kid": 1485348238, // Customer-ID — Source-of-Truth im URL-Pfad (auch bei allen Sub-Resources)
"nummer": "1430397724", // organisations-spezifische Customer-Nummer
"betreuer": 1485503904, // User-ID des zuständigen Betreuers (siehe /v3/users)
"insert_datum": "2017-01-25", // Erstanlage (Date-only, KEIN Time-Anteil)
"edit_datum": "2020-07-15", // letzte Änderung (Date-only)
// ─── Klassifikation & Anrede ─────────────────────────────────
"kontakt_art": 0, // 0=Kunde, 1=Interessent, 2=Inaktiv, 3=Verstorben, 4=Lead, 5=Empfehlung, 6=Kontakt
"anrede": "Herr", // "Frau" | "Herr" | "Firma" | "Familie"
"briefanrede": "Sehr geehrter Herr Dr. Leier,", // serverseitig generierte Brief-Anrede
// ─── Person / Firma — Stammdaten ─────────────────────────────
"name": "Leier", // Nachname oder Firmenname
"vorname": "Helmut", // bei anrede="Firma" typisch leer
"titel": "Dr.", // akademischer Titel
"nation": "deutsch", // Nationalität — siehe select_fields.customers.nation
// ─── Geburts- und Familien-Daten (nur bei natürlichen Personen) ─
"geb": "1970-01-15", // Geburtsdatum
"geb_ort": "München",
"geb_name": "", // Geburtsname (geboren als …)
"familienstand": "verheiratet", // siehe select_fields.customers.familienstand
"datum_heirat": null,
"datum_scheidung": null,
"datum_erstkontakt": "2017-01-25", // Datum des Erstkontakts mit dem Customer
// ─── Inline-Sub-Resources (opt-in via with_*=true, Default false seit Phase C) ─
// ⚠ Naming-Asymmetrie: das Inline-Array `banks` korrespondiert mit der
// URL `/v3/customers/<kid>/banking`, das Inline-Array `identifications`
// mit `/v3/customers/<kid>/identity`. Beide laufen unter `v3:customers:*`
// — siehe Note unten.
"addresses": [
{
"id": 840,
"kid": 1485348238,
"art": 0, // numerisch (siehe select_fields.addresses)
"bezeichnung": "Geschäftlich", // Freitext-Label, z. B. "Erstanschrift", "Zweitanschrift"
"adresszusatz": "Herr Michael Absmeier",
"strasse": "Bahnhofstraße 20",
"plz": "94099",
"ort": "Ruhstorf-Sulzbach (Inn)",
"bundesland": "Bayern",
"insert_datum": null,
"edit_datum": null
}
],
"contacts": [
{
"id": 3338,
"kid": 1485348238,
"art": "E-Mail", // "E-Mail" | "Telefon" — capitalized, nicht snake_case
"wert": "h.leier@example.com",
"werbung": 1, // 0=Marketing-Opt-out, 1=Opt-in — DSGVO-relevant
"insert_datum": null,
"edit_datum": null
}
],
"banks": [
{
"id": 4,
"kid": 1485348238,
"typ": "0", // "0"=Konto, "1"=Depot (siehe select_fields.banks.bank_typ)
"inhaber": "Helmut Leier", // NICHT `kontoinhaber`
"nummer": "", // Legacy-Kontonummer (vor IBAN-Pflicht), typisch leer
"iban": "DE50750700240505025700",
"bic": "DEUTDEDB750",
"institut": "Deutsche Bank Privat und Geschäftskunden, Regensburg",
"insert_datum": null,
"edit_datum": null
}
],
"numbers": [
{
"id": 6,
"kid": 1485348238,
"art": 1, // numerische Nummern-Art
"wert": "143/188/4024",
"insert_datum": null,
"edit_datum": null
}
],
"identifications": [
{
"id": 91,
"kid": 1485348238,
"art": "Personalausweis", // "Personalausweis" | "Reisepass" (select_fields.identifications.ident_art)
"behoerde": "Stadt München",
"ausgestellt": "2020-03-15",
"gueltig": "2030-03-14",
"insert_datum": null,
"edit_datum": null
}
],
"jobs": [
{
"id": 43,
"kid": 1485348238,
"arbeitgeber": "ACME GmbH",
"beruf": "Geschäftsführer",
"berufsstatus": "Geschäftsführer", // siehe select_fields.jobs.berufsstatus
"datum_eintritt": "2010-04-01",
"datum_austritt": null,
"insert_datum": "2021-04-13 11:00:00", // Sub-Resources: Datetime statt Date-only
"edit_datum": "2021-04-13 11:00:09"
}
]
}
Endpoints
Kunden abfragen
Liefert eine paginierte Liste der Kunden deiner Organisation. Unterressourcen sind standardmäßig nicht eingebunden — wer sie braucht, schaltet sie pro Resource über with_*=true ein.
Query-Parameter
page— Seitenindex (Default1).limit— Items pro Seite (Default50, Max5000).with_addresses— Adressen inline mitliefern. Defaultfalse(opt-in). Auftrueoder1setzen zum Aktivieren.with_contacts— Kontaktdaten (E-Mail, Telefon …) inline mitliefern. Defaultfalse(opt-in).with_jobs— Berufsangaben inline mitliefern. Defaultfalse(opt-in).with_banks— Bankverbindungen inline mitliefern. Defaultfalse(opt-in).with_numbers— Nummern (Kundennummer, Vermittler-Nr. …) inline mitliefern. Defaultfalse(opt-in).with_identifications— Ausweisdaten inline mitliefern. Defaultfalse(opt-in).with_schema— Feld-Schema (Labels, Typen, Option-Quellen) im Response unterfieldsundselect_fieldsmitliefern. Defaultfalse(opt-in).flat— Unterressourcen-Arrays in flache Keys ausrollen statt als Array zurückzugeben. Defaultfalse. Das erste Element heißtaddresses_strasse, das zweiteaddresses_1_strasse, das dritteaddresses_2_strasse. Leere Sub-Resource-Arrays produzieren keine Keys.
Request
curl 'https://www.api.i-planner.app/v3/customers?page=1&limit=50&with_jobs=false' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Response
// OK — Pagination-Envelope + `items[]`. Jedes Item ist ein
// vollständiges Customer-Objekt mit Unterressourcen-Arrays — siehe
// „Das Customer-Objekt" oben für die volle Struktur.
{
"page": 1,
"page_size": 50,
"total": 4217,
"items": [
{
"kid": 12345,
"id": 67890,
"vorname": "Helmut",
"name": "Leier",
// … weitere Felder + addresses[], contacts[], jobs[],
// banks[], numbers[], identifications[]
}
],
"fields": {
"customers": {
"vorname": { "label": "Vorname", "data_type": "string", "select_fields_name": null }
}
},
"select_fields": { "customers": {} }
}
Kunden anlegen
Legt einen oder mehrere Kunden an. Der Request-Body kann entweder ein einzelnes Customer-Objekt oder ein Array von Customer-Objekten sein (Batch, max. 100 Items).
Body-Schema
Der Body enthält nur die direkten Felder des Customer-Objekts (anrede, vorname, name, geb, …). Welche Felder dein Tenant kennt, siehst du im Schema-Tab oben oder live über GET /v3/customers?with_schema=true.
Verhalten bei unbekannten Feldern: Felder, die nicht zum Schema gehören oder system-intern sind (id, kid, guid, insert_datum, edit_datum, del, alle vm_* / push_* / alert_* / Passwort-Felder), werden stillschweigend verworfen — kein 400-Error. Schickst du ein leeres Objekt oder eines mit ausschließlich verworfenen Feldern, antwortet der Server allerdings mit 400 no_valid_fields.
Sonderfeld betreuer: Numerische kid des zuständigen Mitarbeiters. Fehlt das Feld, setzt die API automatisch die kid des authentifizierten Tokens (= „du bist Betreuer").
Batch-Verhalten: Jedes Item wird einzeln in einer eigenen Transaktion angelegt (INSERT + Search-Index + Log + Document-Ordner). Schlägt ein Item fehl, landet es in failed[], der Rest des Batches läuft normal weiter — keine alle-oder-keiner-Semantik. Bis zu 10 Items werden parallel verarbeitet.
Request
curl -X POST 'https://www.api.i-planner.app/v3/customers' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"anrede": "frau",
"vorname": "Anna",
"name": "Müller",
"geb": "1985-03-12"
}'
Response
// Created — nur bei Single-Item-Request UND erfolgreich.
// Der Body ist direkt das angelegte Customer-Objekt (kein Wrapper),
// inkl. der vom Server vergebenen `kid` und `id` plus
// `insert_datum` / `edit_datum`.
{
"kid": 12346,
"id": 67890,
"vorname": "Anna",
"name": "Müller",
"geb": "1985-03-12",
"insert_datum": "2026-05-12",
"edit_datum": "2026-05-12",
"betreuer": 42
}
Kunden abrufen
Liefert einen einzelnen Customer-Datensatz inklusive Unterressourcen. <id> ist die numerische kid.
Query-Parameter — identisch zu GET /v3/customers (with_addresses, with_contacts, with_jobs, with_banks, with_numbers, with_identifications, with_schema, flat). Default für alle: false (opt-in) — Sub-Ressourcen müssen explizit per ?with_addresses=true etc. angefordert werden.
Request
curl 'https://www.api.i-planner.app/v3/customers/12345' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Response
// OK — Customer-Datensatz inkl. aller Unterressourcen (sofern
// `with_*=true`). Schema-Hinweise siehe „Das Customer-Objekt" oben.
{
"kid": 12345,
"id": 67890,
"vorname": "Helmut",
"name": "Leier",
"addresses": [ /* … */ ],
"contacts": [ /* … */ ]
}
Unterscheidung 404-Varianten — endpoint_not_found kommt, wenn <id> nicht numerisch ist (z. B. eine UUID übergeben wurde — die Route existiert für den Pfad nicht). not_found kommt, wenn <id> numerisch und gültig ist, aber kein Kunde mit dieser kid in deiner Organisation existiert oder bereits soft-deleted ist.
Kunden aktualisieren
Aktualisiert die im Body gesendeten Felder eines Customers. Felder, die nicht im Body stehen, bleiben unverändert (PATCH-Semantik, kein PUT).
Wie beim POST gilt: Unterressourcen-Arrays werden ignoriert — addresses, contacts, banking etc. im PATCH-Body bewirken nichts. Unterressourcen werden über ihre eigenen Endpoints (PATCH /v3/customers/<kid>/addresses/<id> usw.) aktualisiert. Unbekannte und system-interne Felder werden still verworfen (gleiches Verhalten wie beim Create).
Request
curl -X PATCH 'https://www.api.i-planner.app/v3/customers/12345' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "kommentar": "Aktualisiert per API am 2026-05-12" }'
Response
// OK — Update angewendet. Der Body ist kompakt: ein Success-Flag
// und `updated` = Anzahl der tatsächlich geänderten Felder. Der
// volle aktualisierte Datensatz wird NICHT zurückgegeben — wer ihn
// braucht, ruft danach `GET /v3/customers/<id>` auf.
{
"success": true,
"updated": 1
}
Kunden löschen
Markiert den Customer als gelöscht (del=1), entfernt ihn aber nicht hart aus der Datenbank — analog zum „Papierkorb" im UI. Der Datensatz wird aus Listen-Responses und Suchergebnissen ausgeblendet, bleibt aber für Audit-Zwecke erhalten.
Request
curl -X DELETE 'https://www.api.i-planner.app/v3/customers/12345' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Response
// OK — Customer wurde als gelöscht markiert (Soft-Delete via `del=1`).
// Der Datensatz bleibt in der Datenbank für Audit-Zwecke erhalten, ist
// aber aus Listen-Responses und Suchergebnissen ausgeblendet.
{
"success": true,
"deleted": true,
"soft_deleted": true,
"kid": 12345
}
Duplikat zusammenführen
/v3/customers/<kid>/mergeFührt einen Slave-Customer in den Master zusammen. Alle Sub-Ressourcen des Slave werden auf den Master umgehängt, der Slave-Datensatz wird soft-deleted (del=1). Der Vorgang läuft in einer Transaktion — entweder gehen alle Daten über, oder gar keine.
Anwendungsfall: Derselbe Kunde wurde versehentlich doppelt erfasst (z. B. einmal über Posteingang-Import, einmal manuell). Du wählst eine der beiden Karteien als "die Wahrheit" (Master) und schiebst alles aus der anderen (Slave) hinein.
Was wandert auf den Master?
| Bereich | Verhalten |
|---|---|
addresses, contacts, banking, numbers, jobs, identity | Slave-Zeilen bleiben als zusätzliche Rows am Master bestehen (kid-Rewrite). |
contracts, damages, finances, goals, activities, documents (inkl. Ordner-Baum) | kid-Rewrite — alle CRM-Objekte des Slave gehören danach dem Master. |
comments, tags, followers | Annotationen, die per (section='customers', <row-pk>) auf den Slave zeigen, werden auf die Master-crm_kontakte.id umgeschrieben. |
links (crm_relations) | Beide Richtungen umgeschrieben; master↔master-Self-Loops, die dabei entstehen, werden direkt gelöscht. |
relations (Ehe-/Verwandtschaft) | Beide kid-Spalten umgeschrieben; master↔master-Self-Loops werden gelöscht. |
Was bleibt am Slave?
- Die
crm_kontakte-Zeile selbst bekommtdel=1und ist überGET /v3/customers/<slave-kid>ab sofort als404 not_foundmarkiert. - Das
crm_log(Audit-Trail) des Slave bleibt unangetastet — Bewegungen vor dem Merge sollen historisch nachvollziehbar bleiben. - Der Such-Index-Eintrag des Slave wird entfernt (der Master behält seinen eigenen).
Konflikt-Strategie für die Stammdaten — über das mode-Feld steuerbar:
mode | Verhalten |
|---|---|
master_wins (Default) | Master-Stammdaten (Name, Anrede, Geburtsdatum etc.) bleiben unverändert. |
enrich_master | Leere Master-Felder werden mit Slave-Werten gefüllt. Felder mit Wert am Master werden nie überschrieben. Betrifft nur crm_kontakte-Skalare (vorname, name, titel, anrede, geb_name, namenszusatz, geb). |
Audit-Log: Auf der Master-Seite wird ein CUSTOMERS_MERGE-Eintrag geschrieben, der Master- und Slave-Display-Namen referenziert. Im Activity-Feed erscheint die Zeile "… hat den Kunden <Master> mit <Slave> zusammengeführt."
Body
| Feld | Typ | Pflicht | Default | Bemerkung |
|---|---|---|---|---|
slave_kid | integer | numerische string | ✓ | — | Die kid des Slave-Customers. Muss ≠ <kid> aus dem Pfad sein. |
mode | master_wins | enrich_master | — | master_wins | Konflikt-Strategie für crm_kontakte-Skalare. |
Request
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/merge' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"slave_kid": 67890,
"mode": "master_wins"
}'
Response
// OK — Merge erfolgreich. Slave-kid ist soft-deleted, alle Sub-Resources
// hängen am Master.
{
"success": true,
"master_kid": 12345,
"slave_kid": 67890,
"mode": "master_wins"
}
Unterressourcen
Jede Unterressource hängt über kid an einem Customer und folgt demselben Pagination-Envelope (page, page_size, total, items) wie die Customer-Liste. POST/PATCH/DELETE verhalten sich wie bei den Customer-Endpoints — Unknown- und Protected-Fields werden still verworfen, Fehler-Bodies folgen dem gleichen Muster (empty_body, invalid_id, not_found etc.).
Direkt am Customer — feste Bestandteile des Customer-Schemas. Jede Unterressource hat einen Listen-Endpoint (/v3/customers/<kid>/<sub-resource>), einen Create-Endpoint am gleichen Pfad und einen <id>-Pfad für Retrieve/Update/Delete (/v3/customers/<kid>/<sub-resource>/<id>). Path-kid ist Source-of-Truth — POST/PATCH-Bodies dürfen kid nicht enthalten, sonst antwortet der Server mit 400 body_kid_forbidden.
Addresses
Adressen eines Customers. Pro Customer können mehrere Adressen hinterlegt sein (Erstanschrift, Zweitanschrift, Geschäftlich, …); die Unterscheidung läuft über das Freitext-Feld bezeichnung.
Scopes: v3:customers:read (List + Get) · v3:customers:write (Create + Patch + Delete).
{
"id": 840, // numerischer Row-Identifier (Postgres-PK)
"kid": 1485348238, // Customer, an dem die Adresse hängt
"art": 0, // numerischer Adress-Typ — in v3 nur 0 belegt
"bezeichnung": "Geschäftlich", // Freitext-Label: "Erstanschrift", "Zweitanschrift", "Geschäftlich", …
"adresszusatz": "Herr Michael Absmeier",
"strasse": "Bahnhofstraße 20",
"plz": "94099",
"ort": "Ruhstorf-Sulzbach (Inn)",
"bundesland": "Bayern",
"insert_datum": null,
"edit_datum": null
}
Query-Parameter
kid(im Pfad, nicht als Query) — Customer-ID des Parents. Bei Sub-Resources steht die ID jetzt im URL-Pfad statt im Query-String.page— Seitenindex (Default1).limit— Items pro Seite (Default50, Max5000).with_schema— Feld-Schema (fields+select_fields) im Response mitliefern. Defaultfalse(opt-in).
Beispiel — Adressen eines Kunden abfragen
curl 'https://www.api.i-planner.app/v3/customers/12345/addresses' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Beispiel — neue Adresse anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/addresses' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"bezeichnung": "Erstanschrift",
"strasse": "Musterweg 1",
"plz": "80331",
"ort": "München",
"bundesland": "Bayern"
}'
Beispiel — Adresse löschen
curl -X DELETE 'https://www.api.i-planner.app/v3/customers/12345/addresses/78001' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Contacts
Kontaktdaten eines Customers — eine Zeile pro Kanal (E-Mail, Telefon, Fax, Website …). Genaue Felder hängen vom Tenant-Schema ab.
Scopes: v3:customers:read (List + Get) · v3:customers:write (Create + Patch + Delete).
{
"id": 3338,
"kid": 1485348238,
"art": "E-Mail", // "E-Mail" | "Telefon" — capitalized, kein snake_case
"wert": "michael@absmeierfv.de",
"werbung": 0, // 0=Marketing-Opt-out, 1=Opt-in (DSGVO-relevant)
"insert_datum": null,
"edit_datum": null
}
Query-Parameter
kid(im Pfad, nicht als Query) — Customer-ID des Parents. Bei Sub-Resources steht die ID jetzt im URL-Pfad statt im Query-String.page— Seitenindex (Default1).limit— Items pro Seite (Default50, Max5000).with_schema— Feld-Schema im Response mitliefern. Defaultfalse(opt-in).
Beispiel — Kontaktdaten eines Kunden abfragen
curl 'https://www.api.i-planner.app/v3/customers/12345/contacts' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Beispiel — E-Mail-Adresse anlegen (mit Marketing-Opt-in)
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/contacts' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"art": "E-Mail",
"wert": "neu@example.com",
"werbung": 1
}'
Beispiel — Kontaktdatensatz löschen
curl -X DELETE 'https://www.api.i-planner.app/v3/customers/12345/contacts/79001' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Banking
Bankverbindungen eines Customers. Genaue Felder hängen vom Tenant-Schema ab.
Scopes: v3:customers:read (List + Get) · v3:customers:write (Create + Patch + Delete).
{
"id": 4,
"kid": 1485348238,
"typ": "0", // "0"=Konto, "1"=Depot — String (in select_fields auch number)
"inhaber": "Absmeier, Michael",
"nummer": "", // Legacy-Kontonummer (vor IBAN-Pflicht), typisch leer
"iban": "DE50750700240505025700",
"bic": "DEUTDEDB750",
"institut": "Deutsche Bank Privat und Geschäftskunden, Regensburg",
"insert_datum": null,
"edit_datum": null
}
Query-Parameter
kid(im Pfad, nicht als Query) — Customer-ID des Parents. Bei Sub-Resources steht die ID jetzt im URL-Pfad statt im Query-String.page— Seitenindex (Default1).limit— Items pro Seite (Default50, Max5000).with_schema— Feld-Schema im Response mitliefern. Defaultfalse(opt-in).
Beispiel — Bankverbindungen abfragen
curl 'https://www.api.i-planner.app/v3/customers/12345/banking' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Beispiel — Bankverbindung anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/banking' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"typ": "0",
"inhaber": "Helmut Leier",
"iban": "DE89370400440532013000",
"bic": "SSKMDEMM",
"institut": "Sparkasse München"
}'
Beispiel — Bankverbindung löschen
curl -X DELETE 'https://www.api.i-planner.app/v3/customers/12345/banking/80001' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Nummern
Kunden-, Vermittler-, Steuer- und sonstige Identifizierungsnummern. Genaue Felder hängen vom Tenant-Schema ab.
Scopes: v3:customers:read (List + Get) · v3:customers:write (Create + Patch + Delete).
{
"id": 6,
"kid": 1485504800,
"art": 1, // numerischer Nummern-Typ — pro Tenant konfiguriert
"wert": "143/188/4024",
"insert_datum": null,
"edit_datum": null
}
Query-Parameter
kid(im Pfad, nicht als Query) — Customer-ID des Parents. Bei Sub-Resources steht die ID jetzt im URL-Pfad statt im Query-String.page— Seitenindex (Default1).limit— Items pro Seite (Default50, Max5000).with_schema— Feld-Schema im Response mitliefern. Defaultfalse(opt-in).
Beispiel — Nummern abfragen
curl 'https://www.api.i-planner.app/v3/customers/12345/numbers' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Beispiel — neue Nummer anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/numbers' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"art": 1,
"wert": "K-9876543"
}'
Beispiel — Nummer löschen
curl -X DELETE 'https://www.api.i-planner.app/v3/customers/12345/numbers/81001' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Identity
Ausweisdaten eines Customers — Personalausweis oder Reisepass.
Scopes: v3:customers:read (List + Get) · v3:customers:write (Create + Patch + Delete).
{
"id": 91,
"kid": 1485348238,
"art": "Personalausweis", // "Personalausweis" | "Reisepass" — capitalized String
"behoerde": "Stadt München", // ausstellende Behörde
"ausgestellt": "2020-03-15", // Ausstellungsdatum (Date)
"gueltig": "2030-03-14", // Ablaufdatum (Date)
"insert_datum": null,
"edit_datum": null
}
Query-Parameter
kid(im Pfad, nicht als Query) — Customer-ID des Parents. Bei Sub-Resources steht die ID jetzt im URL-Pfad statt im Query-String.page— Seitenindex (Default1).limit— Items pro Seite (Default50, Max5000).with_schema— Feld-Schema im Response mitliefern. Defaultfalse(opt-in).
Beispiel — Ausweisdaten abfragen
curl 'https://www.api.i-planner.app/v3/customers/12345/identity' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Beispiel — Reisepass anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/identity' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"art": "Reisepass",
"behoerde": "Landratsamt München",
"ausgestellt": "2022-06-10",
"gueltig": "2032-06-09"
}'
Beispiel — Ausweisdaten löschen
curl -X DELETE 'https://www.api.i-planner.app/v3/customers/12345/identity/82001' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Jobs
Beruf, Arbeitgeber und Beschäftigungs-Details eines Customers. Genaue Felder hängen vom Tenant-Schema ab.
Scopes: v3:customers:read (List + Get) · v3:customers:write (Create + Patch + Delete).
{
"id": 43,
"kid": 1485504800,
"arbeitgeber": "ACME GmbH",
"beruf": "Geschäftsführer",
"berufsstatus": "Geschäftsführer", // siehe select_fields["berufsstatus"]
"datum_eintritt": "2010-04-01",
"datum_austritt": null, // null = aktuell beschäftigt
"insert_datum": "2021-04-13 11:00:00", // Sub-Resources: Datetime statt Date-only
"edit_datum": "2021-04-13 11:00:09"
}
Query-Parameter
kid(im Pfad, nicht als Query) — Customer-ID des Parents. Bei Sub-Resources steht die ID jetzt im URL-Pfad statt im Query-String.page— Seitenindex (Default1).limit— Items pro Seite (Default50, Max5000).with_schema— Feld-Schema im Response mitliefern. Defaultfalse(opt-in).
Beispiel — Berufsangaben abfragen
curl 'https://www.api.i-planner.app/v3/customers/12345/jobs' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Beispiel — Beruf anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/jobs' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"arbeitgeber": "ACME GmbH",
"beruf": "Senior Developer",
"berufsstatus": "Angestellt",
"datum_eintritt": "2024-01-15"
}'
Beispiel — Berufseintrag löschen
curl -X DELETE 'https://www.api.i-planner.app/v3/customers/12345/jobs/83001' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Tags
Freie Beschriftungs-Tags am Customer (z. B. „VIP", „Newsletter", „Bestandskunde"). Genaue Felder hängen vom Tenant-Schema ab.
Scopes: v3:customers:read (List) · v3:customers:write (Create + Delete).
{
"id": 84001,
"kid": 12345,
"name": "VIP",
"farbe": "#FFB400", // Hex- oder Token-Wert (abhängig vom Tenant)
"insert_datum": "2024-08-14",
"edit_datum": "2024-08-14"
}
Query-Parameter
kid(im Pfad, nicht als Query) — Customer-ID des Parents. Bei Sub-Resources steht die ID jetzt im URL-Pfad statt im Query-String.page— Seitenindex (Default1).limit— Items pro Seite (Default50, Max5000).with_schema— Feld-Schema im Response mitliefern. Defaultfalse(opt-in).
Beispiel — Tags eines Kunden abfragen
curl 'https://www.api.i-planner.app/v3/customers/12345/tags' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Beispiel — Tag setzen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/tags' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Bestandskunde",
"farbe": "#22C55E"
}'
Beispiel — Tag entfernen
curl -X DELETE 'https://www.api.i-planner.app/v3/customers/12345/tags/84001' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
CRM-Objekte am Customer — eigenständige Datensätze (Verträge, Schäden, Finanzen, Ziele), die im Customer-Kontext angelegt und gelistet werden. Jedes hat deep paths für angehängte Comments / Documents / Followers / Tags (siehe Anhänge an CRM-Objekten unten).
Contracts
Versicherungs-, Finanzierungs- und sonstige Verträge eines Customers. Genaue Felder hängen vom Tenant-Schema ab.
{
"id": 90001,
"kid": 12345,
"nummer": "V-2024-00471", // interne Vertragsnummer
"gesellschaft": "Allianz", // Versicherer / Anbieter
"sparte": "krankenversicherung", // siehe Schema-Tab
"tarif": "Vital BestMed",
"beitrag": 87.50, // periodischer Beitrag in EUR
"intervall": "monatlich", // monatlich | jaehrlich | einmalig
"beginn": "2024-01-01",
"ende": null, // null = unbefristet
"status": "aktiv", // aktiv | gekuendigt | ruht
"insert_datum": "2024-01-15",
"edit_datum": "2024-06-02"
}
Customer-scoped (Listing + Create only):
Read / Update / Delete laufen über die globally-unique Contract-id top-level — siehe Verträge für die vollständige API:
GET /v3/contracts/<id>— Vertrag abrufenPATCH /v3/contracts/<id>— Vertrag aktualisierenDELETE /v3/contracts/<id>— Vertrag löschen
Zusätzliche Helper-Endpoints
GET /v3/system/sparten— Liste der verfügbaren Sparten als Reference-Daten. Keinkid-Parameter, weil global. Scopev3:system:read(siehe System)./v3/contracts/<id>/personsund/v3/contracts/<id>/tariffs— Sub-Resources versicherte Personen und Tarif-Optionen, top-level über die Contract-id.
Query-Parameter (List)
kid(im Pfad, nicht als Query) — Customer-ID des Parents.page,limit,with_schema— wie bei den direkten Unterressourcen.
Beispiel — Verträge eines Kunden abfragen
curl 'https://www.api.i-planner.app/v3/customers/12345/contracts' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Beispiel — Vertrag anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/contracts' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"nummer": "H-2026-00012",
"gesellschaft": "HUK24",
"sparte": "haftpflicht",
"beitrag": 7.90,
"intervall": "monatlich",
"beginn": "2026-06-01"
}'
Beispiel — Vertrag löschen (top-level über die globally-unique id)
curl -X DELETE 'https://www.api.i-planner.app/v3/contracts/90001' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Damages
Schadensfälle / Schadenmeldungen am Customer.
Scopes: v3:damages:read (List + Get) · v3:damages:write (Create + Patch + Delete).
{
"id": 91001,
"kid": 12345,
"schadennummer": "S-2026-00018",
"vertrag_id": 90001, // optionale Verknüpfung zum Vertrag
"art": "haftpflicht",
"datum": "2026-04-21", // Schadendatum
"schadenshoehe": 1250.00,
"status": "in_bearbeitung", // gemeldet | in_bearbeitung | reguliert | abgelehnt
"beschreibung": "Wasserschaden in der Küche",
"insert_datum": "2026-04-22",
"edit_datum": "2026-04-23"
}
Customer-scoped (Listing + Create only):
Read / Update / Delete laufen über die globally-unique Schaden-id top-level — siehe Schäden für die vollständige API.
Query-Parameter (List) — kid (im Pfad), page, limit, with_schema.
Beispiel — Schaden anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/damages' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"vertrag_id": 90001,
"art": "haftpflicht",
"datum": "2026-04-21",
"schadenshoehe": 1250.00,
"beschreibung": "Wasserschaden in der Küche"
}'
Finances
Finanz-Positionen am Customer (Einnahmen, Ausgaben, Vermögen, Schulden).
Scopes: v3:finances:read (List + Get) · v3:finances:write (Create + Patch + Delete).
{
"id": 92001,
"kid": 12345,
"art": "einnahme", // einnahme | ausgabe | vermoegen | verbindlichkeit
"kategorie": "gehalt",
"betrag": 4500.00,
"intervall": "monatlich",
"beginn": "2024-01-01",
"ende": null,
"beschreibung": "Grundgehalt Festanstellung",
"insert_datum": "2024-01-15",
"edit_datum": "2024-01-15"
}
Customer-scoped (Listing + Create only):
Read / Update / Delete laufen über die globally-unique Finanz-id top-level — siehe Finanzen für die vollständige API.
Query-Parameter (List) — kid (im Pfad), page, limit, with_schema.
Beispiel — Finanz-Position anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/finances' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"art": "ausgabe",
"kategorie": "miete",
"betrag": 1450.00,
"intervall": "monatlich"
}'
Goals
Finanz-/Lebensziele eines Customers (Altersvorsorge, Hauskauf, Studium der Kinder …).
Scopes: v3:goals:read (List + Get) · v3:goals:write (Create + Patch + Delete).
{
"id": 93001,
"kid": 12345,
"titel": "Altersvorsorge",
"kategorie": "altersvorsorge", // siehe Schema-Tab
"zielbetrag": 250000.00,
"zieldatum": "2055-01-01",
"prioritaet": 1, // 1 = hoch, 3 = niedrig
"status": "in_planung", // in_planung | aktiv | erreicht | verworfen
"beschreibung": "Private Rentenversicherung + ETF-Sparplan",
"insert_datum": "2024-01-15",
"edit_datum": "2026-03-12"
}
Customer-scoped (Listing + Create only):
Read / Update / Delete laufen über die globally-unique Ziel-id top-level — siehe Ziele für die vollständige API.
Query-Parameter (List) — kid (im Pfad), page, limit, with_schema.
Beispiel — Ziel anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/goals' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"titel": "Hauskauf",
"kategorie": "immobilie",
"zielbetrag": 400000.00,
"zieldatum": "2030-06-01",
"prioritaet": 1
}'
Aktivitäten & Kollaboration — generische Anhang-Ressourcen am Customer: Kommentare, Dokumente und Follower.
Comments
Freitext-Kommentare am Customer. Full-CRUD: List, Get, Create, Patch, Delete.
Scopes: v3:customers:read (List + Get) · v3:customers:write (Create + Patch + Delete).
{
"id": 95001,
"kid": 12345,
"text": "Kunde hat per E-Mail nach einer Vertragsanpassung gefragt.",
"autor_kid": 7, // ausdrücklich angegebener Berater; 0 = Organisationstoken
"autor_name": "Anna Berater",
"insert_datum": "2026-05-12T14:23:00.000Z"
}
Query-Parameter (List) — kid (Pflicht), page, limit. Comments haben kein konfigurierbares Schema; with_schema wird ignoriert.
Beim POST ist text Pflicht. Optional kann autor_kid die KID eines aktiven Beraters derselben Organisation angeben. Die API prüft die Berater-Mitgliedschaft; eine unbekannte, gelöschte oder inaktive KID wird mit HTTP 400 (invalid_author_kid) abgelehnt. Ohne autor_kid erscheint der Name des Organisationstokens als Kommentarautor (autor_kid: 0). Das Änderungsprotokoll nennt in beiden Fällen den ausführenden Token. PATCH ändert nur den Text und lässt den beim POST bestimmten Autor bestehen.
Beispiel — Kommentar anlegen
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/comments' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"text": "Telefonat: Kunde möchte Beratungstermin im Juni.",
"autor_kid": 7
}'
Documents
Dokumente am Customer (PDF, Bilder, beliebige Datei-Typen). Werden in einer Ordnerstruktur abgelegt; die Default-Ordner Dokumente wird beim Customer-Create automatisch angelegt.
Scopes: v3:documents:read (List + Get + Folders) · v3:documents:write (Create + Patch + Delete).
{
"id": 96001,
"kid": 12345,
"name": "Versicherungsschein-Allianz-2024.pdf",
"mime_type": "application/pdf",
"dateigroesse": 142315, // Bytes
"ordner_id": 5001, // Verweis auf einen Folder, siehe GET .../folders
"ordner_name": "Verträge",
"beschreibung": "KV-Police Vital BestMed",
"insert_datum": "2024-01-16",
"edit_datum": "2024-01-16"
}
Customer-scoped (Listing + Create only):
Read / Update / Delete laufen über die globally-unique Dokument-id top-level — siehe Dokumente für die vollständige API.
Query-Parameter (List) — kid (im Pfad), page, limit. Optional ordner_id zum Filtern auf einen bestimmten Ordner.
Beispiel — Dokument hochladen (Datei-Inhalt als Base64-String im inhalt-Feld)
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/documents' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Vertragsanlage.pdf",
"mime_type": "application/pdf",
"ordner_id": 5001,
"inhalt": "JVBERi0xLjQKJeLjz9MK…"
}'
Followers
Mitarbeiter, die einen Customer „abonniert" haben — bekommen Notifications bei Änderungen. Keine eigenen Datensatz-Felder außer der User-Verknüpfung.
Scopes: v3:customers:read (List) · v3:customers:write (Create + Delete).
{
"id": 97001,
"kid": 12345, // beobachteter Customer
"user_kid": 7, // Mitarbeiter, der folgt
"user_name": "Helmut Leier",
"insert_datum": "2026-04-20"
}
Query-Parameter (List) — kid (Pflicht), page, limit.
Beispiel — Customer abonnieren
curl -X POST 'https://www.api.i-planner.app/v3/customers/12345/followers' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"user_kid": 7
}'
Anhänge an CRM-Objekten
Comments, Documents, Followers und Tags lassen sich auch an einem konkreten CRM-Objekt anlegen — z. B. ein Kommentar zu einem Vertrag, ein Dokument an einem Schaden.
Pfad-Pattern für Sub-Domains mit globally-unique id (contracts, damages, finances, goals, contact-persons, portals):
/v3/<section>/<sectionId>/<resource>[/<id>]
Pfad-Pattern für Identity — eine customer-direkte Sub-Resource ohne eigenen Top-Level:
/v3/customers/<kid>/identity/<sectionId>/<resource>[/<id>]
<section>—contracts,damages,finances,goals,contact-persons,portals(odercustomers/<kid>/identity)<sectionId>— Integer-ID des konkreten Section-Objekts<resource>—comments,documents,followersodertags
Scopes: je nach <resource> — v3:customers:* für comments / followers / tags an Customer-direkten Subs, v3:documents:* für documents. Ein Parent-Scope wie v3:contracts:read ersetzt niemals den Dokument-Scope. Der Parent-Datensatz selbst bleibt an seine eigene Scope-Familie gebunden.
Felder, Methods und Response-Bodies sind identisch zu den Customer-Level-Pendants oben — der einzige Unterschied: kein kid-Body-Feld, kein kid-Query-Param. Beides ergibt sich aus dem Pfad. POST/PATCH-Bodies mit kid-Feld werden mit 400 body_kid_forbidden abgelehnt.
curl -X POST 'https://www.api.i-planner.app/v3/contracts/90001/comments' \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "text": "Beitragserhöhung 2026 vorgemerkt." }'