# Synchroniser un lead Elementor vers HubSpot sans dépendre d’un webhook fragile

> Architecture de synchronisation basée sur une file d'attente plutôt que sur un webhook direct depuis Elementor Pro Forms vers HubSpot.

- Auteur : Clément Hadrot
- Publié le : 2024-08-29
- Mis à jour le : 2024-08-29
- Catégorie : Elementor
- URL : https://wpmoderne.dev.wordpress-developpement.fr/elementor/elementor-hubspot-crm-synchroniser-lead-sans-webhook/

## L’essentiel

- File d'attente locale plutôt qu'appel API synchrone
- Nouvelles tentatives automatiques en cas d'échec temporaire
- Aucun lead perdu même en cas de panne HubSpot

Pourquoi un lead capturé par un formulaire Elementor Pro Forms disparaît-il parfois sans jamais apparaître dans HubSpot ? Après plusieurs incidents de ce type sur un site B2B à fort trafic commercial, la réponse est devenue évidente : l'intégration en place appelait l'API HubSpot directement et de façon synchrone au moment de la soumission du formulaire, sans aucune reprise en cas d'échec temporaire du service tiers.

Un appel API synchrone déclenché depuis `elementor_pro/forms/new_record` fonctionne parfaitement tant que HubSpot répond dans les temps. Dès qu'une latence anormale ou une indisponibilité momentanée survient côté HubSpot, l'appel échoue, et sans mécanisme de nouvelle tentative, le lead est simplement perdu, sans trace ni alerte.

## Le problème structurel de l'appel direct

Un appel synchrone bloque également, même brièvement, la réponse renvoyée au visiteur qui vient de soumettre le formulaire : si l'API HubSpot met trois secondes à répondre, le visiteur attend ces trois secondes avant de voir le message de confirmation, une expérience dégradée que l'architecture initiale ignorait.

## La file d'attente comme couche de fiabilité

La solution retenue introduit une étape intermédiaire : plutôt que d'appeler HubSpot directement depuis le hook Elementor, chaque soumission de formulaire écrit d'abord une entrée dans une table dédiée, avec un statut « en attente ». Un traitement différé, déclenché par une tâche planifiée WP-Cron toutes les minutes, vient ensuite traiter les entrées en attente, un par un.

> L'essentiel à retenir : File d'attente locale plutôt qu'appel API synchrone ; Nouvelles tentatives automatiques en cas d'échec temporaire ; Aucun lead perdu même en cas de panne HubSpot

```
add_action('elementor_pro/forms/new_record', function ($record, $handler) {
    global $wpdb;
    $fields = $record->get('fields');

    $wpdb->insert($wpdb->prefix . 'file_hubspot', [
        'donnees' => wp_json_encode([
            'email' => $fields['email']['value'] ?? '',
            'nom'   => $fields['nom']['value'] ?? '',
        ]),
        'statut' => 'en_attente',
        'tentatives' => 0,
        'date_creation' => current_time('mysql'),
    ]);
}, 10, 2);

add_action('traiter_file_hubspot', function () {
    global $wpdb;
    $lignes = $wpdb->get_results(
        "SELECT * FROM {$wpdb->prefix}file_hubspot WHERE statut = 'en_attente' AND tentatives < 6 LIMIT 20"
    );

    foreach ($lignes as $ligne) {
        $donnees = json_decode($ligne->donnees, true);
        $reponse = wp_remote_post('https://api.hubapi.com/crm/v3/objects/contacts', [
            'headers' => ['Authorization' => 'Bearer ' . getenv('HUBSPOT_TOKEN')],
            'body' => wp_json_encode(['properties' => $donnees]),
            'timeout' => 10,
        ]);

        $succes = !is_wp_error($reponse) && wp_remote_retrieve_response_code($reponse) < 300;
        $wpdb->update($wpdb->prefix . 'file_hubspot', [
            'statut' => $succes ? 'envoye' : 'en_attente',
            'tentatives' => $ligne->tentatives + 1,
        ], ['id' => $ligne->id]);
    }
});

if (!wp_next_scheduled('traiter_file_hubspot')) {
    wp_schedule_event(time(), 'chaque_minute', 'traiter_file_hubspot');
}
```

## Ce que ce découplage apporte concrètement

Le visiteur reçoit une confirmation immédiate à la soumission du formulaire, sans attendre la réponse de HubSpot. En cas d'indisponibilité temporaire du CRM, les leads s'accumulent simplement dans la file d'attente en statut « en attente » plutôt que d'être perdus, et sont traités automatiquement dès que le service redevient disponible.

- Réponse immédiate au visiteur, indépendante de la disponibilité de HubSpot
- Six tentatives automatiques espacées, avant un abandon définitif signalé par email interne
- Historique complet conservé en base pour rejouer manuellement un envoi si nécessaire

## Surveiller la file elle-même

Une alerte est envoyée à l'équipe technique dès qu'un lead atteint ses six tentatives sans succès, ce qui a permis, sur les trois premiers mois, d'identifier deux incidents distincts côté HubSpot avant même que le client ne s'en aperçoive.

Cette architecture ne couvre volontairement pas la configuration du CRM HubSpot lui-même (propriétés personnalisées, pipelines), ni les workflows marketing déclenchés une fois le contact créé, deux sujets qui relèvent de la configuration métier de HubSpot, indépendante de cette couche de fiabilité technique.

> Un webhook direct fonctionne parfaitement jusqu'au jour où le service distant tombe : c'est précisément ce jour-là qu'une file d'attente locale fait toute la différence.

## En résumé

Découpler la capture d'un lead Elementor de son envoi effectif vers HubSpot, via une file d'attente locale traitée par WP-Cron, élimine le risque de perte silencieuse en cas d'indisponibilité temporaire du CRM. Le coût de cette robustesse reste modeste : une table supplémentaire, une tâche planifiée, et une surveillance des échecs répétés.
