Entwickler

API-Dokumentation

Lege Leads per REST-API an, lass sie automatisch per WhatsApp anschreiben und erhalte Ereignisse — zum Beispiel ob eine Nummer auf WhatsApp erreichbar ist — per Webhook zurück in dein System.

Einführung

Die Public API ist eine REST-API mit JSON-Bodys. Alle Endpoints liegen unter der Base-URL:

https://comu-ai.de/api/v1

Typischer Ablauf: Dein System (Website-Formular, CRM, eigenes Backend) legt per POST /v1/leads einen Lead an. Comu.ai schreibt den Lead sofort über den gewählten Agent per WhatsApp an. Ob die Nummer WhatsApp-fähig ist, erfährst du Sekunden später per Webhook (lead.undeliverable) oder per Polling (GET /v1/leads/{id}).

Authentifizierung

Alle Requests brauchen einen API-Schlüssel als Bearer-Token. Schlüssel erstellst du in den Einstellungen unter „API“ (nur Account-Owner). Der Schlüssel wird dir genau einmal angezeigt — speichere ihn sicher, z. B. in einem Secret-Manager. Übertrage ihn nie im Frontend-Code.

curl https://comu-ai.de/api/v1/agents \
  -H "Authorization: Bearer comu_live_IhrSchluessel"

Ungültige oder widerrufene Schlüssel erhalten 401 UNAUTHORIZED.

Rate Limits

Limits gelten pro API-Schlüssel und Minute:

EndpointLimit
POST /v1/leads10 Requests / Minute (jeder Call löst einen WhatsApp-Versand aus)
GET-Endpoints60 Requests / Minute

Bei Überschreitung antwortet die API mit 429 RATE_LIMITED inklusive Retry-After-Header. Jede Antwort enthält X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset.

Lead anlegen

POST/v1/leads

Legt einen Lead an und verschickt sofort die Startnachricht (bzw. Opt-In-Frage) des Agents. Der Agent muss dafür bereit sein — seine Opener-Vorlage muss von WhatsApp freigegeben sein (siehe Agents auflisten).

FeldTypBeschreibung
agent_idstring (UUID), PflichtDer Agent, der den Lead anschreibt (siehe GET /v1/agents)
phonestring, PflichtTelefonnummer, beliebiges Format — wird zu E.164 normalisiert (deutsche Nummern ohne Ländervorwahl werden als +49 interpretiert)
namestring, PflichtName des Leads (Vorname wird in der Startnachricht verwendet)
emailstring, optionalE-Mail-Adresse
external_idstring, optionalDeine eigene ID (Idempotenz-Schlüssel, siehe unten)
custom_fieldsobject, optionalSchlüssel-Wert-Paare (z. B. Formularantworten) — stehen dem KI-Agent als Kontext zur Verfügung
curl -X POST https://comu-ai.de/api/v1/leads \
  -H "Authorization: Bearer comu_live_IhrSchluessel" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "6f1e...c2a0",
    "phone": "+49 151 23456789",
    "name": "Max Mustermann",
    "email": "max@example.org",
    "external_id": "crm-lead-4711",
    "custom_fields": { "plz": "10717", "anliegen": "Beratung Solaranlage" }
  }'

Antwort 201 Created:

{
  "lead": {
    "id": "a3d2...91bc",
    "external_id": "crm-lead-4711",
    "status": "open",
    "name": "Max Mustermann",
    "phone": "4915123456789",
    "agent_id": "6f1e...c2a0",
    "created_at": "2026-07-08T09:30:00.000Z",
    "whatsapp": { "undeliverable": false, "undeliverable_at": null },
    "qualification": { "qualified": false, "qualified_at": null, "trigger": null },
    "appointment": { "at": null },
    "opted_out_at": null
  },
  "first_message": { "status": "sent" }
}

first_message.status ist "sent" oder "blocked" (mit reason), falls WhatsApp den Versand abgelehnt hat. Der Lead existiert auch bei "blocked" und ist im Dashboard sichtbar.

Idempotenz

Übergib eine external_id (im Body oder als Idempotency-Key-Header). Wiederholte Requests mit derselben external_id legen keinen zweiten Lead an, sondern antworten 200 mit dem bestehenden Lead und "replayed": true. Ein Lead mit bereits aktiver Telefonnummer wird unabhängig davon mit 409 DUPLICATE_LEAD abgelehnt.

Lead abfragen

GET/v1/leads/{id}

{id} ist die Comu-Lead-UUID oder deine external_id. Die Antwort enthält denselben lead-Body wie oben — inklusive whatsapp.undeliverable für Polling, falls du keine Webhooks nutzen willst.

curl https://comu-ai.de/api/v1/leads/crm-lead-4711 \
  -H "Authorization: Bearer comu_live_IhrSchluessel"

Agents auflisten

GET/v1/agents

Liefert alle Agents des Accounts mit ihrer Sende-Bereitschaft. Nur Agents mit "ready": true können Leads entgegennehmen; sonst nennt reason die Ursache (NO_WHATSAPP, NO_TEMPLATE, TEMPLATE_NOT_APPROVED).

{
  "agents": [
    { "id": "6f1e...c2a0", "name": "Solar-Beratung", "ready": true, "reason": null }
  ]
}

Fehlercodes

Fehler kommen immer im selben Envelope:

