🚀 Jetzt neu: FlowAI! Ein revolutionärer Chat mit personalisierten AI-Agenten. 🌟

FlowCRM API - für moderne CRM-Integrationen

Eine moderne REST API zur Verwaltung von Kundendaten, Leads, Kanban-Boards und Timeline-Einträgen. Perfekt für CRM-Integrationen, Lead-Ingest, Automatisierung und individuelle Anwendungen.

🔐 Schnellstart

Basis-URL: https://creativeskyline.de/api/clients https://creativeskyline.de/api/clients/{uuid}/timeline https://creativeskyline.de/api/clients/{uuid}/projects https://creativeskyline.de/api/leads https://creativeskyline.de/api/lead-boards https://creativeskyline.de/api/leads/{uuid}/docs
Sicherheitshinweis
Behandeln Sie Ihren API-Key wie ein Passwort und teilen Sie ihn niemals öffentlich.
Zugriff auf die Leads-Endpunkte
Die Leads-, Board- und Lead-FlowDoc-Endpunkte erfordern zusätzlich zum FlowCRM-Modul die Leads-Unterberechtigung Ihres Teams. Ein Token ohne diese Unterberechtigung erhält HTTP 403. Die Kunden-Endpunkte sowie die FlowDoc-Endpunkte für Kunden, Kontakte und Projekte benötigen nur den FlowCRM-Modulzugriff.

1. API-Zugangsdaten abrufen

Bevor Sie die API nutzen können, benötigen Sie Ihre persönlichen Zugangsdaten: Melden Sie sich an, navigieren Sie zu Profil → API-Zugang und kopieren Sie Ihren persönlichen API-Key (pk_...).

2. Authentifizierung

Alle API-Anfragen benötigen diesen HTTP-Header. Akzeptiert werden ein persönlicher Key (pk_...) oder ein Team-API-Token (at_...):

Authorization: Bearer pk_dein_api_key
Accept: application/json

Pro Token sind bis zu 300 Anfragen pro Minute erlaubt.

🏢 Kunden-Verwaltung

Kunden auflisten

GET /api/clients

Ruft die Kunden Ihres Teams ab, ohne weitere Angabe nur die aktiven. Mit status=archived erhalten Sie die archivierten Kunden, mit status=all beide. Jeder Kunde enthält seine Tags und Quellen. Verwenden Sie für die Adressierung einzelner Kunden ausschließlich das Feld uuid.

Query-Parameter:

status string Welche Kunden geliefert werden: <code>active</code> (Standard), <code>archived</code> oder <code>all</code> für beide. Jeder andere Wert führt zu 422
per_page integer Einträge pro Seite (1 bis 500, Standard 500). Die Antwort enthält zusätzlich einen <code>meta</code>-Block mit <code>current_page</code>, <code>per_page</code>, <code>total</code> und <code>last_page</code>.
page integer Seitennummer, beginnend bei 1
GET /api/clients/search

Durchsucht die Kunden Ihres Teams nach Name, E-Mail-Adresse, Telefonnummer oder Webseite. Ohne weitere Angabe werden nur aktive Kunden gefunden, status bezieht archivierte ein.

Query-Parameter:

search string * Suchbegriff für die Kundensuche
status string Welche Kunden geliefert werden: <code>active</code> (Standard), <code>archived</code> oder <code>all</code> für beide. Jeder andere Wert führt zu 422
per_page integer Einträge pro Seite (1 bis 500, Standard 500). Die Antwort enthält zusätzlich einen <code>meta</code>-Block mit <code>current_page</code>, <code>per_page</code>, <code>total</code> und <code>last_page</code>.
page integer Seitennummer, beginnend bei 1

Kunde anlegen (Find-or-Create)

POST /api/clients

Legt einen Kunden im Team des Tokens an. Idempotent per Find-or-Create: Zuerst wird über eine gesetzte external_id gesucht, danach über die E-Mail-Adresse (teamweit, Gross-/Kleinschreibung egal). Wird ein bestehender Kunde gefunden, auch ein archivierter, gibt die Antwort diesen mit created: false zurück und synchronisiert nur die mitgesendeten tag_uuids und sources. Nur bei einer echten Neuanlage ist created: true (HTTP 201). Kollidiert die E-Mail oder external_id mit einem Kunden im Papierkorb, antwortet der Endpunkt mit HTTP 409.

Request Body:

name string * Name des Kunden
email string * E-Mail-Adresse (dient als Find-or-Create-Schlüssel)
phone string Telefonnummer
source string Einzelne Herkunftsquelle als Freitext
external_id string Maschinen-Kennung für den Upsert-Abgleich (hat Vorrang vor der E-Mail)
whmcs_client_id integer Optionale WHMCS-Kunden-ID
address_line_1 string Adresszeile 1
address_line_2 string Adresszeile 2
postal_code string Postleitzahl
city string Ort
country string Land (ISO-Code oder Name)
contact_person string Ansprechpartner
tax_id string Steuernummer
vat_id string USt-IdNr. des Kunden (max. 32 Zeichen). Für E-Rechnungen mit Reverse Charge erforderlich
tax_treatment string Steuerbehandlung: standard (mit Umsatzsteuer, Vorgabe) | reverse_charge (Belege ohne Umsatzsteuer, Steuerschuld beim Empfänger)
billing_language string Rechnungssprache des Kunden: de (Vorgabe) | en | pt. Gilt als Belegsprache neuer Rechnungen, wenn dort keine angegeben ist
tag_uuids array Liste team-eigener Tag-UUIDs aus <code>GET /api/tags</code>, die dem Kunden zugeordnet werden. Eine unbekannte, teamfremde oder gelöschte UUID führt zu HTTP 422, es wird dann nichts angelegt
sources array Liste von Herkunftsquellen als Freitext
stripe_customer_id string Optionale Stripe-Kunden-ID (Präfix cus_), wird in die Zahlungszuordnung geschrieben

Kunde aktualisieren

PATCH /api/clients/{uuid}

Aktualisiert einen team-eigenen Kunden anhand seiner UUID. Nur explizit gesendete Felder werden geschrieben, ausgelassene Felder bleiben unverändert; ein Feld mit dem Wert null gilt als nicht gesendet. Archivieren und reaktivieren: Ein inaktiver Kunde heißt in FlowSuite archiviert. status: archived archiviert den Kunden und seine Projekte, status: active reaktiviert ihn; die Projekte bleiben dabei archiviert und werden einzeln reaktiviert. Ein nach DSGVO gelöschter Kunde lässt sich nicht reaktivieren (422). Breaking Change: Der frühere numerische Pfad /api/clients/{id} wurde ersatzlos entfernt (HTTP 404); es gilt ausschließlich der UUID-Pfad.

Request Body:

name string Name des Kunden
email string E-Mail-Adresse
contact_person string Ansprechpartner
phone string Telefonnummer
website string Webseite
notes string Interne Notizen zum Kunden
status string active | archived. Archiviert oder reaktiviert den Kunden, siehe Beschreibung
tag_uuids array Tag-UUIDs, die dem Kunden zusätzlich zugeordnet werden. Vorhandene Tags bleiben erhalten; entfernt wird über <code>PATCH /api/clients/{uuid}/metadata</code> mit <code>remove_tag_uuids</code>
sources array Herkunftsquellen als Freitext, die dem Kunden zusätzlich zugeordnet werden
address_line_1 string Adresszeile 1
address_line_2 string Adresszeile 2
postal_code string Postleitzahl
city string Ort
state string Bundesland / Region
country string Land
tax_id string Steuernummer
vat_id string USt-IdNr. des Kunden (max. 32 Zeichen). Für E-Rechnungen mit Reverse Charge erforderlich
tax_treatment string Steuerbehandlung: standard | reverse_charge
billing_language string Rechnungssprache des Kunden: de | en | pt

Kunde abrufen

GET /api/clients/{uuid}

Ruft einen einzelnen Kunden Ihres Teams über seine uuid ab. Unbekannte oder teamfremde Kunden führen zu 404.

Kunde nachschlagen

GET /api/clients/lookup

Exakte Suche nach genau einem Kunden, ohne jemals einen anzulegen. Ohne weitere Angabe werden nur aktive Kunden gefunden, status bezieht archivierte ein. Mindestens einer der drei Parameter ist erforderlich. Bei mehreren Angaben gilt die feste Reihenfolge external_id, dann customer_number, dann email (ohne Beachtung der Groß- und Kleinschreibung).

Query-Parameter:

external_id string Externe Kennung des Kunden (max. 255)
customer_number string Kundennummer (max. 255)
email string E-Mail-Adresse (max. 255)
status string Welche Kunden geliefert werden: <code>active</code> (Standard), <code>archived</code> oder <code>all</code> für beide. Jeder andere Wert führt zu 422

Kunde löschen (DSGVO)

DELETE /api/clients/{uuid}

Löscht den Kunden im Sinne der DSGVO. Aufbewahrungspflichtige Buchhaltungsbelege bleiben erhalten. Ein auf diesem Weg gelöschter Kunde lässt sich nicht wiederherstellen. Soll ein Kunde nur aus dem aktiven Bestand verschwinden, archivieren Sie ihn stattdessen über PATCH /api/clients/{uuid} mit status: archived.

Query-Parameter:

include_export boolean Bei <code>true</code> enthält die Antwort zusätzlich den DSGVO-Datenexport des Kunden

Kunde wiederherstellen

POST /api/clients/{uuid}/restore

Holt einen Kunden aus dem Papierkorb zurück. Für archivierte Kunden ist dieser Endpunkt nicht gedacht, sie werden über PATCH /api/clients/{uuid} mit status: active reaktiviert. Ein nicht gelöschter Kunde wird unverändert zurückgegeben; die Antwort weist aus, ob eine Wiederherstellung stattgefunden hat. Nach DSGVO gelöschte Kunden sind davon ausgenommen.

📅 Timeline-Verwaltung

