> ## Knowledge Base Index
> Fetch the complete knowledge base index at: https://help.spreadly.app/sitemap.xml
> Use this file to discover available pages before exploring further.
> Pure-Markdown content can be obtained by appending a '.md' suffix to the content URLs listed in the sitemap (without the trailing slash).

# Leads mit Webhooks senden

*Dies ist eine automatisch aus dem Englischen übersetzte Version. [Originalartikel anzeigen](https://help.spreadly.app/en/article/send-leads-with-a-webhooks-1sff2sq/)*

|| Voraussetzung: Ein öffentlich erreichbarer Endpunkt, der JSON-POST-Anfragen akzeptiert.

Spreadly sendet eine HTTP-POST-Anfrage mit einem JSON-Body, der ein einzelnes Lead-Objekt enthält, sobald ein Lead erstellt oder aktualisiert wird. Die Authentifizierung erfolgt über eine HMAC-SHA-256-Signatur des rohen Anfrage-Bodys.

Typische Ziele:
* Automatisierungsplattformen (Zapier, Make, n8n)
* Serverless (AWS Lambda, Vercel, Cloudflare)
* Benutzerdefinierte APIs/Middleware

---

### Einrichtung

1) Gehe in deinem Spreadly-Dashboard zu: Leads → CRM-Integrationen → Webhook
2) Konfiguriere:
* Webhook-URL: Dein öffentlich zugänglicher Endpunkt
* Geheimschlüssel: Kopiere und speichere ihn sicher (z. B. als `SPREADLY_WEBHOOK_SECRET`)
3) Speichere deine Konfiguration
4) Test senden: Nutze die Schaltfläche „Webhook testen“, um deinen Endpunkt zu überprüfen

Sobald aktiviert, sendet Spreadly das Lead-Objekt bei Erstellung und Aktualisierung per POST.

---

### Authentifizierung

Signaturbasiert (HMAC SHA-256, erforderlich):
* Header: `X-Spreadly-Signature`
* Inhalt: HMAC-SHA-256-Signatur des rohen Anfrage-Bodys, berechnet mit deinem Webhook-Geheimschlüssel

| Hinweis: Verifiziere die Signatur immer mit dem unveränderten, rohen Anfrage-Body

Überprüfungsregeln:
* Berechne HMAC SHA-256 mit `SPREADLY_WEBHOOK_SECRET`
* Verwende die rohen Bytes des Anfrage-Bodys (vor dem Parsen von JSON)
* Vergleiche exakt mit dem `X-Spreadly-Signature`-Header

---

### Überprüfungsbeispiel (Next.js/Node)

```javascript
// /pages/api/spreadly-webhook.js
import crypto from 'crypto';

export const config = {
  api: { bodyParser: false }, // wichtig: roher Body für HMAC
};

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ message: 'Method Not Allowed' });
  }

  const rawBody = await getRawBody(req);
  const secret = process.env.SPREADLY_WEBHOOK_SECRET;

  const signature = req.headers['x-spreadly-signature'];
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  if (!signature || signature !== expectedSignature) {
    return res.status(401).json({ message: 'Invalid signature' });
  }

  // Body ist ein einzelnes Lead-Objekt
  const webhook = JSON.parse(rawBody);

  // Optional: Test-Payloads behandeln (falls aktiviert)
  if (webhook.data.is_test === true) {
    return res.status(200).json({ message: 'Test-Webhook erfolgreich empfangen' });
  }

  // Upsert über lead.id
  // await upsertLead(lead);

  return res.status(200).json({ message: 'Webhook erfolgreich empfangen' });
}

function getRawBody(req) {
  return new Promise((resolve, reject) => {
    const chunks = [];
    req.on('data', chunk => chunks.push(chunk));
    req.on('end', () => resolve(Buffer.concat(chunks)));
    req.on('error', reject);
  });
}
```

---

### Payload-Struktur: Lead (flaches Objekt)

Beispiel-Anfrage-Body:
```json
{
  "type": "lead.created",
  "timestamp": "2025-10-22T19:51:54.000000Z",
  "data": {
    "id": 0,
    "avatar_url": "https://localhost/img/assets/default_avatar.jpg",
    "given_name": "John",
    "family_name": "Doe",
    "job_title": "Sales Manager",
    "department": null,
    "company": "Acme, Inc.",
    "note": "This is a test note",
    "emails": [
      { "id": 0, "email": "j.smith@acme.com" }
    ],
    "phones": [
      { "id": 0, "number": "+39 58273 83572", "type": "mobile" }
    ],
    "websites": [
      { "id": 0, "url": "https://acme.com" }
    ],
    "addresses": [
      {
        "id": 0,
        "line1": "Via Roma 12",
        "line2": null,
        "line3": null,
        "city": "Roma",
        "state": null,
        "postal_code": null,
        "country": "Italy"
      }
    ],
    "custom_fields": [],
    "event_id": null,
    "latitude": null,
    "longitude": null,
    "locale": "en",
    "source": null,
    "enriched_at": null,
    "is_ai_enrichment_completed": true,
    "external_id": null,
    "external_system": null,
    "external_url": null,
    "created_at": "2025-10-22T19:51:54.000000Z",
    "updated_at": "2025-10-22T19:51:54.000000Z"
  }
}
```

Hinweise zu den Feldern:
* id: interne Lead-ID (bleibt bei Aktualisierungen stabil; für Upsert verwenden)
* given_name, family_name, job_title, department, company: Profildaten
* note: optionaler Freitext
* emails[], phones[], websites[], addresses[]: Arrays mit zugehörigen Einträgen
* custom_fields[]: Erweiterbarkeit für dein Schema
* event_id: optionale Ereignis-/Erfassungsreferenz
* latitude, longitude: optionale Geolokalisierung
* locale: Sprach-/Regionalcode
* source: Ursprung (z. B. spreadly_card, scanner_app)
* Anreicherungsfelder: enriched_at, is_ai_enrichment_completed
* external_*: Verknüpfungen zu externen Systemen (falls zutreffend)
* created_at, updated_at: Zeitstempel im ISO-8601-Format

Optionale Flags (falls in deinem Arbeitsbereich aktiviert):
* is_test: true kann auf Root-Ebene enthalten sein, um Test-Payloads zu kennzeichnen

---

### Testen

* Gehe zu Leads → CRM-Integrationen → Webhook und klicke auf „Webhook testen“
* Erwarte HTTP 200, wenn die Verarbeitung erfolgreich war
* Falls aktiviert, enthalten Test-Payloads `is_test: true` im selben flachen Lead-Objekt
* Behandle `is_test: true` als nicht persistent und gib einfach 200 zurück

---

### Fehlerbehebung

Webhook wird nicht ausgelöst:
* Stelle sicher, dass der Endpunkt öffentlich zugänglich ist
* Gib HTTP 200 bei Erfolg zurück
* Überprüfe, ob der Webhook unter Leads → CRM-Integrationen → Webhook aktiviert ist
* Nutze „Webhook testen“, um die Konfiguration zu validieren

Verbindungstest fehlgeschlagen:
* Akzeptiere POST-Anfragen
* Überprüfe URL und Verfügbarkeit
* Bestätige, dass Server/Funktion läuft
* Prüfe die Server-Logs