> ## 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).

# Envoyer des leads avec des Webhooks

*Cet article a été traduit automatiquement depuis l'anglais. [View original article](https://help.spreadly.app/en/article/send-leads-with-a-webhooks-1sff2sq/)*

|| Exigence : Un point de terminaison accessible publiquement qui accepte les requêtes POST JSON.

Spreadly envoie une requête HTTP POST avec un corps JSON contenant un seul objet lead chaque fois qu'un lead est créé ou mis à jour. L'authentification utilise une signature HMAC SHA-256 sur le corps brut de la requête.

Destinations typiques :
* Plateformes d'automatisation (Zapier, Make, n8n)
* Serverless (AWS Lambda, Vercel, Cloudflare)
* API personnalisées/middleware

---

### Configuration

1) Dans ton tableau de bord Spreadly, va dans : Leads → Intégrations CRM → Webhook
2) Configure :
* URL du Webhook : Ton point de terminaison accessible publiquement
* Clé secrète : Copie et stocke-la en sécurité (par exemple, `SPREADLY_WEBHOOK_SECRET`)
3) Enregistre ta configuration
4) Envoyer un test : Utilise le bouton « Test webhook » pour vérifier ton point de terminaison

Une fois activé, Spreadly enverra l'objet lead par POST à la création et à la mise à jour.

---

### Authentification

Basée sur une signature (HMAC SHA-256, obligatoire) :
* En-tête : `X-Spreadly-Signature`
* Contenu : Signature HMAC SHA-256 du corps brut de la requête, calculée avec ta Clé Secrète du Webhook

| Remarque : Vérifie toujours la signature en utilisant le corps brut non modifié de la requête

Règles de vérification :
* Calcule le HMAC SHA-256 avec `SPREADLY_WEBHOOK_SECRET`
* Utilise les octets bruts du corps de la requête (avant tout parsing JSON)
* Compare exactement avec l'en-tête `X-Spreadly-Signature`

---

### Exemple de vérification (Next.js/Node)

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

export const config = {
  api: { bodyParser: false }, // important: use raw body for 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 is a single lead object
  const webhook = JSON.parse(rawBody);

  // Optional: handle test payloads (if enabled)
  if (webhook.data.is_test === true) {
    return res.status(200).json({ message: 'Test webhook received successfully' });
  }

  // Upsert by lead.id
  // await upsertLead(lead);

  return res.status(200).json({ message: 'Webhook received successfully' });
}

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);
  });
}
```

---

### Structure de la charge utile : Lead (Objet plat)

Exemple de corps de requête :
```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"
  }
}
```

Remarques sur les champs :
* id : ID interne du lead (stable lors des mises à jour ; à utiliser pour l'upsert)
* given_name, family_name, job_title, department, company : champs de profil
* note : texte libre optionnel
* emails[], phones[], websites[], addresses[] : tableaux d'éléments associés
* custom_fields[] : extensibilité pour ton schéma
* event_id : référence optionnelle à un événement/capture
* latitude, longitude : géolocalisation optionnelle
* locale : code de langue/région
* source : origine (par exemple, spreadly_card, scanner_app)
* champs d'enrichissement : enriched_at, is_ai_enrichment_completed
* external_* : liens vers des systèmes externes si applicable
* created_at, updated_at : horodatages ISO 8601

Drapeaux optionnels (si activés dans ton espace de travail) :
* is_test : true peut être inclus à la racine pour marquer les charges utiles de test

---

### Test

* Va dans Leads → Intégrations CRM → Webhook et clique sur « Test Webhook »
* Attends-toi à un HTTP 200 si le traitement est réussi
* Si activé, les charges utiles de test incluent `is_test: true` sur le même objet lead plat
* Traite `is_test: true` comme non persistant et renvoie simplement 200

---

### Résolution des problèmes

Le webhook ne se déclenche pas :
* Assure-toi que le point de terminaison est accessible publiquement
* Renvoie HTTP 200 en cas de succès
* Vérifie que le webhook est activé dans Leads → Intégrations CRM → Webhook
* Utilise « Test Webhook » pour valider

Échec du test de connexion :
* Accepte POST
* Vérifie l'URL et la disponibilité
* Confirme que le serveur/fonction est en cours d'exécution
* Consulte les journaux du serveur