{ "error": { "code": "TEMPLATE_NOT_APPROVED", "message": "...", "details": { } } }
HTTPCodeBedeutung
400INVALID_JSON / VALIDATION_ERRORBody fehlerhaft; details.issues nennt die Felder
400INVALID_PHONENummer konnte nicht zu E.164 normalisiert werden
401UNAUTHORIZEDAPI-Schlüssel fehlt, ist ungültig oder widerrufen
404AGENT_NOT_FOUND / LEAD_NOT_FOUNDRessource existiert nicht in diesem Account
409DUPLICATE_LEADAktiver Lead mit dieser Nummer existiert bereits (details.existing_lead_id)
422NO_WHATSAPPAgent hat kein aktives WhatsApp-Konto
422NO_TEMPLATEAgent hat keine Opener-Vorlage konfiguriert
422TEMPLATE_NOT_APPROVEDOpener-Vorlage wartet noch auf WhatsApp-Freigabe
429RATE_LIMITEDRate Limit überschritten — Retry-After beachten
500INTERNAL_ERRORUnerwarteter Fehler — Request wiederholen

Webhooks

Registriere in den Einstellungen unter „API“ eine https-URL und erhalte Lead-Ereignisse als POST mit JSON-Body. Ohne Event-Auswahl bekommst du alle Ereignisse.

EventWann
lead.createdNeuer Lead angelegt (API, Meta-Formular, Dashboard, WhatsApp-Erstkontakt)
lead.undeliverableWhatsApp meldet: Nummer nicht erreichbar (kein WhatsApp) — i. d. R. Sekunden nach dem ersten Sendeversuch
lead.respondedLead hat zum ersten Mal geantwortet
lead.qualifiedLead wurde qualifiziert (data.trigger: booking oder classifier)
lead.lostLead verloren (data.reason: opt_out, opt_in_expired oder manual)
appointment.bookedTermin gebucht oder umgebucht (data.appointment mit Zeit, Provider, Link)

Beispiel-Payload:

{
  "id": "7c04...e8d1",
  "type": "lead.undeliverable",
  "created_at": "2026-07-08T09:30:07.000Z",
  "data": {
    "lead": {
      "id": "a3d2...91bc",
      "external_id": "crm-lead-4711",
      "status": "open",
      "whatsapp": { "undeliverable": true, "undeliverable_at": "2026-07-08T09:30:06.512Z" }
    }
  }
}

Signatur prüfen

Jeder Request trägt einen X-Comu-Signature-Header im Format t=<unix>,v1=<hex>. Die Signatur ist ein HMAC-SHA256 über `${t}.${rawBody}` mit deinem Endpoint-Secret (whsec_…). Prüfe zusätzlich, dass t nicht älter als 5 Minuten ist (Replay-Schutz).

// Node.js
const crypto = require("crypto")

function verifyComuSignature(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(signatureHeader.split(",").map(p => p.split("=")))
  const age = Math.abs(Date.now() / 1000 - Number(parts.t))
  if (age > 300) return false // Replay-Fenster 5 min

  const expected = crypto.createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex")
  return crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected))
}

Weitere Header: X-Comu-Event (Event-Typ), X-Comu-Event-Id (stabile Event-ID für Dedup) und X-Comu-Delivery-Id (pro Zustellversuch).

Zustellung & Retries

Antworte mit einem 2xx-Status innerhalb von 10 Sekunden. Zustellung ist at-least-once: Dedupliziere über die Event-ID (id im Body bzw. X-Comu-Event-Id). Bei Fehlern versuchen wir es erneut nach 1, 5 und 30 Minuten sowie 2 und 12 Stunden (insgesamt 6 Versuche). Nach 20 fehlgeschlagenen Zustellungen in Folge wird der Endpoint automatisch deaktiviert — in den Einstellungen kannst du ihn wieder aktivieren und testen.

WhatsApp-Erreichbarkeit

Es gibt keinen offiziellen Weg, vor dem Versand zu prüfen, ob eine Nummer auf WhatsApp ist — Meta bietet dafür bewusst keine Lookup-API an. Das zuverlässige (und einzige ToS-konforme) Signal entsteht beim ersten Sendeversuch: Ist die Nummer nicht auf WhatsApp, meldet Meta den Fehler 131026 („Message undeliverable“) — asynchron, typischerweise wenige Sekunden nach dem Versand.

Comu.ai übersetzt das für dich in Echtzeit: Lead per API anlegen → Startnachricht geht raus → bei Nichterreichbarkeit kommt das Webhook-Event lead.undeliverable (bzw. whatsapp.undeliverable = true beim Polling). In der Praxis hast du das Ergebnis meist in unter 10 Sekunden nach dem API-Call. Nicht zustellbare Nachrichten berechnet WhatsApp nicht.

Hinweis: 131026 ist ein Sammel-Fehlercode — neben „kein WhatsApp“ kann in seltenen Fällen z. B. eine stark veraltete WhatsApp-Version des Empfängers die Ursache sein. Für Formular-Validierung in Echtzeit empfehlen wir zusätzlich eine clientseitige Plausibilitätsprüfung (Mobilfunknummer, E.164-Format), bevor du den Lead pushst.

Abrechnung

API-Leads durchlaufen dieselbe Pipeline wie alle anderen Leads: Abgerechnet werden ausschließlich qualifizierte Leads gemäß deinem Tarif — das Anlegen von Leads und die Webhook-Zustellung sind kostenfrei. Nicht zustellbare Nummern (lead.undeliverable) erzeugen keine Kosten.

Stand: Juli 2026 · API-Version v1 · Fragen an info@phonoflow.de