inDeal API: Leads per Schnittstelle anlegen und aktualisieren

Lars Krüger

Lars Krüger

Zuletzt aktualisiert am Sep 26, 2026

Mit der inDeal API legst du Leads aus anderen Systemen an, liest sie, hältst sie synchron und schreibst Aktivitäten wie Notizen oder Anrufe in die Timeline. Alles, was du dafür brauchst, findest du unter Einstellungen -> API & Webhooks.

Inhalt

Schlüssel erstellen

  1. Öffne Einstellungen -> API & Webhooks.
  2. Klick auf Neuen Schlüssel erstellen und vergib einen Namen, der das angebundene System beschreibt.
  3. Kopiere den Schlüssel sofort. Kopiere den Schlüssel jetzt. Er wird nur einmal angezeigt und kann später nicht erneut abgerufen werden.

Der Dialog zum Erstellen eines Schlüssels mit dem Namen CRM-Sync

Die einmalige Anzeige deines neuen Schlüssels mit Kopieren-Knopf

Danach zeigt die Liste nur noch die letzten vier Zeichen. Brauchst du den Schlüssel erneut, widerrufe den alten mit Widerrufen und erstelle einen neuen. Es sind bis zu 10 aktive Schlüssel möglich - so kannst du je System einen eigenen vergeben und einzeln widerrufen.

Die Schlüsselliste mit dem maskierten Schlüssel CRM-Sync und den Verbindungsdaten darunter

Grundlagen

Angabe Wert
Base-URL https://app.indeal.ai/api/v1
Authentifizierung Header Authorization: Bearer indeal_...
Format JSON in Anfrage und Antwort
Limit 600 Anfragen pro Minute je Schlüssel

Über dem Limit antwortet die API mit Status 429 und dem Header Retry-After: 60 - warte dann eine Minute.

Lead anlegen

POST /leads legt einen Lead an. Mindestens eines von email oder linkedin_url (die Profil-URL des Kontakts) ist Pflicht.

curl -X POST https://app.indeal.ai/api/v1/leads \
  -H "Authorization: Bearer indeal_..." \
  -H "Content-Type: application/json" \
  -d '{
    "full_name": "Julia Weber",
    "email": "julia.weber@muster.de",
    "company_name": "Muster GmbH",
    "role_title": "Geschaeftsfuehrerin"
  }'

Antwort bei Erfolg (Status 201):

{
  "status": "created",
  "lead": {
    "id": "0b0e...",
    "stage": "qualifying",
    "full_name": "Julia Weber",
    "email": "julia.weber@muster.de",
    "company_name": "Muster GmbH"
  }
}

Existiert der Lead schon, bekommst du Status 200 mit "status": "duplicate" und dem bestehenden Lead - siehe Doppelte Leads.

Lead lesen

GET /leads/{id} liefert einen einzelnen Lead.

curl https://app.indeal.ai/api/v1/leads/0b0e... \
  -H "Authorization: Bearer indeal_..."

Antwort (Status 200): { "lead": { ... } }. Eine unbekannte ID liefert Status 404.

Lead aktualisieren

PATCH /leads/{id} ändert nur die Felder, die du schickst. null leert ein Feld. Mit stage wechselst du die Phase - die Verlaufshistorie in inDeal wird dabei automatisch geschrieben. custom_data wird zusammengeführt, nicht ersetzt: null als Wert löscht einen Key, alle anderen Keys bleiben.

curl -X PATCH https://app.indeal.ai/api/v1/leads/0b0e... \
  -H "Authorization: Bearer indeal_..." \
  -H "Content-Type: application/json" \
  -d '{ "stage": "meeting_scheduled", "next_step": "Demo vorbereiten" }'

Antwort (Status 200): { "lead": { ... } }. Kollidiert die Änderung mit einem bestehenden Lead (E-Mail oder Profil-URL schon vergeben), kommt Status 409.

Leads auflisten

GET /leads liefert Leads seitenweise, sortiert nach Änderungszeitpunkt.

curl "https://app.indeal.ai/api/v1/leads?updated_since=2026-09-01T00:00:00Z&limit=100" \
  -H "Authorization: Bearer indeal_..."
Parameter Bedeutung
updated_since nur Leads, die seit diesem Zeitpunkt geändert wurden (ISO 8601)
limit 1 bis 200, Standard 100
cursor next_cursor aus der vorigen Antwort
order asc (Standard, älteste Änderung zuerst) oder desc (neueste zuerst)

Antwort: { "leads": [...], "next_cursor": "..." }. Ist next_cursor null, bist du am Ende. Der Cursor merkt sich die Sortierrichtung, du musst order beim Blättern nicht wiederholen. Für laufende Synchronisation: regelmäßig mit updated_since anfragen und mit cursor blättern.

Lead per E-Mail oder Profil-URL finden