Einträge bestehen nur aus Text
Ein Timeline-Eintrag besteht aus content, Typ und Datum. Das frühere Feld title ist veraltet: Es wird beim Anlegen und Ändern weiter angenommen, aber nicht mehr als Titel gespeichert. Sendet ein Client beim Anlegen nur title, wird dieser Text als content übernommen. Einträge aus der Zeit davor liefern ihren alten Titel weiterhin im Feld title, neue Einträge eine leere Zeichenkette.
Einträge adressieren und bereinigen
Jeder Eintrag trägt eine uuid. Mit ihr wird er geändert oder gelöscht; editable sagt vorab, ob das mit dem verwendeten Schlüssel möglich ist. Wer denselben Eintrag mit demselben event_date erneut sendet, erhält den vorhandenen Eintrag mit duplicate: true zurück, statt eine Kopie anzulegen.

Timeline-Einträge auflisten

GET /api/clients/{uuid}/timeline

Ruft alle Timeline-Einträge für einen bestimmten Kunden chronologisch sortiert ab. Jeder Eintrag enthält seine uuid für Ändern und Löschen.

Timeline-Eintrag erstellen

POST /api/clients/{uuid}/timeline

Erstellt einen neuen Timeline-Eintrag für den angegebenen Kunden. Erfordert wie jede Timeline-Änderung das FlowCRM-Schreibrecht, sonst HTTP 403. Existiert bereits ein eigener Eintrag mit identischem Inhalt und identischem event_date, wird kein zweiter angelegt: Die Antwort ist dann HTTP 200 mit duplicate: true und dem vorhandenen Eintrag. Ohne event_date entsteht immer ein neuer Eintrag.

Request Body:

content string * Text des Eintrags. Ältere Clients, die nur title senden, bleiben gültig: Der Titel wird dann als Text übernommen.
event_date string Ereignisdatum (ISO 8601, Standard: jetzt)
title string Veraltet. Neben content wird er verworfen, allein gesendet wird er als content gespeichert.

Timeline-Eintrag ändern

PATCH /api/clients/{uuid}/timeline/{entry_uuid}

Korrigiert einen eigenen, manuell verfassten Eintrag. Einträge anderer Personen und automatisch erzeugte Einträge, etwa aus einer Besprechungszuordnung, antworten mit HTTP 403 und behalten ihre Quelle.

Request Body:

content string Neuer Inhalt
title string Veraltet. Wird angenommen und nicht gespeichert.
type string note, meeting, email, call, text, coffee, food, networking, party oder other
event_date string Neuer Zeitpunkt

Timeline-Eintrag löschen

DELETE /api/clients/{uuid}/timeline/{entry_uuid}

Entfernt einen eigenen, manuell verfassten Eintrag.

Mehrere Timeline-Einträge löschen

POST /api/clients/{uuid}/timeline/bulk-delete

Entfernt bis zu 200 eigene, manuell verfasste Einträge eines Kunden in einem Aufruf. Für jeden Eintrag gilt dieselbe Regel wie beim einzelnen Löschen. Fremde, automatisch erzeugte und unbekannte Einträge brechen den Aufruf nicht ab, sondern erscheinen mit ihrem Ergebnis in results.

Request Body:

entry_uuids array * Liste der zu löschenden Eintrags-UUIDs (1 bis 200, jede nur einmal)
GET /api/clients/{uuid}/timeline/search

Durchsucht die Timeline-Einträge eines Kunden nach Inhalt. Bei älteren Einträgen wird auch der frühere Titel durchsucht. Die Treffer haben dieselbe Form wie in der Liste.

Query-Parameter:

search string * Suchbegriff

👥 Kontakt-Verwaltung

Geteilte und private Kontakte
Ein Kontakt mit Teambindung (visibility: team) ist für alle Mitglieder mit der Unterberechtigung „kunden" sichtbar. Ein privater Kontakt (visibility: private) gehört nur dem anlegenden Benutzer und benötigt lediglich den FlowCRM-Modulzugriff. Wird ein privater Kontakt einem Kunden zugeordnet, wird er dadurch bewusst mit dem Team geteilt.

Kontakte auflisten

GET /api/contacts

Listet die Kontakte auf, die der verwendete Schlüssel sehen darf: geteilte Teamkontakte und die eigenen privaten Kontakte.

Query-Parameter:

search string Sucht in Vorname, Nachname, Firma sowie in hinterlegten E-Mail-Adressen und Rufnummern
client_uuid uuid Nur Kontakte des angegebenen Kunden
status string <code>active</code> (Standard), <code>archived</code> oder <code>all</code>
visibility string <code>team</code> oder <code>private</code>; ohne Angabe beides
per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Kontakt anlegen

POST /api/contacts

Legt einen Kontakt an. Mindestens Vor- oder Nachname ist erforderlich. Wird client_uuid gesetzt, entsteht direkt ein Teamkontakt beim angegebenen Kunden.

Request Body:

first_name string Vorname
last_name string Nachname
salutation string Herr, Frau, Divers, Firma oder keine
title string Titel, etwa Dr. oder Prof.
job_title string Position im Unternehmen
company string Firmenname
description string Freitext zur Person
birth_day integer Geburtstag, 1 bis 31
birth_month integer Geburtsmonat, 1 bis 12
birth_year integer Geburtsjahr
client_uuid uuid Kunde, zu dem der Kontakt gehört
visibility string <code>team</code> (Standard) oder <code>private</code>

Kontakt abrufen

GET /api/contacts/{uuid}

Liefert einen Kontakt mit allen Wertesammlungen: E-Mail-Adressen, Rufnummern, Anschriften, Links, Profile, Daten und Freifelder.

Kontakt aktualisieren

PATCH /api/contacts/{uuid}

Ändert nur die gesendeten Felder. Über status lässt sich ein Kontakt archivieren und wieder aktivieren. Vor- und Nachname dürfen nicht gleichzeitig leer werden.

Request Body:

first_name string Vorname
last_name string Nachname
salutation string Herr, Frau, Divers, Firma oder keine
title string Titel
job_title string Position im Unternehmen
company string Firmenname
description string Freitext zur Person
birth_day integer Geburtstag
birth_month integer Geburtsmonat
birth_year integer Geburtsjahr
status string <code>active</code> oder <code>archived</code>

Kontakt löschen

DELETE /api/contacts/{uuid}

Verschiebt den Kontakt in den Papierkorb, genau wie die Kontaktliste in der Oberfläche. Wer den Kontakt nur vorübergehend ausblenden möchte, setzt stattdessen status: archived.

Kontakt einem Kunden zuordnen

PUT /api/contacts/{uuid}/client

Ordnet den Kontakt einem Kunden zu oder löst die Zuordnung mit client_uuid: null. Ein bisher privater Kontakt wird dabei bewusst mit dem Team geteilt. Ist beim Kunden noch kein Ansprechpartner hinterlegt, übernimmt er den Namen dieses Kontakts.

Request Body:

client_uuid uuid * Kunde, oder <code>null</code> zum Lösen der Zuordnung

Kontaktwert hinzufügen

POST /api/contacts/{uuid}/values/{collection}

Fügt genau einen Wert einer Sammlung hinzu. Mögliche Sammlungen: emails, phones, addresses, links, socials, dates, customs. Pro Sammlung kann höchstens ein Wert is_primary sein; ein neuer Hauptwert löst den bisherigen ab.

Request Body:

label string * Bezeichnung, etwa Arbeit oder Privat. Bei <code>socials</code> stattdessen <code>platform</code>
email string Nur bei <code>emails</code>
phone string Nur bei <code>phones</code>
url string Nur bei <code>links</code> und <code>socials</code>
date string Nur bei <code>dates</code>, im Format JJJJ-MM-TT
value string Nur bei <code>customs</code>
is_primary boolean Nur bei <code>emails</code>, <code>phones</code> und <code>addresses</code>

Kontaktwert ändern

PATCH /api/contacts/{uuid}/values/{collection}/{value_uuid}

Ändert genau einen Wert. Es müssen nur die tatsächlich geänderten Felder gesendet werden. Bei Anschriften werden hinterlegte Koordinaten verworfen, sobald sich ein Adressfeld ändert.

Request Body:

label string Bezeichnung des Werts
is_primary boolean Macht den Wert zum Hauptwert der Sammlung

Kontaktwert entfernen

DELETE /api/contacts/{uuid}/values/{collection}/{value_uuid}

Entfernt genau einen Wert aus der angegebenen Sammlung.

📁 Projekt-Verwaltung

Berechtigung und Archivierung
Projekte erfordern zusätzlich zum FlowCRM-Modul die Unterberechtigung „projekte". Ein Projekt wird nie gelöscht: DELETE archiviert es, weil Zeiterfassung, Rechnungen und Aufgabenboards weiter darauf verweisen. Ein PATCH mit status: active holt es zurück.

Kundenprojekte auflisten

GET /api/clients/{uuid}/projects

Listet alle Projekte des angegebenen Kunden auf, inklusive Status, Beschreibung und einem modules-Array mit aktiven Integrationen (flowcall, flowtime, flowtasks).

Alle Projekte auflisten

GET /api/projects

Listet die Projekte des Teams über alle Kunden hinweg.

Query-Parameter:

client_uuid uuid Nur Projekte des angegebenen Kunden
search string Sucht im Projektnamen
status string <code>active</code> (Standard), <code>archived</code> oder <code>all</code>
per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Projekt anlegen

POST /api/projects

Legt ein Projekt beim angegebenen Kunden an.

Request Body:

name string * Name des Projekts
client_uuid uuid * Kunde, zu dem das Projekt gehört
description string Beschreibung
notes string Interne Notizen
budget_type string <code>hours</code> oder <code>amount</code>
budget_value number Budgetwert
budget_currency string Währung als dreistelliger Code
budget_interval string <code>total</code>, <code>monthly</code> oder <code>daily</code>
budget_enforcement string <code>soft</code> oder <code>hard</code>

Projekt beim Kunden anlegen

POST /api/clients/{uuid}/projects

