Reactive CRM Réception de leads multi-contrat depuis le site web ← Guide d'intégration

Réception de leads multi-contrat depuis le site web

Ce document décrit un contrat API unique par lequel le backend du site envoie les données de lead, les coordonnées du visiteur et les métriques UTM marketing à ReactiveCRM en une seule requête.

1. Objectif

L'intégrateur du site n'a pas besoin de créer séparément le contact, le téléphone, l'email, le lead et l'événement marketing. Une seule requête doit créer atomiquement :

  1. le contact ;
  2. le téléphone principal du contact ;
  3. l'email principal du contact, s'il est fourni ;
  4. le lead ;
  5. le lien entre le contact et le lead ;
  6. l'événement marketing et l'attribution UTM.

Si une étape échoue, l'ensemble de la requête est annulé et les données partiellement créées ne sont pas enregistrées.

2. Endpoint

http
POST /api/site/leads
Authorization: Bearer <CRM_ACCESS_TOKEN>
Content-Type: application/json

Le token doit être transmis uniquement depuis le backend du site ou une fonction serverless. Ne placez jamais le token CRM dans le JavaScript du navigateur.

Le locataire est déterminé à partir du token d'autorisation. Tous les UUID fournis sont validés dans ce locataire.

3. Contrat JSON complet

json
{
  "externalId": "site-form-01J7K9A2M4Y5T6",
  "lead": {
    "leadSourceId": "7b33b18f-55bd-48a5-a8f0-e450a56dde47",
    "quality": "WARM",
    "message": "Je souhaite une consultation sur la mise en œuvre du CRM"
  },
  "contact": {
    "firstName": "Ivan",
    "lastName": "Ivanov",
    "phone": "+79991234567",
    "email": "ivan@example.com"
  },
  "marketing": {
    "occurredAt": "2026-09-06T18:00:00Z",
    "visitorId": "visitor-8b7f",
    "sessionId": "session-31ac",
    "source": "website",
    "channel": "paid",
    "utmSource": "google",
    "utmMedium": "cpc",
    "utmCampaign": "summer-consulting",
    "utmContent": "banner-a",
    "utmTerm": "crm consultation",
    "gclid": "EAIaIQobChMI-example",
    "fbclid": null,
    "landingUrl": "https://example.com/consultation",
    "referrer": "https://www.google.com/"
  }
}

4. Champs de la requête

4.1. Champs racine

ChampTypeRequisDescription
externalIdchaînerecommandéID unique stable de l'envoi du formulaire pour l'idempotence
leadobjetouiDonnées du lead en cours de création
contactobjetouiDonnées de la personne de contact
marketingobjetnonMétriques UTM et données techniques de la visite marketing

externalId est généré avant la première tentative d'envoi. Lors de la répétition de la requête après un délai d'attente ou une erreur réseau, utilisez la même valeur.

4.2. L'objet lead

ChampTypeRequisDescription
leadSourceIduuidouiID de la source de leads dans le locataire actuel
qualitychaînenonÉvaluation initiale : HOT, WARM, COOL ou COLD
messagechaînenonMessage du visiteur ou commentaire sur l'envoi

Si le site n'effectue pas de pré-qualification, il est préférable de ne pas envoyer le champ quality.

4.3. L'objet contact

ChampTypeRequisDescription
firstNamechaîneouiPrénom de la personne de contact
lastNamechaînenonNom de famille de la personne de contact
phonechaîneouiTéléphone principal ; format E.164 recommandé
emailchaîne(email)nonEmail principal de la personne de contact

Les données minimales requises pour traiter un envoi sont firstName et phone.

4.4. L'objet marketing

ChampTypeRequisDescription
occurredAtdate-heurenonHeure de l'envoi du formulaire ; l'heure CRM est utilisée en l'absence
visitorIdchaînenonID de visiteur anonyme
sessionIdchaînenonID de session du site
sourcechaînenonSource de l'événement, par défaut website
channelchaînenonCanal : ex. paid, organic, social, email, direct
utmSourcechaînenonValeur de utm_source
utmMediumchaînenonValeur de utm_medium
utmCampaignchaînenonValeur de utm_campaign
utmContentchaînenonValeur de utm_content
utmTermchaînenonValeur de utm_term
gclidchaînenonID de clic Google
fbclidchaînenonID de clic Meta/Facebook
landingUrlchaînenonURL de la page de destination
referrerchaînenonURL de la page précédente

Les données personnelles ne doivent pas être dupliquées dans l'objet marketing. Le nom, le téléphone, l'email et le texte du message sont transmis uniquement dans contact et lead.

5. Requête minimale

json
{
  "externalId": "site-form-550e8400-e29b-41d4-a716-446655440000",
  "lead": {
    "leadSourceId": "7b33b18f-55bd-48a5-a8f0-e450a56dde47"
  },
  "contact": {
    "firstName": "Ivan",
    "phone": "+79991234567"
  }
}

6. Réponse réussie

