Links
Verknüpfungen zwischen beliebigen CRM-Objekten — Customer ↔ Vertrag, Vertrag ↔ Dokument, Schaden ↔ Aktivität etc. Verfügbar parent-scoped unter Customer, Produktpartner und Benutzer. Liefert die Cross-Reference-Layer für Workflows, die mehrere Ressourcen-Typen miteinander koppeln.
Zuletzt geprüft: 14. Mai 2026
Übersicht
Ein Link ist eine generische Verknüpfung zwischen zwei CRM-Objekten — definiert über ein (owner_section, owner_id) ↔ (foreign_section, foreign_id)-Paar. Beispiele:
- Vertrag → Dokument (Police gehört zu Vertrag)
- Schaden → Aktivität (Telefonat zum Schaden)
- Customer → Customer (Familien-Beziehung über die Relations-API modelliert; Links sind die generische Variante)
Im Gegensatz zur typisierten Relations-API (mit Beziehungs-Typen wie „Ehepartner") sind Links untyped — nur die Sections und IDs zählen. Das macht sie flexibel, aber semantisch leicht.
Section-Werte sind die Resource-Familien-Namen aus der Start — customers, contracts, damages, documents etc.
Scopes
Links teilen sich die Scope-Familie mit ihrem Parent — sie sind ein Cross-Reference-Layer am jeweiligen Parent-Modell, kein eigenes Geschäftsobjekt:
| Endpoint | Scope |
|---|---|
GET /v3/customers/<kid>/links | v3:customers:read |
POST /v3/customers/<kid>/links | v3:customers:write |
DELETE /v3/customers/<kid>/links/<id> | v3:customers:write |
GET /v3/products/<kid>/links | v3:products:read |
POST /v3/products/<kid>/links | v3:products:write |
DELETE /v3/products/<kid>/links/<id> | v3:products:write |
GET /v3/users/<kid>/links | v3:users:read |
POST /v3/users/<kid>/links | v3:users:write |
DELETE /v3/users/<kid>/links/<id> | v3:users:write |
Auth-Mechanik und Fehler siehe Authentifizierung. Vollständige Scope-Referenz mit Token-Beispielen: Scopes.
Schema
{
"id": 55001,
"kid": 12345, // Customer, an dem der Link hängt
"owner_section": "contracts",
"owner_id": 90001, // Vertrag-ID
"foreign_section": "documents",
"foreign_id": 33001, // Dokument-ID
"insert_datum": "2024-06-15"
}
kid-Bindung: Jeder Link hängt logisch an seinem Parent (kid = Customer-, Product- oder User-ID). Der kid steht im Pfad (/v3/{customers|products|users}/<kid>/links) — sowohl für List, POST als auch DELETE. POST/PATCH-Bodies mit kid-Feld werden mit 400 body_kid_forbidden abgelehnt.
Lateral-Access-Schutz (Mai 2026): Der Server verifiziert bei jedem DELETE zusätzlich, dass der adressierte Link wirklich zum URL-Parent gehört. Bei einem Mismatch kommt 404 not_found. Das gilt sowohl für die parent-scoped Variante (DELETE /v3/customers/<kid>/links/<linkId> muss zum Customer-kid passen) als auch für die nested-resource-Variante (DELETE /v3/<section>/<sectionId>/links/<linkId> muss owner_section/owner_id matchen). Damit kann ein Caller mit Tenant-Scope einen Link nicht über einen fremden Parent löschen — selbst wenn er die Link-ID kennt.
Endpoints
Die Endpoints sind 1:1 identisch unter allen drei Parents — die Beispiele unten zeigen customers, dieselben Aufrufe funktionieren mit products und users als Parent.
Links abfragen
Liefert alle Links, deren Owner der durch den Pfad referenzierte Parent ist — also owner_section = customers|products|users und owner_id = <kid>. Anders als andere List-Endpoints kein Pagination-Envelope; die Response ist ein einfaches { total, items }-Objekt.
Wichtig — Owner ist Pfad-fest: owner_section und owner_id werden aus dem URL-Pfad abgeleitet und sind nicht als Query-Parameter setzbar. Um Links eines anderen Owner-Records (z. B. eines Vertrags, eines Schadens) abzufragen, nutze die nested-resource-Variante des jeweiligen Records — z. B. GET /v3/contracts/<id>/links für die Links eines Vertrags. Diese Route trägt ihren eigenen Scope (v3:contracts:read) und ihre eigene Ownership-Pruefung.
Path-Parameter: <kid> (Customer-, Product- oder User-ID — gleichzeitig Owner-ID des Links).
Query-Parameter:
| Name | Typ | Pflicht | Beschreibung |
|---|---|---|---|
foreign_section | string | nein | Filter: nur Links auf diese Foreign-Section (z. B. documents, contracts) |
Fehler:
query_owner_section_forbidden(400) —owner_sectionals Query angegeben (Owner ist Pfad-fest)query_owner_id_forbidden(400) —owner_idals Query angegeben (Owner ist Pfad-fest)
# Alle Links dieses Customers
curl "https://www.api.i-planner.app/v3/customers/12345/links" \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
# Nur die Dokumente, die direkt an diesem Customer haengen
curl "https://www.api.i-planner.app/v3/customers/12345/links?foreign_section=documents" \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"
Link anlegen
Legt eine neue Verknüpfung an, deren Owner der durch den Pfad referenzierte Parent ist (owner_section = customers|products|users, owner_id = <kid>). Der Body liefert ausschliesslich die Foreign-Seite.
Owner ist Pfad-fest: owner_section und owner_id werden nicht im Body akzeptiert. Um einen Link mit einem anderen Owner-Record anzulegen (z. B. Vertrag → Dokument), nutze die nested-resource-POST-Variante des jeweiligen Records — z. B. POST /v3/contracts/<id>/links mit Body { foreign_section, foreign_id }.
Path-Parameter: <kid> (Customer-, Product- oder User-ID — der Owner des neuen Links).
Body (alle Felder Pflicht — kid, owner_section, owner_id sind verboten, da Pfad-fest):
| Feld | Typ | Beschreibung |
|---|---|---|
foreign_section | string | Resource-Familie des Foreign-Objekts (z. B. documents) |
foreign_id | int > 0 | ID des Foreign-Objekts — siehe Hinweis unten zur Wahl der ID |
Fehler:
empty_body(400) — Body fehlt oder ist kein Objektbody_owner_section_forbidden(400) —owner_sectionim Body (Owner ist Pfad-fest)body_owner_id_forbidden(400) —owner_idim Body (Owner ist Pfad-fest)body_kid_forbidden(400) —kidim Body (kommt aus Pfad)missing_foreign_section(400) —foreign_sectionfehltinvalid_foreign_id(400) —foreign_idfehlt, ist 0, negativ oder kein Integerrelation_exists(409) — Link existiert bereits
Response: 201 mit { success: true, ids: [<owner→foreign>, <foreign→owner>] }. Links werden serverseitig bidirektional angelegt — pro Aufruf entstehen zwei crm_relations-Rows, deren IDs in der Reihenfolge owner→foreign, foreign→owner zurückkommen. Zum Löschen reicht einer der beiden IDs; der gegenläufige Eintrag wird automatisch mit entfernt.
curl -X POST https://www.api.i-planner.app/v3/customers/12345/links \
-H "Authorization: Bearer $IPLANNER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"foreign_section": "documents",
"foreign_id": 33001
}'
Link löschen
Path-Parameter: <kid> (Customer-, Product- oder User-ID), <id> (Link-Row-ID).
Löscht eine Verknüpfung. Hard-Delete — kein Soft-Delete-Flag, der Link ist nach erfolgreichem Aufruf weg. Die verlinkten Owner-/Foreign-Objekte bleiben unangetastet.
Path-Parameter: id (integer, positiv).
Response: 200 mit { success: true }. 404 endpoint_not_found bei nicht-numerischer ID, 404 not_found bei nicht existierender ID, 400 invalid_id bei 0/negativ. Volle Error-Tabelle in Fehler.
curl -X DELETE https://www.api.i-planner.app/v3/customers/12345/links/55001 \
-H "Authorization: Bearer $IPLANNER_API_TOKEN"