Wie „Projekt anlegen", der Kunde steht jedoch bereits im Pfad und muss nicht im Rumpf wiederholt werden.

Request Body:

name string * Name des Projekts
description string Beschreibung
notes string Interne Notizen

Projekt abrufen

GET /api/projects/{uuid}

Liefert ein einzelnes Projekt samt Budgetangaben und aktiven Modulen.

Projekt aktualisieren

PATCH /api/projects/{uuid}

Ändert nur die gesendeten Felder. Über client_uuid lässt sich ein Projekt einem anderen Kunden desselben Teams zuordnen, über status archivieren und wieder aktivieren.

Request Body:

name string Name des Projekts
description string Beschreibung
notes string Interne Notizen
client_uuid uuid Neuer Kunde des Projekts
status string <code>active</code> oder <code>archived</code>
budget_type string <code>hours</code> oder <code>amount</code>
budget_value number Budgetwert
budget_currency string Währung als dreistelliger Code
budget_interval string <code>total</code>, <code>monthly</code> oder <code>daily</code>
budget_enforcement string <code>soft</code> oder <code>hard</code>

Projekt archivieren

DELETE /api/projects/{uuid}

Archiviert das Projekt. Es bleibt erhalten, weil Zeiterfassung, Rechnungen und Aufgabenboards weiter darauf verweisen.

🗂️ Projekt-Timeline

Projekt-Timeline abrufen

GET /api/clients/{uuid}/projects/{project_uuid}/timeline

Ruft alle Timeline-Einträge für ein bestimmtes Projekt ab, analog zur Kunden-Timeline und in derselben Form, einschließlich uuid je Eintrag.

Projekt-Timeline-Eintrag erstellen

POST /api/clients/{uuid}/projects/{project_uuid}/timeline

Hängt einen Eintrag an die Projekt-Timeline an. Verfasser und Team ergeben sich aus dem Schlüssel und können nicht im Rumpf gesetzt werden. Ein eigener Eintrag mit identischem Inhalt, Typ und event_date wird nicht doppelt angelegt; die Antwort ist dann HTTP 200 mit duplicate: true.

Request Body:

content string * Inhalt des Eintrags
title string Veraltet. Wird angenommen und nicht gespeichert.
type string note (Standard), meeting, email, call, text, coffee, food, networking, party oder other
event_date string Zeitpunkt des Ereignisses; ohne Angabe jetzt

Projekt-Timeline-Eintrag ändern

PATCH /api/clients/{uuid}/projects/{project_uuid}/timeline/{entry_uuid}

Korrigiert einen eigenen, manuell verfassten Eintrag. Einträge anderer Personen und automatisch erzeugte Einträge antworten mit HTTP 403.

Request Body:

content string Neuer Inhalt
title string Veraltet. Wird angenommen und nicht gespeichert.
type string Neuer Typ
event_date string Neuer Zeitpunkt

Projekt-Timeline-Eintrag löschen

DELETE /api/clients/{uuid}/projects/{project_uuid}/timeline/{entry_uuid}

Entfernt einen eigenen, manuell verfassten Eintrag.

Mehrere Projekt-Timeline-Einträge löschen

POST /api/clients/{uuid}/projects/{project_uuid}/timeline/bulk-delete

Entfernt bis zu 200 eigene, manuell verfasste Einträge eines Projekts in einem Aufruf. Regeln und Antwort entsprechen dem Sammel-Löschen der Kunden-Timeline.

Request Body:

entry_uuids array * Liste der zu löschenden Eintrags-UUIDs (1 bis 200, jede nur einmal)

🗃️ Aufgaben, Metadaten und Dateien

Gleiche Endpunkte auf drei Datensatzarten
Aufgaben, Metadaten und Dateien gibt es in identischer Form unter /api/clients, /api/contacts und /api/projects. Projekte kennen keine Tags und keine Quellen; ein solcher Versuch antwortet mit HTTP 422. Private Kontakte nehmen keine CRM-Aufgaben auf.
Dateien kommen als Upload
Dateien werden ausschließlich als multipart/form-data übertragen. Es gibt bewusst keinen Weg, dem Server eine Adresse zum Herunterladen zu nennen. Der Rückweg läuft über einen kurzlebigen Abruflink, damit große Dateien nicht zweimal durch die Anwendung wandern.

Aufgaben auflisten (Kunden)

GET /api/clients/{uuid}/todos

Listet die Aufgaben des Datensatzes auf. Erledigte Aufgaben erscheinen nur mit include_completed=1.

Query-Parameter:

include_completed boolean Erledigte Aufgaben mit ausgeben
per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Aufgabe anlegen (Kunden)

POST /api/clients/{uuid}/todos

Legt eine Aufgabe am Datensatz an. Zuständige werden über ihre Benutzer-UUID benannt und müssen zum Team des Schlüssels gehören. Mit recurring_interval entsteht eine Serie, also eine Aufgabe, die sich nach jedem Erledigen selbst auf den nächsten Termin setzt. Eine Serie braucht ein due_date und kann nicht bereits erledigt angelegt werden; beides antwortet sonst mit HTTP 422.

Request Body:

title string * Titel der Aufgabe
description string Beschreibung
due_date string Fälligkeit im Format JJJJ-MM-TT
priority string <code>high</code>, <code>medium</code> (Standard) oder <code>low</code>
completed boolean Direkt als erledigt anlegen. Nicht zusammen mit <code>recurring_interval</code>
recurring_interval string Wiederholung der Aufgabe: <code>daily</code>, <code>every_2_days</code>, <code>weekly</code>, <code>every_2_weeks</code>, <code>monthly</code>, <code>every_2_months</code>, <code>quarterly</code>, <code>half_yearly</code> oder <code>yearly</code>. Erfordert <code>due_date</code>
assigned_user_uuids array Benutzer-UUIDs der Zuständigen

Aufgabe aktualisieren (Kunden)

PATCH /api/clients/{uuid}/todos/{todo_uuid}

Ändert nur die gesendeten Felder. Über completed wird eine Aufgabe erledigt oder wieder geöffnet. Ein weggelassenes assigned_user_uuids lässt die Zuständigkeit unverändert, ein leeres Feld hebt sie auf. Bei einer Serie (Aufgabe mit recurring_interval) erledigt completed: true nur die aktuelle Wiederholung: Die Aufgabe bleibt offen, ihr due_date rückt um ein Intervall vor, und die erledigte Wiederholung wird als eigene, erledigte Aufgabe abgelegt. data ist immer die adressierte Aufgabe, bei einer Serie also weiterhin mit completed: false und dem neuen due_date. Die erledigte Wiederholung steht daneben im Antwortfeld completed_occurrence; in allen anderen Fällen ist es null. Wieder öffnen (completed: false) wirkt auf einfache Aufgaben und auf erledigte Wiederholungen, die Serie selbst ist nie erledigt. Das due_date einer Serie lässt sich nicht direkt ändern (HTTP 422). Ein wiederholter Aufruf würde auch die nächste Wiederholung erledigen: Wer expected_due_date mitsendet, erhält stattdessen HTTP 409 mit dem aktuellen Termin in current_due_date, sobald die Serie bereits weitergerückt ist.

Request Body:

title string Titel der Aufgabe
description string Beschreibung
due_date string Fälligkeit im Format JJJJ-MM-TT
priority string <code>high</code>, <code>medium</code> oder <code>low</code>
completed boolean Erledigt-Zustand. Bei einer Serie erledigt <code>true</code> nur die aktuelle Wiederholung
recurring_interval string Wiederholung der Aufgabe: <code>daily</code>, <code>every_2_days</code>, <code>weekly</code>, <code>every_2_weeks</code>, <code>monthly</code>, <code>every_2_months</code>, <code>quarterly</code>, <code>half_yearly</code> oder <code>yearly</code>. Erfordert ein <code>due_date</code>; <code>null</code> beendet die Serie
expected_due_date string Nur beim Erledigen einer Serie: der Termin im Format JJJJ-MM-TT, den der Aufrufer gerade sieht. Weicht er vom aktuellen <code>due_date</code> ab, antwortet der Endpunkt mit HTTP 409 und erledigt nichts
assigned_user_uuids array Benutzer-UUIDs der Zuständigen

Aufgabe löschen (Kunden)

DELETE /api/clients/{uuid}/todos/{todo_uuid}

Entfernt die Aufgabe.

Metadaten abrufen (Kunden)

GET /api/clients/{uuid}/metadata

Liefert Tags, Quellen und Zusatzfelder des Datensatzes sowie die im Team verfügbaren Tags und Zusatzfeld-Definitionen. Zusatzfelder vom Typ reference werden mit der UUID und dem Namen des Ziels beantwortet. Jede Definition nennt ihren type: text, textarea, number, url, dropdown, reference, date oder currency. Bei number und currency steht in decimals die Zahl der erlaubten Nachkommastellen, bei currency zusätzlich in currency der feste ISO-4217-Code des Feldes; für alle anderen Typen sind beide Angaben null. Werte vom Typ date haben das Format JJJJ-MM-TT, Werte vom Typ currency sind eine Dezimalzahl mit Punkt als Dezimaltrenner und nennen den Währungscode in currency.

Metadaten ändern (Kunden)

PATCH /api/clients/{uuid}/metadata

Ergänzt oder entfernt gezielt einzelne Tags, Quellen und Zusatzfeldwerte. Nichts wird als Ganzes ersetzt, ein leerer Wert löscht das jeweilige Zusatzfeld. Zusatzfelder werden über definition_uuid oder ihren eindeutigen name benannt; bei Referenzfeldern ist der Wert die UUID des Ziels. Felder vom Typ date erwarten ein Datum im Format JJJJ-MM-TT, Felder vom Typ currency einen Betrag als Zahl oder Zahl-String ohne Währungszeichen und ohne Tausendertrennzeichen. Der Betrag darf höchstens so viele Nachkommastellen haben, wie die Definition in decimals nennt, und wird auf diese Stellenzahl aufgefüllt gespeichert. Ein Wert, der nicht zum Typ passt, führt zu HTTP 422 mit dem Feldbezug custom_fields.{index}; es wird dann nichts geändert.

