Website-Formular zum Lead
Legen Sie jede Anfrage über das Formular auf Ihrer Website sofort als Lead in Klantly an, mit der Nachricht als Notiz und auf Wunsch einem Deal.
Ein Besucher füllt das Kontaktformular auf Ihrer Website aus. Mit wenigen Anfragen steht diese Anfrage als Lead in Klantly, mit der Nachricht dazu und einer Karte auf Ihrem Pipeline-Board.
Warnung
Senden Sie das Formular an Ihren eigenen Server und stellen Sie die API-Anfragen von dort. Ein API-Schlüssel gehört nie in den Code Ihrer Website: Dort kann ihn jeder lesen.
Was Sie brauchen
Einen API-Schlüssel mit diesen Scopes:
| Scope | Wofür |
|---|---|
customers.read |
Prüfen, ob die E-Mail-Adresse schon bekannt ist. |
customers.write |
Den Lead erstellen und die Notiz hinzufügen. |
deals.write |
Optional: den Lead auf das Pipeline-Board setzen. |
Schritt 1: Gibt es den Kunden schon?
Eine E-Mail-Adresse ist innerhalb Ihres Unternehmens eindeutig. Prüfen Sie daher zuerst, ob sie schon bekannt ist:
curl --globoff "https://app.klantly.com/api/v1/customers?filter[email]=jan@example.com" \
-H "Authorization: Bearer $KLANTLY_API_KEY"Ist data leer, erstellen Sie den Lead. Andernfalls verwenden Sie die id des Kunden, den Sie zurückbekommen.
Schritt 2: Den Lead erstellen
curl -X POST "https://app.klantly.com/api/v1/customers" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: form-8f14e45f" \
-d '{"email": "jan@example.com", "name": "Jan de Vries", "phone": "+31 6 12345678"}'Geben Sie jeder Einsendung einen eigenen Idempotency-Key, zum Beispiel die ID der Einsendung in Ihrer eigenen Datenbank. Klickt ein Besucher zweimal auf Senden oder versucht Ihr Server es nach einem Timeout erneut, entsteht trotzdem nur ein Lead. Mehr dazu unter Idempotenz.
Kommen zwei Einsendungen mit derselben E-Mail-Adresse fast gleichzeitig an, kann die zweite einen 422 mit einem Fehler bei email liefern. Suchen Sie den Kunden dann erneut, wie in Schritt 1.
Schritt 3: Die Nachricht als Notiz
curl -X POST "https://app.klantly.com/api/v1/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/notes" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: form-8f14e45f-note" \
-d '{"content": "Über das Website-Formular: Ich hätte gern ein Angebot für eine Terrassenüberdachung von 5 mal 3 Metern."}'Schritt 4: Ein Deal auf dem Board (optional)
curl -X POST "https://app.klantly.com/api/v1/deals" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: form-8f14e45f-deal" \
-d '{"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70", "title": "Terrassenüberdachung 5x3 m"}'Ein Kunde hat nur einen offenen Deal gleichzeitig. Gibt es schon einen, erhalten Sie 409 mit dem Code conflict und der ID dieses Deals in deal_id. Das ist kein echter Fehler: Die Anfrage gehört dann zu dem Deal, der bereits läuft.
Alles zusammen
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
function sendLeadToKlantly(array $form, string $submissionId): void
{
$klantly = new Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
// 1. Gibt es den Kunden schon?
$found = json_decode((string) $klantly->get('customers', [
'query' => ['filter' => ['email' => $form['email']]],
])->getBody(), true)['data'];
// 2. Wenn nicht: den Lead erstellen.
$customer = $found[0] ?? json_decode((string) $klantly->post('customers', [
'headers' => ['Idempotency-Key' => "form-{$submissionId}"],
'json' => array_filter(['email' => $form['email'], 'name' => $form['name'], 'phone' => $form['phone']]),
])->getBody(), true)['data'];
// 3. Die Nachricht als Notiz.
$klantly->post("customers/{$customer['id']}/notes", [
'headers' => ['Idempotency-Key' => "form-{$submissionId}-note"],
'json' => ['content' => $form['message']],
]);
// 4. Ein Deal; 409 bedeutet, dass es schon einen offenen Deal gibt.
try {
$klantly->post('deals', [
'headers' => ['Idempotency-Key' => "form-{$submissionId}-deal"],
'json' => ['customer_id' => $customer['id'], 'title' => $form['subject']],
]);
} catch (ClientException $e) {
if ($e->getResponse()->getStatusCode() !== 409) {
throw $e;
}
}
}const BASE_URL = 'https://app.klantly.com/api/v1';
async function klantly(method, path, { body, idempotencyKey } = {}) {
const response = await fetch(`${BASE_URL}/${path}`, {
method,
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
...(body ? { 'Content-Type': 'application/json' } : {}),
...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
return { status: response.status, json: await response.json() };
}
export async function sendLeadToKlantly(form, submissionId) {
// 1. Gibt es den Kunden schon?
const found = await klantly('GET', `customers?${new URLSearchParams({ 'filter[email]': form.email })}`);
if (found.status !== 200) throw new Error(found.json.detail ?? found.json.title);
let customer = found.json.data[0];
// 2. Wenn nicht: den Lead erstellen.
if (!customer) {
const created = await klantly('POST', 'customers', {
body: { email: form.email, name: form.name, ...(form.phone ? { phone: form.phone } : {}) },
idempotencyKey: `form-${submissionId}`,
});
if (created.status !== 201) throw new Error(created.json.detail ?? created.json.title);
customer = created.json.data;
}
// 3. Die Nachricht als Notiz.
await klantly('POST', `customers/${customer.id}/notes`, {
body: { content: form.message },
idempotencyKey: `form-${submissionId}-note`,
});
// 4. Ein Deal; 409 bedeutet, dass es schon einen offenen Deal gibt.
const deal = await klantly('POST', 'deals', {
body: { customer_id: customer.id, title: form.subject },
idempotencyKey: `form-${submissionId}-deal`,
});
if (deal.status !== 201 && deal.status !== 409) throw new Error(deal.json.detail ?? deal.json.title);
}Fehler abfangen
422mitvalidation_failed: zum Beispiel eine ungültige E-Mail-Adresse. Inerrorssteht pro Feld, was nicht stimmt. Lassen Sie den Besucher es korrigieren.429mitrate_limited: Warten Sie die Anzahl Sekunden ausRetry-Afterab und versuchen Sie es erneut. Siehe Rate Limits.- Ein
5xx-Fehler oder ein Timeout: Versuchen Sie es später erneut mit demselbenIdempotency-Key. Stellen Sie die Einsendung am besten in eine Warteschlange, dann geht nie eine Anfrage verloren.
Tipp
Möchten Sie wissen, wann ein Lead zum Kunden wird? Hören Sie mit einem Webhook auf das Event customer.converted.
Zuletzt aktualisiert am 15. September 2026