Du kennst die E-Mail-Adresse oder die Profil-URL und brauchst die id? Gib sie als Parameter mit. inDeal sucht dann genauso wie beim Anlegen: Groß- und Kleinschreibung spielen keine Rolle, bei der Profil-URL auch nicht https://, www oder ein Schrägstrich am Ende.

curl "https://app.indeal.ai/api/v1/leads?email=julia.weber@muster.de" \
  -H "Authorization: Bearer indeal_..."
Parameter Bedeutung
email Treffer über die E-Mail-Adresse
linkedin_url Treffer über die Profil-URL

Gibst du beide an, bekommst du jeden Lead, auf den mindestens eines passt. Die Antwort ist { "leads": [...] } ohne next_cursor, denn mehr als zwei Treffer kann es nicht geben. Passt nichts, ist die Liste leer. updated_since und cursor werden bei dieser Suche ignoriert. Eine ungültige E-Mail-Adresse oder URL liefert Status 400 mit dem Feldnamen.

Aktivitäten

Jeder Lead hat eine Timeline. Über die API legst du dort Einträge an und liest sie.

Aktivität anlegen

POST /leads/{id}/activities legt einen Timeline-Eintrag am Lead an. Schreibbar sind die Typen note (Notiz), call (Anruf), email (E-Mail) und meeting_scheduled (Termin). Mindestens eines von title oder body ist Pflicht. Fehlt title, bildet inDeal ihn aus den ersten 80 Zeichen von body.

Feld Pflicht Hinweis
type ja note, call, email, meeting_scheduled
title nein max. 200 Zeichen
body nein Freitext, max. 10000 Zeichen, etwa das Gesprächsergebnis
channel nein linkedin, email, meet, call
occurred_at nein Zeitpunkt (ISO 8601), Standard jetzt, nicht in der Zukunft
curl -X POST https://app.indeal.ai/api/v1/leads/0b0e.../activities \
  -H "Authorization: Bearer indeal_..." \
  -H "Content-Type: application/json" \
  -d '{ "type": "call", "body": "Kurzes Telefonat, Demo nächste Woche", "channel": "call" }'

Antwort bei Erfolg (Status 201):

{
  "activity": {
    "id": "9f3a...",
    "type": "call",
    "title": "Kurzes Telefonat, Demo nächste Woche",
    "body": "Kurzes Telefonat, Demo nächste Woche",
    "quote": null,
    "channel": "call",
    "occurred_at": "2026-09-03T14:00:00+00:00",
    "created_at": "2026-09-03T14:00:01+00:00",
    "pinned": false,
    "edited_at": null
  }
}

Der Eintrag erscheint sofort in der Timeline des Leads, und Anrufe sowie E-Mails zählen als Kontaktpunkt. Die Typen reply (Antwort aus einer Kampagne) und stage_change (Phasenwechsel) schreibt inDeal selbst; schickst du sie, kommt Status 400. Eine unbekannte Lead-ID liefert Status 404.

Timeline lesen

GET /leads/{id}/activities liefert alle Einträge des Leads, neueste zuerst, inklusive der nur lesbaren Typen reply und stage_change.

Parameter Bedeutung
type nur ein Typ: note, call, email, meeting_scheduled, reply, stage_change
limit 1 bis 200, Standard 50
cursor next_cursor aus der vorigen Antwort
curl "https://app.indeal.ai/api/v1/leads/0b0e.../activities?type=reply&limit=50" \
  -H "Authorization: Bearer indeal_..."

Antwort: { "activities": [...], "next_cursor": "..." }. Bei Antworten aus Kampagnen steht der Text in quote. edited_at zeigt, dass ein Eintrag nachträglich bearbeitet wurde. Ändern oder Löschen per API gibt es nicht.

Willst du über neue Einträge sofort informiert werden, statt die Timeline abzufragen, abonniere das Webhook-Ereignis activity.created - siehe inDeal Webhooks.

Felder

Pflichtregel: mindestens eines von email / linkedin_url beim Anlegen. Alles andere ist optional.

Feld Typ Hinweis
full_name Text Name des Kontakts
role_title Text Position
email Text Dedup-Anker
phone, mobile, company_phone Text werden automatisch bereinigt
linkedin_url Text Profil-URL, Dedup-Anker
company_name Text Firma
company_size Ganzzahl Mitarbeiterzahl
industry Text Branche
company_website, company_linkedin Text Firmen-Links
street, zip, city, country Text Adresse
next_step Text nächster Schritt
next_step_due Datum Format YYYY-MM-DD
est_value Zahl geschätzter Wert
description Text Beschreibung
lead_source Text Herkunft
sentiment Auswahl positive, neutral, negative
channel_direction Auswahl inbound, outbound
lost_reason Text Verlustgrund
stage Auswahl qualifying, schedule_meeting, meeting_scheduled, meeting_no_show, meeting_done, lead_lost
custom_data Objekt eigene Felder, siehe Eigene Felder