Request Body:

add_tag_uuids array Tags, die ergänzt werden
remove_tag_uuids array Tags, die entfernt werden
add_sources array Quellen, die ergänzt werden
remove_sources array Quellen, die entfernt werden
custom_fields array Einträge aus <code>definition_uuid</code> oder <code>name</code> und <code>value</code>. Bei <code>date</code> ist <code>value</code> ein Datum wie <code>"2026-12-31"</code>, bei <code>currency</code> ein Betrag wie <code>12500.5</code> oder <code>"12500.50"</code>

Dateien auflisten (Kunden)

GET /api/clients/{uuid}/files

Listet die Dateien des Datensatzes auf. has_document_source zeigt an, ob die Datei aus Markdown erzeugt wurde und damit überarbeitet statt ersetzt werden kann.

Query-Parameter:

per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Datei hochladen (Kunden)

POST /api/clients/{uuid}/files

Hängt eine hochgeladene Datei an den Datensatz. Übertragung als multipart/form-data, höchstens 50 MB. Nicht zugelassene Dateitypen antworten mit HTTP 422.

Request Body:

file file * Die hochzuladende Datei
name string Abweichender Dateiname

Abruflink für eine Datei (Kunden)

GET /api/clients/{uuid}/files/{file_uuid}/download

Liefert einen kurzlebigen Abruflink samt Gültigkeitsdauer in Sekunden. Die Antwort enthält den Link, nicht die Bytes.

Text einer Datei lesen (Kunden)

GET /api/clients/{uuid}/files/{file_uuid}/text

Gibt den bereits extrahierten Text der Datei in Abschnitten von 20.000 Zeichen zurück. Der Endpunkt liest nur; er stößt keine neue Extraktion an.

Query-Parameter:

offset integer Startposition im Text; <code>next_offset</code> der Antwort führt zum nächsten Abschnitt

Dokument aus Markdown erzeugen (Kunden)

POST /api/clients/{uuid}/documents

Erzeugt aus Markdown ein PDF oder ein Word-Dokument und legt es am Datensatz ab. Mit file_uuid wird eine bestehende, ebenfalls so erzeugte Fassung überarbeitet statt eine zweite daneben zu legen.

Request Body:

title string * Titel und zugleich Dateiname ohne Endung
source_markdown string * Der Inhalt als Markdown
format string * <code>pdf</code> oder <code>docx</code>
file_uuid uuid Bestehende Fassung, die ersetzt wird

Aufgaben auflisten (Kontakte)

GET /api/contacts/{uuid}/todos

Listet die Aufgaben des Datensatzes auf. Erledigte Aufgaben erscheinen nur mit include_completed=1.

Query-Parameter:

include_completed boolean Erledigte Aufgaben mit ausgeben
per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Aufgabe anlegen (Kontakte)

POST /api/contacts/{uuid}/todos

Legt eine Aufgabe am Datensatz an. Zuständige werden über ihre Benutzer-UUID benannt und müssen zum Team des Schlüssels gehören. Mit recurring_interval entsteht eine Serie, also eine Aufgabe, die sich nach jedem Erledigen selbst auf den nächsten Termin setzt. Eine Serie braucht ein due_date und kann nicht bereits erledigt angelegt werden; beides antwortet sonst mit HTTP 422.

Request Body:

title string * Titel der Aufgabe
description string Beschreibung
due_date string Fälligkeit im Format JJJJ-MM-TT
priority string <code>high</code>, <code>medium</code> (Standard) oder <code>low</code>
completed boolean Direkt als erledigt anlegen. Nicht zusammen mit <code>recurring_interval</code>
recurring_interval string Wiederholung der Aufgabe: <code>daily</code>, <code>every_2_days</code>, <code>weekly</code>, <code>every_2_weeks</code>, <code>monthly</code>, <code>every_2_months</code>, <code>quarterly</code>, <code>half_yearly</code> oder <code>yearly</code>. Erfordert <code>due_date</code>
assigned_user_uuids array Benutzer-UUIDs der Zuständigen

Aufgabe aktualisieren (Kontakte)

PATCH /api/contacts/{uuid}/todos/{todo_uuid}

Ändert nur die gesendeten Felder. Über completed wird eine Aufgabe erledigt oder wieder geöffnet. Ein weggelassenes assigned_user_uuids lässt die Zuständigkeit unverändert, ein leeres Feld hebt sie auf. Bei einer Serie (Aufgabe mit recurring_interval) erledigt completed: true nur die aktuelle Wiederholung: Die Aufgabe bleibt offen, ihr due_date rückt um ein Intervall vor, und die erledigte Wiederholung wird als eigene, erledigte Aufgabe abgelegt. data ist immer die adressierte Aufgabe, bei einer Serie also weiterhin mit completed: false und dem neuen due_date. Die erledigte Wiederholung steht daneben im Antwortfeld completed_occurrence; in allen anderen Fällen ist es null. Wieder öffnen (completed: false) wirkt auf einfache Aufgaben und auf erledigte Wiederholungen, die Serie selbst ist nie erledigt. Das due_date einer Serie lässt sich nicht direkt ändern (HTTP 422). Ein wiederholter Aufruf würde auch die nächste Wiederholung erledigen: Wer expected_due_date mitsendet, erhält stattdessen HTTP 409 mit dem aktuellen Termin in current_due_date, sobald die Serie bereits weitergerückt ist.

Request Body:

title string Titel der Aufgabe
description string Beschreibung
due_date string Fälligkeit im Format JJJJ-MM-TT
priority string <code>high</code>, <code>medium</code> oder <code>low</code>
completed boolean Erledigt-Zustand. Bei einer Serie erledigt <code>true</code> nur die aktuelle Wiederholung
recurring_interval string Wiederholung der Aufgabe: <code>daily</code>, <code>every_2_days</code>, <code>weekly</code>, <code>every_2_weeks</code>, <code>monthly</code>, <code>every_2_months</code>, <code>quarterly</code>, <code>half_yearly</code> oder <code>yearly</code>. Erfordert ein <code>due_date</code>; <code>null</code> beendet die Serie
expected_due_date string Nur beim Erledigen einer Serie: der Termin im Format JJJJ-MM-TT, den der Aufrufer gerade sieht. Weicht er vom aktuellen <code>due_date</code> ab, antwortet der Endpunkt mit HTTP 409 und erledigt nichts
assigned_user_uuids array Benutzer-UUIDs der Zuständigen

Aufgabe löschen (Kontakte)

DELETE /api/contacts/{uuid}/todos/{todo_uuid}

Entfernt die Aufgabe.

Metadaten abrufen (Kontakte)

GET /api/contacts/{uuid}/metadata

Liefert Tags, Quellen und Zusatzfelder des Datensatzes sowie die im Team verfügbaren Tags und Zusatzfeld-Definitionen. Zusatzfelder vom Typ reference werden mit der UUID und dem Namen des Ziels beantwortet. Jede Definition nennt ihren type: text, textarea, number, url, dropdown, reference, date oder currency. Bei number und currency steht in decimals die Zahl der erlaubten Nachkommastellen, bei currency zusätzlich in currency der feste ISO-4217-Code des Feldes; für alle anderen Typen sind beide Angaben null. Werte vom Typ date haben das Format JJJJ-MM-TT, Werte vom Typ currency sind eine Dezimalzahl mit Punkt als Dezimaltrenner und nennen den Währungscode in currency.

Metadaten ändern (Kontakte)

PATCH /api/contacts/{uuid}/metadata

Ergänzt oder entfernt gezielt einzelne Tags, Quellen und Zusatzfeldwerte. Nichts wird als Ganzes ersetzt, ein leerer Wert löscht das jeweilige Zusatzfeld. Zusatzfelder werden über definition_uuid oder ihren eindeutigen name benannt; bei Referenzfeldern ist der Wert die UUID des Ziels. Felder vom Typ date erwarten ein Datum im Format JJJJ-MM-TT, Felder vom Typ currency einen Betrag als Zahl oder Zahl-String ohne Währungszeichen und ohne Tausendertrennzeichen. Der Betrag darf höchstens so viele Nachkommastellen haben, wie die Definition in decimals nennt, und wird auf diese Stellenzahl aufgefüllt gespeichert. Ein Wert, der nicht zum Typ passt, führt zu HTTP 422 mit dem Feldbezug custom_fields.{index}; es wird dann nichts geändert.

Request Body:

add_tag_uuids array Tags, die ergänzt werden
remove_tag_uuids array Tags, die entfernt werden
add_sources array Quellen, die ergänzt werden
remove_sources array Quellen, die entfernt werden
custom_fields array Einträge aus <code>definition_uuid</code> oder <code>name</code> und <code>value</code>. Bei <code>date</code> ist <code>value</code> ein Datum wie <code>"2026-12-31"</code>, bei <code>currency</code> ein Betrag wie <code>12500.5</code> oder <code>"12500.50"</code>

Dateien auflisten (Kontakte)

GET /api/contacts/{uuid}/files

Listet die Dateien des Datensatzes auf. has_document_source zeigt an, ob die Datei aus Markdown erzeugt wurde und damit überarbeitet statt ersetzt werden kann.

Query-Parameter:

per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Datei hochladen (Kontakte)

POST /api/contacts/{uuid}/files

Hängt eine hochgeladene Datei an den Datensatz. Übertragung als multipart/form-data, höchstens 50 MB. Nicht zugelassene Dateitypen antworten mit HTTP 422.

Request Body:

file file * Die hochzuladende Datei
name string Abweichender Dateiname

Abruflink für eine Datei (Kontakte)

GET /api/contacts/{uuid}/files/{file_uuid}/download

Liefert einen kurzlebigen Abruflink samt Gültigkeitsdauer in Sekunden. Die Antwort enthält den Link, nicht die Bytes.