Première requête — 201 Created

json
{
  "leadId": "22222222-2222-2222-2222-222222222222",
  "contactId": "33333333-3333-3333-3333-333333333333",
  "phoneId": "44444444-4444-4444-4444-444444444444",
  "emailId": "55555555-5555-5555-5555-555555555555",
  "marketingEventId": "66666666-6666-6666-6666-666666666666",
  "duplicate": false,
  "createdAt": "2026-09-06T18:00:01Z"
}

Si les données d'email ou de marketing ne sont pas fournies, les ID correspondants sont renvoyés sous forme de null.

Répétition avec le même externalId — 200 OK

json
{
  "leadId": "22222222-2222-2222-2222-222222222222",
  "contactId": "33333333-3333-3333-3333-333333333333",
  "phoneId": "44444444-4444-4444-4444-444444444444",
  "emailId": "55555555-5555-5555-5555-555555555555",
  "marketingEventId": "66666666-6666-6666-6666-666666666666",
  "duplicate": true,
  "createdAt": "2026-09-06T18:00:01Z"
}

Une requête répétée ne doit pas créer un second lead ou contact.

7. Exemple cURL

bash
curl -X POST "$CRM_BASE_URL/api/site/leads" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "site-form-01J7K9A2M4Y5T6",
    "lead": {
      "leadSourceId": "7b33b18f-55bd-48a5-a8f0-e450a56dde47",
      "quality": "WARM",
      "message": "Rappelez-moi"
    },
    "contact": {
      "firstName": "Ivan",
      "lastName": "Ivanov",
      "phone": "+79991234567",
      "email": "ivan@example.com"
    },
    "marketing": {
      "utmSource": "google",
      "utmMedium": "cpc",
      "utmCampaign": "crm-demo",
      "landingUrl": "https://example.com/demo"
    }
  }'

8. Interfaces TypeScript

ts
type LeadQuality = 'HOT' | 'WARM' | 'COOL' | 'COLD';

interface SiteLeadRequest {
  externalId?: string;
  lead: {
    leadSourceId: string;
    quality?: LeadQuality;
    message?: string;
  };
  contact: {
    firstName: string;
    lastName?: string;
    phone: string;
    email?: string;
  };
  marketing?: {
    occurredAt?: string;
    visitorId?: string;
    sessionId?: string;
    source?: string;
    channel?: string;
    utmSource?: string;
    utmMedium?: string;
    utmCampaign?: string;
    utmContent?: string;
    utmTerm?: string;
    gclid?: string;
    fbclid?: string;
    landingUrl?: string;
    referrer?: string;
  };
}

interface SiteLeadResponse {
  leadId: string;
  contactId: string;
  phoneId: string;
  emailId: string | null;
  marketingEventId: string | null;
  duplicate: boolean;
  createdAt: string;
}

9. Exemple côté serveur

ts
export async function sendLeadToCrm(payload: SiteLeadRequest): Promise<SiteLeadResponse> {
  const response = await fetch(`${process.env.CRM_BASE_URL}/api/site/leads`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.CRM_ACCESS_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    const body = await response.text();
    throw new Error(`ReactiveCRM returned ${response.status}: ${body}`);
  }

  return response.json() as Promise<SiteLeadResponse>;
}

10. Erreurs

HTTPCauseAction de l'intégrateur
400Erreur de format, champ requis manquant, email/téléphone/quality invalideCorrigez les données ; ne réessayez pas automatiquement sans modifications
401Token manquant ou invalideRafraîchissez le token d'intégration
403Pas d'accès au locataire ou à l'opérationVérifiez l'utilisateur d'intégration et le rôle
404leadSourceId non trouvé dans le locataire actuelMettez à jour l'ID de la source dans les paramètres du site
409externalId est déjà lié à une requête incompatibleVérifiez la génération de l'ID et le journal d'intégration
5xxErreur CRM transitoireRéessayez la même requête avec le même externalId

Exemple d'erreur de validation :

json
{
  "status": 400,
  "error": "Bad Request",
  "message": "contact.phone must not be blank",
  "path": "/api/site/leads"
}

11. Idempotence

12. Mini-guide pour le développeur du site

  1. Lors de la première visite, stockez les balises UTM, gclid, fbclid, l'URL de destination et le référent.
  2. Lorsque le formulaire est soumis, générez un externalId stable.
  3. Envoyez le formulaire au backend du site.
  4. Le backend ajoute le token CRM et appelle POST /api/site/leads.
  5. Sur 201 ou 200 avec duplicate: true, considérez l'envoi comme livré.
  6. En cas de délai d'attente ou de 5xx, réessayez la requête avec le même externalId.
  7. N'envoyez jamais le token CRM directement depuis le navigateur.

13. Ce que le gestionnaire CRM obtient

Après une requête réussie, le CRM contient un lead qui :

Cet ensemble est suffisant pour que le gestionnaire voie l'envoi, appelle le contact et qualifie le lead.