Jede Antwort enthält zusätzlich url, den Link zur Lead-Seite in inDeal (nur lesend). Unbekannte Felder lehnt die API ab - die Fehlermeldung nennt das betroffene Feld. Interne Felder (etwa Anreicherungs-Status) gibt die API weder heraus noch nimmt sie sie an.

Eigene Felder

Eigene Felder legst du in inDeal unter Layout anpassen an, getrennt für Leads und Deals. Ihre Werte stehen im Objekt custom_data, der Schlüssel ist der API-Name des Feldes.

Felder abrufen

curl "https://app.indeal.ai/api/v1/custom-fields?entity=lead" \
  -H "Authorization: Bearer indeal_..."

entity ist Pflicht (lead oder deal). Die Antwort enthält alle aktiven Felder in der Reihenfolge des Layouts, jeweils mit key (API-Name), label, type, bei Auswahlfeldern options, bei Währung currency_code und der section. Ausgeblendete Felder fehlen.

Wertformat pro Typ

type Wert in custom_data Beispiel
text Text, max. 10.000 Zeichen, wird getrimmt "Rückruf nach Messe"
url Link, nur http oder https; ohne Schema wird https:// ergänzt "https://indeal.ai"
number Zahl 42
currency Zahl; die Währung steht in currency_code des Feldes 5000
checkbox true oder false true
date YYYY-MM-DD "2026-10-15"
datetime ISO 8601 mit Offset "2026-10-15T09:30:00+02:00"
dropdown der API-Name einer Option, nicht ihr Name "gold"
multiselect Liste von Options-API-Namen, doppelte werden entfernt ["messe", "empfehlung"]

null löscht einen Wert, ebenso ein leerer Text oder eine leere Liste. Pro Request sind höchstens 50 Schlüssel in custom_data erlaubt.

Prüfung beim Schreiben

POST und PATCH auf Leads und Deals prüfen custom_data gegen die Felder des jeweiligen Moduls:

  • Unbekannte Schlüssel und Schlüssel ausgeblendeter Felder werden ignoriert und in warnings gemeldet. Das ist kein Fehler, der Rest wird gespeichert.
{ "lead": { ... }, "warnings": [{ "key": "partner_id", "code": "unknown_key" }, { "key": "alt", "code": "deleted_field" }] }
  • Ungültige Werte bekannter Felder ergeben Status 422 mit validation_error und details. Dann wird nichts geschrieben, auch keine anderen Felder aus demselben Request.
{
  "error": {
    "code": "validation_error",
    "message": "custom_data: invalid values.",
    "details": [
      { "key": "tarif", "code": "invalid_option" },
      { "key": "budget", "code": "invalid_type" }
    ]
  }
}

Mögliche Werte für details.code: invalid_type, invalid_option, invalid_date, invalid_url, too_long, readonly_field. warnings ist in jeder Schreibantwort enthalten, als leere Liste, wenn nichts ignoriert wurde.

Doppelte Leads

Beim Anlegen prüft inDeal zuerst die Profil-URL, dann die E-Mail-Adresse - beide unabhängig von Groß- und Kleinschreibung. Gibt es bereits einen passenden Lead, wird KEIN neuer angelegt: du bekommst Status 200 mit "status": "duplicate" und dem bestehenden Lead samt seiner id.

Das macht den Endpoint gefahrlos wiederholbar: dieselbe Anfrage zweimal zu senden erzeugt nie zwei Leads. Willst du den bestehenden Lead ändern, nutze die id aus der Antwort mit PATCH /leads/{id}.

Fehlercodes

Alle Fehler haben dieselbe Form: { "error": { "code": "...", "message": "..." } }. Die Meldung ist immer auf Englisch und für Menschen gedacht, prüfe in deinem Code den code.

{ "error": { "code": "not_found", "message": "Lead not found." } }
Code Status Bedeutung
unauthorized 401 Schlüssel fehlt, ist ungültig oder widerrufen
rate_limited 429 Limit überschritten, warte die Sekunden aus Retry-After
validation_error 400 Eingabe ungültig, die Meldung nennt das Feld
validation_error 422 Ungültige Werte in custom_data, details nennt Feld und Grund, es wurde nichts geschrieben
not_found 404 Lead existiert nicht oder liegt im Papierkorb
conflict 409 Änderung kollidiert mit einem bestehenden Lead
blacklisted 409 Person oder Firma steht auf der Blacklist, es wurde nichts angelegt
internal 500 Unerwarteter Fehler, versuch es erneut
internal 503 Blacklist-Prüfung vorübergehend nicht möglich, es wurde nichts angelegt, versuch es später erneut

Weiter