Text einer Datei lesen (Kontakte)

GET /api/contacts/{uuid}/files/{file_uuid}/text

Gibt den bereits extrahierten Text der Datei in Abschnitten von 20.000 Zeichen zurück. Der Endpunkt liest nur; er stößt keine neue Extraktion an.

Query-Parameter:

offset integer Startposition im Text; <code>next_offset</code> der Antwort führt zum nächsten Abschnitt

Dokument aus Markdown erzeugen (Kontakte)

POST /api/contacts/{uuid}/documents

Erzeugt aus Markdown ein PDF oder ein Word-Dokument und legt es am Datensatz ab. Mit file_uuid wird eine bestehende, ebenfalls so erzeugte Fassung überarbeitet statt eine zweite daneben zu legen.

Request Body:

title string * Titel und zugleich Dateiname ohne Endung
source_markdown string * Der Inhalt als Markdown
format string * <code>pdf</code> oder <code>docx</code>
file_uuid uuid Bestehende Fassung, die ersetzt wird

Aufgaben auflisten (Projekte)

GET /api/projects/{uuid}/todos

Listet die Aufgaben des Datensatzes auf. Erledigte Aufgaben erscheinen nur mit include_completed=1.

Query-Parameter:

include_completed boolean Erledigte Aufgaben mit ausgeben
per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Aufgabe anlegen (Projekte)

POST /api/projects/{uuid}/todos

Legt eine Aufgabe am Datensatz an. Zuständige werden über ihre Benutzer-UUID benannt und müssen zum Team des Schlüssels gehören. Mit recurring_interval entsteht eine Serie, also eine Aufgabe, die sich nach jedem Erledigen selbst auf den nächsten Termin setzt. Eine Serie braucht ein due_date und kann nicht bereits erledigt angelegt werden; beides antwortet sonst mit HTTP 422.

Request Body:

title string * Titel der Aufgabe
description string Beschreibung
due_date string Fälligkeit im Format JJJJ-MM-TT
priority string <code>high</code>, <code>medium</code> (Standard) oder <code>low</code>
completed boolean Direkt als erledigt anlegen. Nicht zusammen mit <code>recurring_interval</code>
recurring_interval string Wiederholung der Aufgabe: <code>daily</code>, <code>every_2_days</code>, <code>weekly</code>, <code>every_2_weeks</code>, <code>monthly</code>, <code>every_2_months</code>, <code>quarterly</code>, <code>half_yearly</code> oder <code>yearly</code>. Erfordert <code>due_date</code>
assigned_user_uuids array Benutzer-UUIDs der Zuständigen

Aufgabe aktualisieren (Projekte)

PATCH /api/projects/{uuid}/todos/{todo_uuid}

Ändert nur die gesendeten Felder. Über completed wird eine Aufgabe erledigt oder wieder geöffnet. Ein weggelassenes assigned_user_uuids lässt die Zuständigkeit unverändert, ein leeres Feld hebt sie auf. Bei einer Serie (Aufgabe mit recurring_interval) erledigt completed: true nur die aktuelle Wiederholung: Die Aufgabe bleibt offen, ihr due_date rückt um ein Intervall vor, und die erledigte Wiederholung wird als eigene, erledigte Aufgabe abgelegt. data ist immer die adressierte Aufgabe, bei einer Serie also weiterhin mit completed: false und dem neuen due_date. Die erledigte Wiederholung steht daneben im Antwortfeld completed_occurrence; in allen anderen Fällen ist es null. Wieder öffnen (completed: false) wirkt auf einfache Aufgaben und auf erledigte Wiederholungen, die Serie selbst ist nie erledigt. Das due_date einer Serie lässt sich nicht direkt ändern (HTTP 422). Ein wiederholter Aufruf würde auch die nächste Wiederholung erledigen: Wer expected_due_date mitsendet, erhält stattdessen HTTP 409 mit dem aktuellen Termin in current_due_date, sobald die Serie bereits weitergerückt ist.

Request Body:

title string Titel der Aufgabe
description string Beschreibung
due_date string Fälligkeit im Format JJJJ-MM-TT
priority string <code>high</code>, <code>medium</code> oder <code>low</code>
completed boolean Erledigt-Zustand. Bei einer Serie erledigt <code>true</code> nur die aktuelle Wiederholung
recurring_interval string Wiederholung der Aufgabe: <code>daily</code>, <code>every_2_days</code>, <code>weekly</code>, <code>every_2_weeks</code>, <code>monthly</code>, <code>every_2_months</code>, <code>quarterly</code>, <code>half_yearly</code> oder <code>yearly</code>. Erfordert ein <code>due_date</code>; <code>null</code> beendet die Serie
expected_due_date string Nur beim Erledigen einer Serie: der Termin im Format JJJJ-MM-TT, den der Aufrufer gerade sieht. Weicht er vom aktuellen <code>due_date</code> ab, antwortet der Endpunkt mit HTTP 409 und erledigt nichts
assigned_user_uuids array Benutzer-UUIDs der Zuständigen

Aufgabe löschen (Projekte)

DELETE /api/projects/{uuid}/todos/{todo_uuid}

Entfernt die Aufgabe.

Metadaten abrufen (Projekte)

GET /api/projects/{uuid}/metadata

Liefert Tags, Quellen und Zusatzfelder des Datensatzes sowie die im Team verfügbaren Tags und Zusatzfeld-Definitionen. Zusatzfelder vom Typ reference werden mit der UUID und dem Namen des Ziels beantwortet. Jede Definition nennt ihren type: text, textarea, number, url, dropdown, reference, date oder currency. Bei number und currency steht in decimals die Zahl der erlaubten Nachkommastellen, bei currency zusätzlich in currency der feste ISO-4217-Code des Feldes; für alle anderen Typen sind beide Angaben null. Werte vom Typ date haben das Format JJJJ-MM-TT, Werte vom Typ currency sind eine Dezimalzahl mit Punkt als Dezimaltrenner und nennen den Währungscode in currency.

Metadaten ändern (Projekte)

PATCH /api/projects/{uuid}/metadata

Ergänzt oder entfernt gezielt einzelne Tags, Quellen und Zusatzfeldwerte. Nichts wird als Ganzes ersetzt, ein leerer Wert löscht das jeweilige Zusatzfeld. Zusatzfelder werden über definition_uuid oder ihren eindeutigen name benannt; bei Referenzfeldern ist der Wert die UUID des Ziels. Felder vom Typ date erwarten ein Datum im Format JJJJ-MM-TT, Felder vom Typ currency einen Betrag als Zahl oder Zahl-String ohne Währungszeichen und ohne Tausendertrennzeichen. Der Betrag darf höchstens so viele Nachkommastellen haben, wie die Definition in decimals nennt, und wird auf diese Stellenzahl aufgefüllt gespeichert. Ein Wert, der nicht zum Typ passt, führt zu HTTP 422 mit dem Feldbezug custom_fields.{index}; es wird dann nichts geändert.

Request Body:

add_tag_uuids array Tags, die ergänzt werden
remove_tag_uuids array Tags, die entfernt werden
add_sources array Quellen, die ergänzt werden
remove_sources array Quellen, die entfernt werden
custom_fields array Einträge aus <code>definition_uuid</code> oder <code>name</code> und <code>value</code>. Bei <code>date</code> ist <code>value</code> ein Datum wie <code>"2026-12-31"</code>, bei <code>currency</code> ein Betrag wie <code>12500.5</code> oder <code>"12500.50"</code>

Dateien auflisten (Projekte)

GET /api/projects/{uuid}/files

Listet die Dateien des Datensatzes auf. has_document_source zeigt an, ob die Datei aus Markdown erzeugt wurde und damit überarbeitet statt ersetzt werden kann.

Query-Parameter:

per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Datei hochladen (Projekte)

POST /api/projects/{uuid}/files

Hängt eine hochgeladene Datei an den Datensatz. Übertragung als multipart/form-data, höchstens 50 MB. Nicht zugelassene Dateitypen antworten mit HTTP 422.

Request Body:

file file * Die hochzuladende Datei
name string Abweichender Dateiname

Abruflink für eine Datei (Projekte)

GET /api/projects/{uuid}/files/{file_uuid}/download

Liefert einen kurzlebigen Abruflink samt Gültigkeitsdauer in Sekunden. Die Antwort enthält den Link, nicht die Bytes.

Text einer Datei lesen (Projekte)

GET /api/projects/{uuid}/files/{file_uuid}/text

Gibt den bereits extrahierten Text der Datei in Abschnitten von 20.000 Zeichen zurück. Der Endpunkt liest nur; er stößt keine neue Extraktion an.

Query-Parameter:

offset integer Startposition im Text; <code>next_offset</code> der Antwort führt zum nächsten Abschnitt

Dokument aus Markdown erzeugen (Projekte)

POST /api/projects/{uuid}/documents

Erzeugt aus Markdown ein PDF oder ein Word-Dokument und legt es am Datensatz ab. Mit file_uuid wird eine bestehende, ebenfalls so erzeugte Fassung überarbeitet statt eine zweite daneben zu legen.

Request Body:

title string * Titel und zugleich Dateiname ohne Endung
source_markdown string * Der Inhalt als Markdown
format string * <code>pdf</code> oder <code>docx</code>
file_uuid uuid Bestehende Fassung, die ersetzt wird

🏷️ Tags

Tags werden über ihre UUID gesetzt
Kunden und Leads nehmen Tags über das Feld tag_uuids an, Kunden und Kontakte außerdem über PATCH .../metadata mit add_tag_uuids und remove_tag_uuids. Ein Feld tags mit Tag-Namen gibt es nicht; es wird mit HTTP 422 abgelehnt, damit kein Aufruf scheinbar erfolgreich ist, ohne etwas zu speichern. Die UUIDs liefert GET /api/tags, ein fehlendes Tag legt POST /api/tags an. Unbekannte, teamfremde und gelöschte Tag-UUIDs führen zu HTTP 422.

