ReactiveCRM Integrationsanleitung
Technische Dokumentation für Unternehmen (Mandanten), die eine eigene Integration mit ReactiveCRM entwickeln möchten: Erfassen von Leads und Kunden, Anlegen von Deals, Senden von Marketing-Ereignissen und Exportieren von Daten.
Dieses Dokument behandelt nur die für externe Integrationen am häufigsten verwendeten APIs. Interne Referenzdaten und Admin-Service-Endpunkte werden bewusst ausgeschlossen.
1. Überblick über die Integration
Ein typischer Integrationsablauf sieht wie folgt aus:
Ihr System (Backend / serverseitiger Proxy)
|
| 1. POST /api/auth/login (Access- und Refresh-Token anfordern)
v
ReactiveCRM
| 2. Referenzen: GET /api/users/paged, GET /api/statuses, GET /api/stages, GET /api/lead-sources
| (UUIDs für ownerId, authorId, statusId usw. abrufen)
v
| 3. Kernoperationen:
| POST /api/leads/create — Lead anlegen
| POST /api/clients/create — Kunden anlegen
| POST /api/contacts/create — Kontakt anlegen
| POST /api/deals/create — Deal anlegen
| POST /api/dashboard/marketing/events — Marketing-Ereignis senden
| POST /api/leads/import/batch — Leads per Sammelimport anlegen
v
| 4. Lesen / Exportieren:
| GET /api/leads/paged — Seitenweises Lesen mit Filtern
| GET /api/export/leads — NDJSON-Export aller Leads
Wichtige Sicherheitsregel: Rufen Sie die CRM-API niemals direkt aus dem Browser eines Endbenutzers auf. Bewahren Sie das CRM-Token und die internen Identifikatoren in Ihrem Backend (oder einer Serverless-Funktion) auf.
2. Authentifizierung
2.1. Token abrufen
Die Authentifizierungsendpunkte benötigen kein Token:
| Methode | URL | Beschreibung |
|---|---|---|
POST | /api/auth/login | Anmeldung mit Benutzername + Passwort, gibt Access- und Refresh-Token zurück |
POST | /api/auth/refresh | Refresh-Token gegen ein neues Tokenpaar eintauschen |
POST | /api/auth/logout | Refresh-Token widerrufen |
curl -X POST "$CRM_BASE_URL/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username": "integration", "password": "secret123"}'
{
"token": "eyJhbGciOiJIUzI1NiJ9...",
"refreshToken": "a8f3k2m9Qx7Tt1Vv...",
"tokenType": "Bearer",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"firstName": "Integration",
"lastName": "Bot",
"tenantId": "660e8400-e29b-41d4-a716-446655440001"
},
"tenant": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Zunga Corp"
}
}
2.2. Regeln für die Token-Verwaltung
- Access-Token (
token) — ein JWT mit einer Gültigkeit von 1 Stunde. Senden Sie es bei jeder Anfrage mit:Authorization: Bearer <token>. - Refresh-Token (
refreshToken) — eine Zufallszeichenfolge mit einer Gültigkeit von 7 Tagen. Verwenden Sie es, um ein neues Tokenpaar anzufordern. - Bei jedem
/api/auth/refreshrotiert der Server das Refresh-Token: Das alte wird gelöscht und ein neues ausgestellt. Speichern Sie beide neuen Werte. - Eine Anfrage mit einem abgelaufenen Access-Token antwortet mit
401. In diesem Fall aktualisieren Sie das Token und wiederholen die ursprüngliche Anfrage — führen Sie keine erneute Anmeldung durch.
2.3. Grundeinstellungen
CRM_BASE_URL=https://crm.example.com
In allen folgenden Beispielen werden diese Header vorausgesetzt:
Authorization: Bearer <CRM_ACCESS_TOKEN>
Content-Type: application/json
3. Konventionen für Seiten-APIs
Alle Listen-Endpunkte der Form GET /api/*/paged teilen dieselben Konventionen:
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
page | integer | 0 | Seitennummer, nullbasiert |
size | integer | pro Endpunkt | Seitengröße |
sort | string | createdAt,desc | Sortierung im Format Feld,Richtung. Richtung: asc oder desc |
Antwortstruktur für Seiten
{
"content": [ { "..." } ],
"page": 0,
"size": 20,
"totalElements": 137,
"totalPages": 7
}
Datumsfilter
Verwenden Sie FeldVon / FeldBis für Bereiche (ISO 8601):
createdAtFrom=2026-01-01T00:00:00Z
createdAtTo=2026-01-31T23:59:59Z
Sortierung
Immer ?sort=Feld,Richtung:
?sort=createdAt,desc
?sort=name,asc
Einige Filterfelder haben eigene Bereichsparameter (z. B.
dealAmountFrom/dealAmountTo).
Semantik der Filterung
- Alle Filterungen und Sortierungen werden serverseitig durchgeführt (es ist nicht nötig, alles herunterzuladen und clientseitig zu filtern).
- Mehrere Filter werden mit UND verknüpft.
- Textfilter (Teilstring) verwenden eine case-insensitive Suche (ILIKE).
- Der universelle
search-Filter durchsucht mehrere Felder mit ODER.
4. Referenzen (UUIDs abrufen)
Bevor Sie Entitäten anlegen, rufen Sie die UUIDs der zugehörigen Referenzdaten ab. Die wichtigsten sind:
4.1. Benutzer (GET /api/users/paged)
Wird für ownerId, authorId, developingManagerIds verwendet.
curl "$CRM_BASE_URL/api/users/paged?page=0&size=50&sort=createdAt,asc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
Beispielantwort (content-Auszug):
[
{
"id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"firstName": "Roman",
"lastName": "Posledovskiy",
"username": "roman",
"email": "roman@example.com",
"tenantId": "660e8400-e29b-41d4-a716-446655440001"
}
]
4.2. Status (GET /api/statuses)
Wird für statusId von Leads, Deals und Deal-Party-Kunden verwendet. Gibt ein Array zurück:
curl "$CRM_BASE_URL/api/statuses" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
[
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "New",
"entityType": "LEAD"
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"name": "In progress",
"entityType": "STAGE"
}
]
4.3. Phasen (GET /api/stages)
Wird für die stageId eines Deals verwendet:
curl "$CRM_BASE_URL/api/stages" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
4.4. Lead-Quellen (GET /api/lead-sources)
Gibt einen Baum der Lead-Quellen zurück. Wird für die leadSourceId eines Leads verwendet:
curl "$CRM_BASE_URL/api/lead-sources" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
[
{
"id": "cccc0001-0000-0000-0000-000000000001",
"name": "Website",
"children": [
{
"id": "cccc0001-0000-0000-0000-000000000002",
"name": "Feedback form",
"children": []
}
]
}
]
5. Leads
5.1. Lead anlegen (POST /api/leads/create)
curl -X POST "$CRM_BASE_URL/api/leads/create" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Website-Anfrage: Beratung",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"leadSourceId": "cccc0001-0000-0000-0000-000000000002",
"statusId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"quality": "WARM"
}'
Anfragefelder:
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
message | string | nein | Nachricht / Anfrage-Text |
ownerId | uuid | ja | Verantwortlicher Benutzer |
authorId | uuid | ja | Benutzer, der den Lead erstellt hat |
clientId | uuid | nein | Zugehöriger Kunde |
contactId | uuid | nein | Zugehöriger Kontakt |
leadSourceId | uuid | nein | Knoten der Lead-Quelle |
statusId | uuid | nein | Status |
quality | enum | nein | HOT, WARM, COOL, COLD |
Beispielantwort 201 Created:
{
"id": "22222222-2222-2222-2222-222222222222",
"message": "Website-Anfrage: Beratung",
"status": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "New"
},
"quality": "WARM",
"dealId": null,
"createdAt": "2026-09-05T20:00:00Z",
"updatedAt": "2026-09-05T20:00:00Z",
"version": 0,
"author": {
"id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"firstName": "Roman",
"lastName": "Posledovskiy"
},
"owner": {
"id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"firstName": "Roman",
"lastName": "Posledovskiy"
}
}
Bewahren Sie die zurückgegebene
idauf — sie wird für dieleadIddes Marketing-Ereignisses benötigt (siehe Abschnitt 8).
5.2. Seitenweises Lesen (GET /api/leads/paged)
curl "$CRM_BASE_URL/api/leads/paged?page=0&size=20&createdAtFrom=2026-09-01T00:00:00Z&sort=createdAt,desc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
Wichtige Filter:
| Parameter | Typ | Modus | Beschreibung |
|---|---|---|---|
statusId | uuid | exakt | Nach Status filtern |
leadSourceId | uuid | exakt | Nach Lead-Quelle filtern |
quality | enum | exakt | HOT, WARM, COOL, COLD |
message | string | ILIKE | Teilstring in der Nachricht |
search | string | ILIKE (ODER) | Suche über Nachricht, Kontakt, E-Mail, Telefon |
contactEmail | string | ILIKE | Nach E-Mail des Kontakts |
contactPhone | string | ILIKE | Nach Telefon des Kontakts |
company | string | ILIKE | Nach Firmenname |
clientId | uuid | exakt | Nach Kunden-ID |
createdAtFrom / createdAtTo | date-time | Bereich | Nach Erstellungsdatum |
updatedAtFrom / updatedAtTo | date-time | Bereich | Nach Änderungsdatum |
createdBy | uuid | exakt | Nach Lead-Autor |
Es gibt auch Filter für den zugehörigen Deal: dealStatusId, dealStageId, dealAmountFrom/dealAmountTo, dealProbabilityFrom/dealProbabilityTo.
Sortierung: createdAt, updatedAt, message, quality, Status/Quelle und andere (Feld,Richtung-Format).
5.3. Einzelnen Lead abrufen (GET /api/leads/{id})
curl "$CRM_BASE_URL/api/leads/$LEAD_ID" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
5.4. Sammelimport von Leads (POST /api/leads/import/batch)
Für das Massenladen vieler Leads verwenden Sie den Batch-Endpunkt. Er akzeptiert ein Array von Leads, erstellt einen Importverlauf und ermöglicht das Zurücksetzen des gesamten Imports.
curl -X POST "$CRM_BASE_URL/api/leads/import/batch" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fileName": "leads-2026-09-05.csv",
"leads": [
{
"message": "Anfrage #1",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"quality": "WARM"
},
{
"message": "Anfrage #2",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"quality": "COOL"
}
]
}'
Beispielantwort:
{
"importId": "44444444-4444-4444-4444-444444444444",
"imported": 2,
"total": 2,
"skipped": []
}
imported— wie viele erstellt wurden.skipped— Array der übersprungenen Zeilen mitindex(0-basiert) undreason.
Verlauf und Zurücksetzen:
# Importverlauf
curl "$CRM_BASE_URL/api/leads/import/history" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
# Import zurücksetzen
curl -X POST "$CRM_BASE_URL/api/leads/import/rollback/$IMPORT_ID" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
5.5. Schneller Website-Lead (POST /api/site/leads)
Für Website-Formulare gibt es einen einzigen kombinierten Endpunkt, der atomar den Kontakt, dessen primäre Telefonnummer und E-Mail, den Lead, die Kontakt-Lead-Verknüpfung und das Marketing-Ereignis in einer Anfrage erstellt — mit Idempotenz über externalId.
Siehe die spezielle Anleitung: site-lead-multi-contract.md.
6. Kunden und Kontakte
6.1. Kunden anlegen (POST /api/clients/create)
curl -X POST "$CRM_BASE_URL/api/clients/create" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "COMPANY",
"name": "Romashka GmbH",
"taxId": "7700000001",
"regNumber": "1234567890",
"country": "RU",
"phone": "+7-495-000-00-01",
"email": "info@romashka.ru",
"website": "https://romashka.ru",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
}'
Wichtige Felder:
| Feld | Typ | Gilt für | Beschreibung |
|---|---|---|---|
type | enum | alle | INDIVIDUAL oder COMPANY (erforderlich) |
name | string | alle | Anzeigename (erforderlich) |
firstName / lastName | string | INDIVIDUAL | Vor- und Nachname |
taxId | string | COMPANY | Steuer-ID (INN) |
regNumber | string | COMPANY | Registrierungsnummer |
legalAddress | string | COMPANY | Rechtliche Anschrift |
phone / email / website | string | alle | Kontaktdaten |
country | string | alle | ISO-Ländercode |
ownerId | uuid | alle | Verantwortlicher Benutzer |
authorId | uuid | alle | Autor |
developingManagerIds | uuid[] | alle | Betreuende Manager |
6.2. Seitenweises Kundenlesen (GET /api/clients/paged)
curl "$CRM_BASE_URL/api/clients/paged?page=0&size=20&type=COMPANY&search=Romashka&sort=name,asc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
Wichtige Filter: name, type (INDIVIDUAL/COMPANY), country, taxId, email, phone, lastName (Einzelpersonen), search (nach Name/Steuer-ID/Telefon), createdAtFrom/createdAtTo, createdBy, developingManagerId.
6.3. Duplikatsprüfung (GET /api/clients/duplicates)
Prüfen Sie vor dem Anlegen eines Kunden, ob bereits ein ähnlicher existiert:
# Nach Steuer-ID und Name
curl "$CRM_BASE_URL/api/clients/duplicates?type=COMPANY&taxId=7700000001&name=Romashka" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
6.4. Kontakt anlegen (POST /api/contacts/create)
curl -X POST "$CRM_BASE_URL/api/contacts/create" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Ivan",
"lastName": "Petrov",
"dateOfBirth": "1990-05-15",
"gender": "MALE",
"countryCode": "RU",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
}'
Felder: firstName (erforderlich), lastName, patronymicName, dateOfBirth (date), gender (MALE/FEMALE), countryCode, ownerId, authorId.
6.5. Seitenweises Kontaktlesen (GET /api/contacts/paged)
curl "$CRM_BASE_URL/api/contacts/paged?page=0&size=20&search=Petrov&sort=createdAt,desc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
7. Deals
7.1. Deal anlegen (POST /api/deals/create)
curl -X POST "$CRM_BASE_URL/api/deals/create" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Server-Hardware-Lieferung",
"clientId": "9f128931-69fd-493a-9a08-be5be0e6603d",
"statusId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"stageId": "dddd0001-0000-0000-0000-000000000001",
"probability": 60,
"amount": 150000.00,
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
}'
Wichtige Felder:
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
name | string | ja | Deal-Name |
clientId | uuid | ja | Kunden-ID |
statusId | uuid | nein | Status (Phasenstatus) |
stageId | uuid | nein | Verkaufsphase |
probability | integer | nein | Wahrscheinlichkeit 0-100 |
amount | number | nein | Betrag |
plannedAmount | number | nein | Geplanter Betrag |
discountPercent | integer | nein | Rabatt 0-100 |
startDate / expectedCloseDate | date-time | nein | Daten |
ownerId | uuid | nein | Besitzer |
leadId | uuid | nein | Zugehöriger Lead |
contactId | uuid | nein | Zugehöriger Kontakt |
productIds | uuid[] | nein | Produkte (vereinfachtes Format) |
dealProducts | array | nein | Deal-Positionen (volles Format) |
dealParties | array | nein | Deal-Parteien |
7.2. Seitenweises Deal-Lesen (GET /api/deals/paged)
curl "$CRM_BASE_URL/api/deals/paged?page=0&size=20&stageKind=OPEN&sort=createdAt,desc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
Wichtige Filter: name (ILIKE), clientId, clientName, statusId, stageId, stageKind (OPEN/WON/LOST), ownerId, search, startDateFrom/startDateTo, expectedCloseDateFrom/expectedCloseDateTo, actualCloseDateFrom/actualCloseDateTo, createdAtFrom/createdAtTo.
8. Marketing-Ereignisse (Attribution)
Zum Senden von UTM-Tags, Werbe-IDs und Traffic-Quellen verwenden Sie:
POST /api/dashboard/marketing/events
curl -X POST "$CRM_BASE_URL/api/dashboard/marketing/events" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"eventType": "lead_submitted",
"occurredAt": "2026-09-05T20:00:00Z",
"visitorId": "visitor-8b7f",
"sessionId": "session-31ac",
"leadId": "22222222-2222-2222-2222-222222222222",
"externalId": "site-form-submit-20260905-000123",
"source": "website",
"channel": "paid",
"utmSource": "google",
"utmMedium": "cpc",
"utmCampaign": "summer-consulting",
"utmContent": "banner-a",
"utmTerm": "crm consultation",
"gclid": "EAIaIQobChMI-example",
"landingUrl": "https://www.example.com/consultation",
"referrer": "https://www.google.com/",
"metadata": {
"formName": "consultation",
"pageType": "landing"
}
}'
Beispielantwort:
{
"accepted": true,
"duplicate": false,
"eventId": "33333333-3333-3333-3333-333333333333"
}
Regeln:
- Erzeugen Sie eine stabile
externalId(UUID oder eine eindeutige requestId). Ein erneutes Senden mit derselbenexternalIdfür dieselbesource/denselben Mandanten gibtduplicate: truezurück — das ist kein Fehler. - Generieren Sie bei einem Wiederholungsversuch keine neue
externalId. - Geben Sie keine personenbeziehbaren Informationen (E-Mail, Telefon, Name, Nachrichtentext) in
metadataan. Nur technische Attribute wie Formularname oder Seitentyp.
Details finden Sie in site-leads-integration-guide.md.
9. Datenexport (NDJSON)
Export-Endpunkte geben alle Datensätze des Mandanten im NDJSON-Format zurück (ein JSON-Objekt pro Zeile, durch \n getrennt).
| Endpunkt | Beschreibung |
|---|---|
GET /api/export/leads | Alle Leads des Mandanten |
GET /api/export/clients | Alle Kunden des Mandanten |
GET /api/export/contacts | Alle Kontakte des Mandanten |
curl "$CRM_BASE_URL/api/export/leads" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
Beispielantwort (Zeilenstrom):
{"id":"550e8400-e29b-41d4-a716-446655440001","message":"Website-Anfrage","quality":"WARM","statusName":"New","createdAt":"2026-08-20T10:00:00+03:00","ownerName":"Ivan Ivanov","clientName":"Romashka GmbH","contactFirstName":"Petr","contactLastName":"Petrov","leadSourceName":"Paid search"}
{"id":"550e8400-e29b-41d4-a716-446655440002","message":"Telefonanruf","quality":"COOL","statusName":"In progress","createdAt":"2026-08-19T09:00:00+03:00","ownerName":"Maria Smirnova","clientName":null}
Wichtig: NDJSON ist kein gültiges JSON-Array. Lesen Sie die Antwort zeilenweise über ReadableStream (verwenden Sie nicht JSON.parse() auf der gesamten Antwort).
10. Beispiel von Anfang bis Ende
Das folgende Szenario erstellt einen Website-Lead, verknüpft einen Kontakt und einen Kunden, erstellt einen Deal und sendet ein Marketing-Ereignis.
CRM_BASE_URL=https://crm.example.com
CRM_TOKEN="<access-token>"
# 1. Anmelden
curl -s -X POST "$CRM_BASE_URL/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username": "integration", "password": "secret123"}' | tee /tmp/login.json
CRM_TOKEN=$(jq -r '.token' /tmp/login.json)
OWNER_ID=$(curl -s "$CRM_BASE_URL/api/users/paged?page=0&size=50" \
-H "Authorization: Bearer $CRM_TOKEN" | jq -r '.content[0].id')
# 2. Kunden anlegen
curl -s -X POST "$CRM_BASE_URL/api/clients/create" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"type\": \"COMPANY\",
\"name\": \"Romashka GmbH\",
\"taxId\": \"7700000001\",
\"country\": \"RU\",
\"ownerId\": \"$OWNER_ID\",
\"authorId\": \"$OWNER_ID\"
}" | tee /tmp/client.json
CLIENT_ID=$(jq -r '.id' /tmp/client.json)
# 3. Kontakt anlegen
curl -s -X POST "$CRM_BASE_URL/api/contacts/create" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"firstName\": \"Ivan\",
\"lastName\": \"Petrov\",
\"countryCode\": \"RU\",
\"ownerId\": \"$OWNER_ID\",
\"authorId\": \"$OWNER_ID\"
}" | tee /tmp/contact.json
CONTACT_ID=$(jq -r '.id' /tmp/contact.json)
# 4. Lead anlegen
curl -s -X POST "$CRM_BASE_URL/api/leads/create" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"message\": \"Website-Anfrage\",
\"clientId\": \"$CLIENT_ID\",
\"contactId\": \"$CONTACT_ID\",
\"ownerId\": \"$OWNER_ID\",
\"authorId\": \"$OWNER_ID\",
\"quality\": \"WARM\"
}" | tee /tmp/lead.json
LEAD_ID=$(jq -r '.id' /tmp/lead.json)
# 5. Deal anlegen, der mit dem Lead verknüpft ist
curl -s -X POST "$CRM_BASE_URL/api/deals/create" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Beratung für Ivan Petrov\",
\"clientId\": \"$CLIENT_ID\",
\"leadId\": \"$LEAD_ID\",
\"contactId\": \"$CONTACT_ID\",
\"amount\": 50000.00,
\"ownerId\": \"$OWNER_ID\",
\"authorId\": \"$OWNER_ID\"
}"
# 6. Marketing-Ereignis senden
curl -s -X POST "$CRM_BASE_URL/api/dashboard/marketing/events" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"eventType\": \"lead_submitted\",
\"occurredAt\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
\"leadId\": \"$LEAD_ID\",
\"externalId\": \"request-$(uuidgen)\",
\"source\": \"website\",
\"channel\": \"direct\",
\"landingUrl\": \"https://www.example.com/form\",
\"metadata\": {\"formName\": \"consultation\"}
}"
11. Idempotenz und Fehlerbehandlung
- Stabile Kennung: Generieren Sie Ihre eigene
externalId(UUID oder requestId) für jede Übermittlung. Ein erneutes Senden derselbenexternalIddarf kein Duplikat erzeugen (bei Marketing-Ereignissen wird dies vom Server behandelt —duplicate: true). - Wiederholung mit derselben Kennung: Bei einem Netzwerkfehler wiederholen Sie mit derselben
externalId; generieren Sie keine neue. - Nicht blind duplizieren: Wenn eine Erstellungsanfrage zeitüberschreitet, überprüfen Sie zuerst das Ergebnis (mit Ihrer eigenen requestId oder durch Suchen der erstellten Entität), anstatt eine neue zu erstellen.
400: Ungültige Nutzlast — eine Wiederholung ohne Änderungen hilft nicht; korrigieren Sie die Daten.401: Access-Token abgelaufen — rufen Sie/api/auth/refreshauf und wiederholen Sie die Anfrage.403: Keine Berechtigung — überprüfen Sie Rolle und Mandant.5xx/Zeitüberschreitung: Transienter Fehler — wiederholen Sie mit derselbenexternalId(für Leads verwenden Sie eine Warteschlange).
12. Schnellstart
- Authentifizieren Sie sich über
POST /api/auth/login; speichern SietokenundrefreshToken. - Fügen Sie
Authorization: Bearer <token>zu jeder Anfrage hinzu. Bei401aktualisieren Sie über/api/auth/refresh. - Rufen Sie Referenzen ab (Benutzer/Status/Phasen/Lead-Quellen) einmalig ab und cachen Sie die UUIDs.
- Erstellen Sie Entitäten in einer logischen Reihenfolge: Kunde → Kontakt → Lead → Deal.
- Verwenden Sie Seiten-Endpunkte für Lesevorgänge mit serverseitiger Filterung und Sortierung.
- Für Exporte verwenden Sie NDJSON-Endpunkte und lesen Sie den Stream zeilenweise.
- Für Massenimporte verwenden Sie Batch-Endpunkte (
/api/leads/import/batch,/api/clients/import/batch) mit Rollback-Unterstützung. - Senden Sie Marketing-Attribution über
POST /api/dashboard/marketing/eventsmit einer stabilenexternalId. - Speichern oder übergeben Sie niemals personenbeziehbare Daten im
metadata-Feld von Marketing-Ereignissen. - Detaillierte API-Dokumentation finden Sie hier:
site-leads-integration-guide.md.
Reactive CRM