Tags auflisten

GET /api/tags

Listet die Tags Ihres Teams alphabetisch nach Titel. Die Liste dient dazu, die uuid eines Tags zu ermitteln, bevor es an einem Kunden, Kontakt oder Lead gesetzt wird. Es genügt der FlowCRM-Zugriff; FlowSend wird dafür nicht benötigt.

Query-Parameter:

search string Liefert nur Tags, deren Titel den Text enthält
per_page integer Einträge pro Seite (1 bis 200, Standard 50)
page integer Seitennummer, beginnend bei 1

Tag anlegen (Find-or-Create)

POST /api/tags

Legt ein Tag für Ihr Team an. Der Aufruf lässt sich gefahrlos wiederholen: Gibt es bereits ein Tag mit diesem Namen, wird es mit created: false und HTTP 200 zurückgegeben; Groß- und Kleinschreibung sowie Sonderzeichen spielen beim Vergleich keine Rolle. Ein zuvor gelöschtes Tag gleichen Namens wird zurückgeholt (restored: true, HTTP 201), ohne seine früheren Zuordnungen. Eine echte Neuanlage antwortet mit created: true und HTTP 201. Erfordert das FlowCRM-Schreibrecht. Umbenennen und Löschen von Tags bleibt der FlowSend-API vorbehalten.

Request Body:

title string * Name des Tags, höchstens 100 Zeichen, mit mindestens einem Buchstaben oder einer Ziffer
description string Beschreibung, höchstens 1.000 Zeichen. Wird nur bei einer Neuanlage gespeichert

🎯 Leads-Verwaltung

Berechtigung
Alle Leads-Endpunkte erfordern den FlowCRM-Modulzugriff plus die Leads-Unterberechtigung Ihres Teams.
Idempotentes Anlegen
Senden Sie beim Anlegen ein Paar aus external_source und external_id. Ein zweiter POST mit demselben Paar aktualisiert den bestehenden Lead (Upsert), statt ein Duplikat zu erzeugen. Dabei werden nur die tatsächlich gesendeten Felder überschrieben.

Leads sind team-eigen: team_id und status werden serverseitig gesetzt und nie aus dem Request übernommen. Ein neuer Lead startet im Standard-Status des Teams. Der Status wird ausschliesslich über den eigenen Status-Endpunkt geändert, der Systemstatus converted nur über die Konvertierung.

Idempotenz: Trifft ein POST über external_source + external_id auf einen bestehenden Lead, werden nur die im Payload enthaltenen Felder aktualisiert (Merge). Nicht gesendete Felder bleiben unberührt. Ein solcher Wiederholungs-POST liefert created: false. Das Roh-Payload wird als source_payload gespeichert, erscheint aber nie in der Antwort.

Duplikatwarnung: Wird beim Anlegen ein mögliches Duplikat erkannt, wird der Lead trotzdem angelegt und die Antwort trägt ein Feld duplicate_warning mit den Treffern. Ohne Treffer ist das Feld null.

Leads auflisten

GET /api/leads

Listet die Leads des Teams paginiert auf. Standardmässig wird nur die offene Pipeline gezeigt (abgeschlossene und konvertierte Leads ausgeblendet); mit pipeline=false wird der volle Satz zurückgegeben. Die Antwort folgt dem Standard-Paginierungsformat mit data, links und meta.

Query-Parameter:

pipeline boolean Standard true (nur offene Pipeline). false zeigt alle Leads inkl. abgeschlossener
search string Volltextsuche über Firmenname, Vor-/Nachname und E-Mail
source string Filter auf eine Quelle oder mehrere per Komma getrennt
tag_uuid string Filter auf eine team-eigene Tag-UUID
assigned_user_uuid string Filter auf die UUID des zugewiesenen Benutzers. Eine UUID ausserhalb des Teams liefert eine leere Liste. Breaking Change: assigned_user_id wird nicht mehr akzeptiert (422)
created_from string Erstellt ab (Datum, YYYY-MM-DD)
created_to string Erstellt bis (Datum, YYYY-MM-DD)
updated_from string Geändert ab (Datum, YYYY-MM-DD)
updated_to string Geändert bis (Datum, YYYY-MM-DD)
per_page integer Einträge pro Seite (Standard 50, Maximum 100)
include string Zusätzliche Relationen, per Komma: contacts, sources, tags, status, board_cards, assigned_user, notes, custom_fields

Lead anlegen (Upsert)

POST /api/leads

Legt einen Lead an oder aktualisiert per external_source + external_id idempotent einen bestehenden (Merge nur der gesendeten Felder). Der Status kann hier nie gesetzt werden; ein neuer Lead startet im Standard-Status. Ein optionales doc-Objekt befüllt beim erstmaligen Anlegen das FlowDoc des Leads, nicht bei einem idempotenten Wiederholungs-POST. Das frühere docs[]-Array wird nicht mehr akzeptiert (422), weil ein Lead genau ein FlowDoc hat. Die Antwort trägt created (bool) und duplicate_warning (Objekt mit matches oder null). HTTP 201 bei Neuanlage, 200 bei idempotenter Aktualisierung.

Request Body:

type string * company oder person
company_name string Firmenname (Pflicht wenn type=company)
first_name string Vorname (Pflicht wenn type=person)
last_name string Nachname
email string E-Mail-Adresse
phone string Telefonnummer
website string Webseite
address_line_1 string Adresszeile 1
address_line_2 string Adresszeile 2
postal_code string Postleitzahl
city string Ort
state string Bundesland / Region
country string Land (ISO-Code)
country_display string Anzeigename des Landes
deal_value number Potenzieller Auftragswert
deal_currency string Währung (3-stelliger ISO-Code)
notes string Freitext-Notiz am Lead
external_source string Quellsystem-Kennung, Teil des Idempotenzschlüssels
external_id string Datensatz-Kennung im Quellsystem, Teil des Idempotenzschlüssels
source_payload object Roh-Payload der Quelle. Wird gespeichert, erscheint aber nie in der Antwort
sources array Liste von Herkunftsquellen als Freitext (max. 20 Einträge)
tag_uuids array Liste team-eigener Tag-UUIDs (max. 50 Einträge)
assigned_user_uuid string UUID eines Team-Mitglieds als zugewiesener Benutzer. Benutzer außerhalb des Teams werden mit 422 abgelehnt. Breaking Change: assigned_user_id wird nicht mehr akzeptiert (Validierungsfehler)
contacts array Ansprechpartner-Objekte (first_name, last_name, email, phone, role; max. 50 Einträge)
custom_fields array Custom-Field-Werte (definition_uuid oder name, plus value). Bei Feldern vom Typ reference ist value die UUID des Ziels (Kunde, Kontakt, Projekt oder Team-Mitglied), zum Beispiel {"definition_uuid": "...", "value": "3f7c1a02-9b64-4d1e-a5c8-2e7b90d41f6a"}. Bei Feldern vom Typ date ist value ein Datum im Format JJJJ-MM-TT, bei Feldern vom Typ currency ein Betrag als Zahl oder Zahl-String ohne Währungszeichen und ohne Tausendertrennzeichen, mit höchstens den in der Definition festgelegten Nachkommastellen; ein unpassender Wert führt zu 422 und es wird kein Lead angelegt. Breaking Change: definition_id wird nicht mehr akzeptiert, und eine numerische Ziel-ID in value wird bei Referenzfeldern ebenfalls mit 422 abgelehnt
doc object Das FlowDoc des Leads, nur bei Neuanlage. Einziges Feld ist content als Markdown-String; ein Titel ist nicht vorgesehen. Breaking Change: das frühere docs[]-Array wird mit 422 abgelehnt

Lead abrufen

GET /api/leads/{uuid}

Ruft einen einzelnen team-eigenen Lead per UUID ab. Status, Quellen, Tags, Ansprechpartner und zugewiesener Benutzer sind enthalten. Custom-Field-Werte nur mit include=custom_fields; Referenzfelder werden ausschließlich per UUID adressiert.

Query-Parameter:

include string custom_fields, um die Custom-Field-Werte mitzuladen. Referenzfelder liefern die UUID des Ziels in value und referenced_uuid sowie den Anzeigenamen in referenced_name; ist das Ziel nicht mehr vorhanden, ist referenced_uuid null. Felder vom Typ date liefern das Datum als JJJJ-MM-TT, Felder vom Typ currency den Betrag als Dezimalzahl mit Punkt in value und den ISO-4217-Code des Feldes in currency

Lead aktualisieren

PATCH /api/leads/{uuid}

Aktualisiert die Kernfelder eines team-eigenen Leads (Teil-Update, nur gesendete Felder). Der Status kann hier nicht gesetzt werden (status und status_id werden mit 422 abgelehnt), dafür dient der Status-Endpunkt. Die Antwort trägt zusätzlich duplicate_warning.

Request Body:

type string company oder person
company_name string Firmenname
first_name string Vorname
last_name string Nachname
email string E-Mail-Adresse
phone string Telefonnummer
website string Webseite
address_line_1 string Adresszeile 1
address_line_2 string Adresszeile 2
postal_code string Postleitzahl
city string Ort
state string Bundesland / Region
country string Land (ISO-Code)
country_display string Anzeigename des Landes
deal_value number Potenzieller Auftragswert
deal_currency string Währung (3-stelliger ISO-Code)
notes string Freitext-Notiz
external_source string Quellsystem-Kennung
external_id string Datensatz-Kennung im Quellsystem
source_payload object Roh-Payload der Quelle. Wird gespeichert, erscheint aber nie in der Antwort
sources array Herkunftsquellen, additiv (fügt nur hinzu, entfernt nie; zum Ersetzen dient PUT /sources; max. 20 Einträge)
tag_uuids array Team-eigene Tag-UUIDs, additiv (zum Ersetzen dient PUT /tags; max. 50 Einträge)
assigned_user_uuid string UUID eines Team-Mitglieds als zugewiesener Benutzer; null entfernt die Zuweisung. Benutzer außerhalb des Teams werden mit 422 abgelehnt. Breaking Change: assigned_user_id wird nicht mehr akzeptiert (Validierungsfehler)
contacts array Ansprechpartner-Objekte (first_name, last_name, email, phone, role), additiv: legt neue Ansprechpartner an, verändert oder löscht keine bestehenden (dafür die /contacts-Endpunkte; max. 50 Einträge)
custom_fields array Custom-Field-Werte (definition_uuid oder name, plus value). Bei Feldern vom Typ reference ist value die UUID des Ziels (Kunde, Kontakt, Projekt oder Team-Mitglied). Bei Feldern vom Typ date ist value ein Datum im Format JJJJ-MM-TT, bei Feldern vom Typ currency ein Betrag als Zahl oder Zahl-String ohne Währungszeichen und ohne Tausendertrennzeichen; ein unpassender Wert führt zu 422. Breaking Change: definition_id wird nicht mehr akzeptiert, und eine numerische Ziel-ID in value wird bei Referenzfeldern ebenfalls mit 422 abgelehnt

Lead löschen

DELETE /api/leads/{uuid}

Löscht einen team-eigenen Lead (Soft-Delete).

🔗 Lead-Beziehungen

Sync ersetzt, Notizen sind append-only
PUT auf Quellen und Tags ist ein voller Sync: die gesendete Liste ersetzt die gespeicherte (ausgelassene Werte werden entfernt, ein leeres Array leert die Relation). Notizen sind unveränderlich, es gibt bewusst kein PATCH oder DELETE.

Alle Endpunkte sind team-scoped: eine fremde Lead-UUID ergibt 404. Fremd-Team-Tag-UUIDs werden als ungültige Auswahl (422) abgelehnt. Die Autorenschaft einer Notiz stammt immer vom Token-Benutzer und kann nicht mitgesendet werden.

Quellen synchronisieren

PUT /api/leads/{uuid}/sources

Voller Sync der Quellen des Leads: die gesendete Liste ersetzt die gespeicherte. Ein leeres Array leert die Quellen. Trimmen, Leer-Entfernen und Deduplizieren übernimmt der Server.

Request Body:

sources array * Vollständige Liste der Quellen (Freitext, max. 50 Einträge). Muss vorhanden sein; leeres Array leert die Quellen

Tags synchronisieren

PUT /api/leads/{uuid}/tags

Voller Sync der Tags des Leads über team-eigene Tag-UUIDs: die gesendete Liste ersetzt die gespeicherte. Behaltene Tags behalten ihre Pivot-Quelle, neu angehängte erhalten source=api, ausgelassene werden entfernt. Ein leeres Array entfernt alle Tags. Eine Fremd-Team-UUID wird mit 422 abgelehnt.

Request Body:

tag_uuids array * Vollständige Liste team-eigener Tag-UUIDs (max. 50 Einträge). Muss vorhanden sein; leeres Array entfernt alle Tags

Ansprechpartner auflisten

GET /api/leads/{uuid}/contacts

Listet die Ansprechpartner eines team-eigenen Leads auf.

Ansprechpartner anlegen

POST /api/leads/{uuid}/contacts

Legt einen Ansprechpartner am Lead an. Nur first_name ist Pflicht.

Request Body:

first_name string * Vorname
last_name string Nachname
email string E-Mail-Adresse
phone string Telefonnummer
role string Rolle / Funktion

Ansprechpartner aktualisieren

PATCH /api/leads/{uuid}/contacts/{contactUuid}

Aktualisiert einen Ansprechpartner (Teil-Update). first_name darf, wenn gesendet, nicht leer sein. Der Ansprechpartner wird per UUID innerhalb des Leads adressiert; numerische IDs werden nicht mehr akzeptiert (HTTP 404).

Request Body:

first_name string Vorname (darf nicht geleert werden)
last_name string Nachname
email string E-Mail-Adresse
phone string Telefonnummer
role string Rolle / Funktion

Ansprechpartner entfernen

DELETE /api/leads/{uuid}/contacts/{contactUuid}

Entfernt einen Ansprechpartner des Leads.

Notizen auflisten

GET /api/leads/{uuid}/notes

Listet die Notizen des Leads auf, neueste zuerst. Der Autor wird als Objekt (uuid, name) mitgeliefert.

Notiz anhängen

POST /api/leads/{uuid}/notes

Hängt eine Notiz an den Lead an. Notizen sind append-only, es gibt kein Bearbeiten oder Löschen. Der Autor ist immer der Token-Benutzer.

Request Body:

body string * Notizinhalt (max. 65535 Zeichen)

🚦 Lead-Status

converted ist nicht setzbar
Der Systemstatus converted kann über diesen Endpunkt nicht gesetzt werden (HTTP 422). Er entsteht ausschliesslich über die Konvertierung. Andere Status (auch gewonnen/verloren) sind normal setzbar.

Der Status wird ausschliesslich über seine team-eigene UUID gesetzt, nie über einen Schlüssel oder eine numerische id. Eine Fremd-Team-Status-UUID wird als ungültige Auswahl (422) abgelehnt. Der Schreibvorgang läuft über denselben Pfad wie die Detailseite, sodass derselbe Timeline-Eintrag geschrieben und das Board synchronisiert wird.

Status setzen

PUT /api/leads/{uuid}/status

Setzt den Status eines team-eigenen Leads auf einen team-eigenen Status, adressiert per Status-UUID. converted wird mit 422 abgelehnt; eine UUID, die die Validierung passiert, aber keinen auffindbaren Status trifft, liefert 404.

Request Body:

status_uuid string * UUID eines team-eigenen Lead-Status

📆 Lead-Timeline

Die Lead-Timeline spiegelt die Kunden-Timeline: GET ist paginiert (neueste zuerst), POST hängt einen Eintrag an. Über die API angelegte Einträge bleiben in der bestehenden Timeline sichtbar und fliessen nach einer Konvertierung in die Kunden-Timeline. Ein konvertierter Lead ist schreibgeschützt: ein POST wird mit HTTP 409 abgelehnt.

Timeline abrufen

GET /api/leads/{uuid}/timeline

Ruft die Timeline-Einträge eines team-eigenen Leads paginiert ab (neueste zuerst).

Query-Parameter:

per_page integer Einträge pro Seite (Standard 50, Maximum 100)

Timeline-Eintrag anlegen

POST /api/leads/{uuid}/timeline

Hängt einen Timeline-Eintrag an den Lead an. type wird gegen die erlaubte Timeline-Typenliste geprüft; fehlt type, wird note verwendet. Bei einem konvertierten Lead antwortet der Endpunkt mit HTTP 409.

Request Body:

content string * Inhalt des Eintrags
type string Timeline-Typ aus der erlaubten Vokabel (Standard note)
event_date string Ereignisdatum (ISO 8601, Standard: jetzt)

🔄 Lead-Konvertierung

Einmalig und unumkehrbar
Eine Konvertierung ist unumkehrbar. Der konvertierte Lead wird schreibgeschützt. Ein zweiter Konvertierungsversuch desselben Leads wird mit HTTP 409 abgelehnt.

Konvertiert einen team-eigenen Lead in einen neuen Kunden über denselben Konvertierungsdienst wie das UI-Modal. Die vier optionalen Transfer-Flags entsprechen den Checkboxen im Modal; ohne Flag wird die jeweilige Kategorie nicht übertragen. Die Flags tragen keine IDs, der Dienst leitet jede übertragene Zeile serverseitig vom gesperrten Lead ab. Die Antwort ist der neu angelegte Kunde (nicht der Lead).

Lead in Kunden konvertieren

POST /api/leads/{uuid}/convert

Konvertiert den Lead in einen neuen Kunden. Ohne client_name wird der Name aus dem Lead abgeleitet (Firmenname bei Firma, Vor- und Nachname bei Person). Die Antwort ist der neue Kunde (CmmClient) mit HTTP 201. Ein bereits konvertierter Lead ergibt 409.

Request Body:

client_name string Expliziter Kundenname (überschreibt den abgeleiteten Namen)
transfer_contacts boolean Ansprechpartner mit übernehmen
transfer_todos boolean Aufgaben mit übernehmen
transfer_docs boolean FlowDocs mit übernehmen
transfer_custom_fields boolean Custom-Field-Werte mit übernehmen

📊 Lead-Berichte

Nur offene Leads
Alle Berichte zählen ausschließlich offene Leads. Ein konvertierter Lead ist ein Kunde und würde sonst doppelt erscheinen, einmal im Trichter und einmal im Kundenbestand.

Trichter je Status

GET /api/leads/reports/funnel

Anzahl und Wert der offenen Leads je Status, in der Reihenfolge der Statusliste, dazu die Zahl der Leads ohne Status.

Verteilung auf Zuständige

GET /api/leads/reports/assignments

Anzahl und Wert der offenen Leads je zuständiger Person. Nicht zugewiesene Leads erscheinen als eigene Zeile mit user: null, damit genau diese Lücke sichtbar bleibt.

Herkunft der Leads

GET /api/leads/reports/sources

Anzahl der Leads je Quelle, absteigend sortiert.

Mögliche Dubletten finden

GET /api/leads/{uuid}/duplicates

Andere offene Leads mit derselben E-Mail-Adresse oder demselben Firmennamen, höchstens zwanzig. Bewusst eng gefasst: verglichen wird exakt, nicht ähnlich, weil über das Zusammenführen ein Mensch entscheidet.

🗂️ Lead-Boards

Berechtigung und Adressierung
Alle Board-Endpunkte erfordern FlowCRM plus die Leads-Unterberechtigung. Boards, Spalten und Karten werden ausschliesslich über ihre UUID adressiert. Pro Team sind maximal 5 Boards erlaubt.

Kanban-Boards für Leads: ein Board enthält Spalten, eine Spalte enthält Karten, jede Karte verweist auf genau einen Lead. Das Verschieben einer Karte in eine status-gemappte Spalte setzt den Status des Leads über denselben Pfad wie das Drag-and-Drop im UI. Karten dieses Endpunkts verweisen immer auf einen Lead, nie auf einen Kunden.

Boards auflisten

GET /api/lead-boards

Listet die Boards des Teams auf. Mit include=columns oder include=columns.cards werden Spalten bzw. Spalten samt Karten mitgeladen.

Query-Parameter:

include string columns oder columns.cards

Board anlegen

POST /api/lead-boards

Legt ein neues Board an. Bei überschrittenem Limit (5 pro Team) antwortet der Endpunkt mit HTTP 422.

Request Body:

name string * Name des Boards

Board abrufen

GET /api/lead-boards/{uuid}

Ruft ein team-eigenes Board ab. Mit include=columns oder columns.cards inklusive Spalten bzw. Karten.

Query-Parameter:

include string columns oder columns.cards

Board umbenennen

PATCH /api/lead-boards/{uuid}

Benennt ein team-eigenes Board um.

Request Body:

name string Neuer Name des Boards

Board löschen

DELETE /api/lead-boards/{uuid}

Löscht ein team-eigenes Board samt seiner Spalten und Karten. Die verknüpften Leads bleiben bestehen.

Spalte anlegen

POST /api/lead-boards/{uuid}/columns

Legt eine Spalte in einem team-eigenen Board an. Ohne sort_order wird die Spalte hinten angefügt.

Request Body:

name string * Name der Spalte
sort_order integer Position der Spalte (Standard: hinten angefügt)

Spalte aktualisieren

PATCH /api/lead-board-columns/{uuid}

Aktualisiert Name oder Position einer team-eigenen Spalte.

Request Body:

name string Neuer Name der Spalte
sort_order integer Neue Position der Spalte

Spalte löschen

DELETE /api/lead-board-columns/{uuid}

Löscht eine team-eigene Spalte. Die Karten der Spalte werden mitentfernt; die verknüpften Leads bleiben bestehen.

Karte anlegen

POST /api/lead-board-columns/{uuid}/cards

Legt eine Karte in einer team-eigenen Spalte an. Genau eine der beiden Varianten angeben: entweder lead_uuid (bestehender Lead) ODER ein verschachteltes lead-Objekt (neuer Lead und Karte in einer Transaktion). Die Karten-eigenen deal_value/deal_currency sind unabhängig von den Deal-Feldern des Leads.

Request Body:

lead_uuid string UUID eines bestehenden team-eigenen Leads (Alternative zu lead)
lead object Neuer Lead (type plus company_name/first_name usw., analog zum Lead-Anlegen; Alternative zu lead_uuid)
deal_value number Auftragswert der Karte
deal_currency string Währung der Karte (3-stelliger ISO-Code)
sort_order integer Position der Karte in der Spalte

Karte aktualisieren

PATCH /api/lead-board-cards/{uuid}

Aktualisiert die Deal-Felder oder die Position einer team-eigenen Karte. Die Verknüpfung zum Lead und die Spalte werden hier nicht geändert (dafür dient der Move-Endpunkt).

Request Body:

deal_value number Auftragswert der Karte
deal_currency string Währung der Karte (3-stelliger ISO-Code)
sort_order integer Position der Karte in der Spalte

Karte verschieben

PUT /api/lead-board-cards/{uuid}/move

Verschiebt eine team-eigene Karte in eine team-eigene Zielspalte. Ist die Zielspalte status-gemappt, wird der Status des Leads über denselben Pfad wie das UI-Drag-and-Drop gesetzt. Die Verknüpfung der Karte kann dabei nicht geändert werden.

Request Body:

target_column_uuid string * UUID der team-eigenen Zielspalte
sort_order integer Zielposition in der Spalte

Karte löschen

DELETE /api/lead-board-cards/{uuid}

Löscht eine team-eigene Karte. Der verknüpfte Lead bleibt bestehen.

📝 FlowDocs

Berechtigung je Eigentümer
FlowDocs an einem Lead erfordern FlowCRM plus die Leads-Unterberechtigung. FlowDocs an Kunden, Kontakten und Projekten benötigen nur den FlowCRM-Modulzugriff.
Versionierung
Jeder Schreibvorgang erzeugt eine neue Version. Die API akzeptiert content ausschließlich als Markdown-String und wandelt ihn serverseitig in TipTap um. content in der Antwort ist das interne TipTap-JSON und die Quelle der Wahrheit. content_html ist eine bereinigte Darstellungsform, die nur ausgegeben und nie entgegengenommen wird.
Technische Markdown-Inhalte
content darf technische Dokumentation mit Backticks, Codebeispielen, SQL-Begriffen, URLs, relativen Pfadsegmenten und Tabellen enthalten. Diese Inhalte werden als Markdown verarbeitet. Pfad, Query-Parameter und alle übrigen API-Felder bleiben durch die Web Application Firewall geschützt.

Jede der vier Eigentümer-Entitäten — Lead, Kunde, Kontakt und Projekt — hat genau ein FlowDoc. Es gibt deshalb weder eine Liste noch einen Anlege-Endpunkt noch eine Dokument-UUID im Pfad: GET /api/{eigentümer}/{uuid}/docs liefert das Dokument und legt es beim ersten Zugriff an, PUT auf denselben Pfad ersetzt den Inhalt vollständig. Breaking Change: POST auf /docs antwortet mit HTTP 405, die früheren Pfade /docs/{docUuid} mit HTTP 404. Der Eigentümer wird per UUID adressiert. title steht aus Kompatibilitätsgründen weiterhin in der Antwort, ist immer Notizen und wird im Request-Body mit 422 abgelehnt; team_id und die Eigentümer-Verknüpfung ebenso. Für Schreibvorgänge wird content ausschließlich als Markdown-String übergeben. TipTap-JSON wird als Eingabe nicht akzeptiert. Die Syntax folgt CommonMark und unterstützt zusätzlich Aufgabenlisten im GitHub-Stil. Verarbeitet werden Überschriften, Absätze, Aufzählungen, nummerierte Listen, Aufgabenlisten, Fett, Kursiv, Links und feste Zeilenumbrüche. Echte LF- und CRLF-Zeilenumbrüche werden verarbeitet und auch einzelne Zeilenumbrüche sichtbar bewahrt; ein vollständig doppelt kodierter Inhalt mit literalen -Sequenzen wird ebenfalls normalisiert. Eingebettetes HTML wird verworfen. Beim Anlegen eines Leads kann das doc-Feld den Inhalt direkt mitliefern (siehe Lead anlegen). Die folgende Referenz zeigt den vollen Payload einmal für Leads; die Endpunkte für Kunden, Kontakte und Projekte sind identisch aufgebaut und unterscheiden sich nur im Pfad und in der Berechtigung.

Lead-Dokument abrufen

GET /api/leads/{uuid}/docs

Ruft das FlowDoc eines team-eigenen Leads ab, inklusive latest_version_number. Existiert noch keines, wird es beim ersten Aufruf angelegt und leer zurückgegeben. documentable.type ist crm_lead.

Lead-Dokument aktualisieren

PUT /api/leads/{uuid}/docs

Ersetzt den Inhalt des FlowDocs vollständig. content muss übergeben werden; null oder ein leerer String leert das Dokument. Jeder Aufruf erzeugt eine neue Version und erhöht latest_version_number. title wird im Body mit 422 abgelehnt.

Request Body:

content string * Markdown-Inhalt, wird serverseitig in TipTap umgewandelt. null oder leerer String leert das Dokument

Kunden-Dokument abrufen

GET /api/clients/{uuid}/docs

Ruft das FlowDoc eines team-eigenen Kunden ab, inklusive latest_version_number. Existiert noch keines, wird es beim ersten Aufruf angelegt und leer zurückgegeben. documentable.type ist cmm_client.

Kunden-Dokument aktualisieren

PUT /api/clients/{uuid}/docs

Ersetzt den Inhalt des FlowDocs vollständig. content muss übergeben werden; null oder ein leerer String leert das Dokument. Jeder Aufruf erzeugt eine neue Version und erhöht latest_version_number. title wird im Body mit 422 abgelehnt.

Request Body:

content string * Markdown-Inhalt, wird serverseitig in TipTap umgewandelt. null oder leerer String leert das Dokument

Kontakt-Dokument abrufen

GET /api/contacts/{uuid}/docs

Ruft das FlowDoc eines Kontakts (ein privater Kontakt ohne Team ist nur für seinen Eigentümer erreichbar) ab, inklusive latest_version_number. Existiert noch keines, wird es beim ersten Aufruf angelegt und leer zurückgegeben. documentable.type ist cmm_contact.

Kontakt-Dokument aktualisieren

PUT /api/contacts/{uuid}/docs

Ersetzt den Inhalt des FlowDocs vollständig. content muss übergeben werden; null oder ein leerer String leert das Dokument. Jeder Aufruf erzeugt eine neue Version und erhöht latest_version_number. title wird im Body mit 422 abgelehnt.

Request Body:

content string * Markdown-Inhalt, wird serverseitig in TipTap umgewandelt. null oder leerer String leert das Dokument

Projekt-Dokument abrufen

GET /api/projects/{uuid}/docs

Ruft das FlowDoc eines Projekts (ein Projekt hat kein eigenes Team und wird über seinen Kunden team-scoped) ab, inklusive latest_version_number. Existiert noch keines, wird es beim ersten Aufruf angelegt und leer zurückgegeben. documentable.type ist cmm_client_project.

Projekt-Dokument aktualisieren

PUT /api/projects/{uuid}/docs

Ersetzt den Inhalt des FlowDocs vollständig. content muss übergeben werden; null oder ein leerer String leert das Dokument. Jeder Aufruf erzeugt eine neue Version und erhöht latest_version_number. title wird im Body mit 422 abgelehnt.

Request Body:

content string * Markdown-Inhalt, wird serverseitig in TipTap umgewandelt. null oder leerer String leert das Dokument