Envoi d'emails
Prérequis
Requis à la création
- Au moins un
Foldercréé pour organiser vos campagnes. - Au moins un
Emailcréé pour être utilisé dans la campagne.
Requis avant l'envoi
- Au moins une
Listcréée contenant lesContactsà qui vous voulez envoyer l'email.
Étapes pour créer une EmailCampaign
1 - Créer une ressource Folder (si nécessaire)
Si vous n'avez pas encore de Folder, créez-en un d'abord avec une requête POST sur l'endpoint /v1/folder/.
- HTTP
- cURL
POST /v1/folder/ HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"name": "<folder_name>",
"description": "<folder_description>"
}
curl \
--location 'https://rest.leadfox.co/v1/folder/' \
--header 'Content-Type: application/json' \
--header 'Authorization: JWT <JWT>' \
--data '{
"name": "<folder_name>",
"description": "<folder_description>"
}'
{
"_id": "<folder_id>", //<--- utilisez cet ID dans les prochaines étapes
"name": "<folder_name>",
"description": "<folder_description>"
// ...
}
2 - Créer votre ressource Email
Avant de créer une EmailCampaign, vous devez créer au moins une ressource Email contenant le design de l'email, avec une requête POST sur l'endpoint /v1/email/.
- HTTP
- cURL
POST /v1/email/ HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"name": "Nom de l'email",
"description": "Description de l'email",
"subject": "Sujet de l'email",
"preheader": "Texte de preheader affiché après le sujet",
"fromemail": "[email protected]",
"fromname": "Nom de l'expéditeur",
"unsubscribetext": "Cliquez ici pour vous désabonner",
"editor": "bee",
"body": "<bee_html>",
"json": "<bee_json>"
}
curl \
--location 'https://rest.leadfox.co/v1/email/' \
--header 'Content-Type: application/json' \
--header 'Authorization: JWT <JWT>' \
--data '{
"name": "Nom de l'\''email",
"description": "Description de l'\''email",
"subject": "Sujet de l'\''email",
"preheader": "Texte de preheader affiché après le sujet",
"fromemail": "[email protected]",
"fromname": "Nom de l'\''expéditeur",
"unsubscribetext": "Cliquez ici pour vous désabonner",
"editor": "bee",
"body": "<bee_html>",
"json": "<bee_json>"
}'
{
"_id": "<email_id>", //<--- utilisez cet ID dans les prochaines étapes
"name": "Nom de l'email",
// ...
}
HTML & JSON
Nous recommandons d'utiliser notre éditeur visuel pour créer le design de la ressource Email ; il génère à la fois le body HTML et l'attribut json. Cela dit, un contenu statique est rarement ce que l'on veut en passant par l'API. Pour créer un design d'email dynamique, nous recommandons les options suivantes :
Remplacements de texte simples
Pour les cas simples, créez un design de base avec notre éditeur visuel et utilisez-le comme template pour votre contenu dynamique. Ajoutez des placeholders facilement identifiables comme {{my_custom_text}} dans le contenu. Nous utilisons déjà la syntaxe « moustaches » {{...}} comme merge tags pour les propriétés de contact lors du rendu, et nous retirons tout tag inconnu avant l'envoi. C'est pratique pour des remplacements de texte simples.
Par exemple, vous créez une EmailCampaign & un Email via l'UI avec Bonjour {{firstname}}, voici votre offre spéciale : {{special_offer_code}} dans un bloc de texte. Vous utilisez cet Email comme template. Récupérez-le et remplacez uniquement le tag {{special_offer_code}} par votre propre code promo, dans le json & le body, que vous utilisez ensuite pour créer de nouvelles ressources EmailCampaign & Email via l'API. Vous avez laissé le tag {{firstname}} tel quel : il sera remplacé à l'envoi par le prénom réel du contact par notre moteur de rendu, comme prévu.
Cette approche est simple mais limitée aux remplacements de texte ; si vous avez besoin d'un contenu dynamique plus complexe en HTML, considérez l'option suivante.
Bloc HTML
Même approche que ci-dessus mais avec un bloc HTML plutôt qu'un bloc de texte. Ajoutez un tag placeholder comme {{dynamic_content}}. Dans votre code, récupérez la ressource Email et remplacez le tag {{dynamic_content}} dans le json & le body par votre propre contenu HTML généré. Vous pouvez générer du HTML complexe avec votre propre code ou vos propres templates.
Prenez soin de générer du HTML valide pour les clients mail, qui n'est pas le même que le HTML web habituel.
3 - Créer votre ressource EmailCampaign
Enfin, créez votre EmailCampaign avec une requête POST sur l'endpoint /v1/campaign/, en utilisant l'ID du Folder de l'étape 1 et le ou les IDs d'Email de l'étape 2.
- HTTP
- cURL
POST /v1/campaign/ HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"name": "Nom de la campagne email",
"description": "Description de la campagne email",
"type": 2, /* EMAIL */
"status": "d", /* DRAFT */
"folder": "<folder_id>",
"start": "2026-01-01T00:00:00.000Z",
"batchConfiguration": { "type": "none" },
/* Variantes d'email (tests A/B) */
"emails": [
{ "email": "<email_id>", "weight": 100 }
],
/* Listes de contacts à qui envoyer */
"lists": [
{ "list": "<list_id>" }
],
/* Mailing List (si la fonctionnalité RGPD est activée) */
"mailinglist": {
"mailinglist": "<mailinglist_id>",
"statusFilter": 0, /* OPT_IN_ONLY: 0, UNDEFINED_ONLY: 1, OPT_IN_OR_UNDEFINED: 2 */
"language": null, /* "fr", "en" */
},
}
curl \
--location 'https://rest.leadfox.co/v1/campaign/' \
--header 'Content-Type: application/json' \
--header 'Authorization: JWT <JWT>' \
--data '{
"name": "Nom de la campagne email",
"description": "Description de la campagne email",
"type": 2,
"folder": "<folder_id>",
"status": "d",
"start": "2026-01-01T00:00:00.000Z",
"batchConfiguration": { "type": "none" },
"emails": [{ "email": "<email_id>", "weight": 100 }],
"lists": [{ "list": "<list_id>" }],
"mailinglist": {
"mailinglist": "<mailinglist_id>",
"statusFilter": 2,
"language": null
}
}'
{
"_id": "<campaign_id>",
"name": "Nom de la campagne email",
// ...
}
Notre système suppose toujours qu'un Email appartient à une seule EmailCampaign.
Ne partagez pas une entité Email entre plusieurs EmailCampaigns ; créez toujours des entités distinctes. Pour réutiliser le même design, dupliquez d'abord l'entité Email. Le plus simple est de faire une requête GET pour récupérer l'Email existant, d'en extraire les attributs json & body, puis de faire une requête POST pour en créer un nouveau avec ces données.
La liste spéciale « Tous les contacts »
En mettant l'attribut list à null, vous utilisez la liste spéciale « Tous les contacts » pour envoyer l'EmailCampaign à tous les Contacts du Client :
- HTTP
- cURL
PUT /v1/campaign/<campaign_id> HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{ "lists": [{ "list": null }] }
curl \
--request PUT \
--location 'https://rest.leadfox.co/v1/campaign/<campaign_id>' \
--header 'Content-Type: application/json' \
--header 'Authorization: JWT <JWT>' \
--data '{ "lists": [{ "list": null }] }'
Nous avons volontairement rendu ce choix explicite pour éviter un envoi accidentel à tous les Contacts lorsqu'aucune List n'est spécifiée (campaign.lists vide).
Exclure des listes
Vous pouvez exclure des Lists précises de votre campagne avec excluded: true. C'est utile pour cibler une large audience tout en excluant certains segments.
Exemple : inclure une liste, en exclure une autre
{
"lists": [
{ "list": "<include_list_id>" },
{ "list": "<exclude_list_id>", "excluded": true }
]
}
Exemple : envoyer à tous les contacts sauf une liste précise
{
"lists": [
{ "list": null },
{ "list": "<exclude_list_id>", "excluded": true }
]
}
Envoyer votre EmailCampaign
Planification
L'attribut start de l'EmailCampaign permet de planifier le début de l'envoi. Pour envoyer immédiatement, utilisez la date et l'heure actuelles (ou passées).
Contrôle du débit
L'attribut batchConfiguration de l'EmailCampaign permet de configurer le contrôle du débit.
- none (défaut)
- fixed_count
- fixed_size
Pas de lots, tout est envoyé d'un coup aussi vite que possible.
{ "batchConfiguration": { "type": "none" } }
Envoie un nombre fixe de lots avec un délai optionnel (durée ISO 8601) entre chaque lot.
Pour une fenêtre d'envoi fixe où vous voulez répartir la charge.
Dans l'exemple ci-dessous, 12 lots sont envoyés avec 1 heure de délai entre chacun.
{ "batchConfiguration": { "type": "fixed_count", "count": 12, "delay": "PT1H" } }
Envoie des lots d'une taille fixe avec un délai (durée ISO 8601) entre chaque lot.
Pour limiter le nombre d'emails envoyés par unité de temps.
Dans l'exemple ci-dessous, des lots de 500 emails sont envoyés chaque heure jusqu'à la fin.
{ "batchConfiguration": { "type": "fixed_size", "size": 500, "delay": "PT1H" }}
Envoi
Lorsque vous êtes prêt, mettez simplement le status de l'EmailCampaign à a (ACTIVE).
- HTTP
- cURL
PUT /v1/campaign/<campaign_id> HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"status": "a",
"start": "2024-06-01T12:00:00.000Z",
"batchConfiguration": { "type": "none" }
}
curl \
--request PUT \
--location 'https://rest.leadfox.co/v1/campaign/<campaign_id>' \
--header 'Content-Type: application/json' \
--header 'Authorization: JWT <JWT>' \
--data '{
"status": "a",
"start": "2026-01-01T00:00:00.000Z",
"batchConfiguration": { "type": "none" }
}'
Récupérer les métriques d'une EmailCampaign
Après l'envoi d'une EmailCampaign, vous pouvez récupérer ses métriques de performance pour analyser son efficacité.
Endpoint de métriques
GET /v1/metric/<element_type>/<element_id>/email
Paramètres de path :
element_type:campaign- Métriques d'uneEmailCampaign(toutes les variantes)target- Métriques d'une varianteEmailpréciseowner- Métriques de toutes lesEmailCampaignsdu client
element_id: L'ID de l'élément (Campaign, Email, ou Client pourowner)
Paramètres de requête :
compile=true: Totaux agrégés sur toute la périodestartdate+enddate: Métriques pour une plage de dates (format ISO 8601), groupées par jour par défautgroupBy:day(défaut),weekoumonth— s'applique seulement avecstartdate+enddate. Lorsqu'il est fourni, la plagestartdate/enddateest limitée à 12 mois (400 au-delà) ; cette limite ne s'applique pas lorsquegroupByest omis.breakdown:campaign,automation,folderoutarget— valide seulement avecelement_type=owner. Retourne une ventilation par élément en plus du total agrégé, plutôt qu'un seul agrégat. Une cinquième valeur,source, existe uniquement sur le subjectsession(ventilation par source de trafic, avec les sous-sources imbriquées danschildren) et ne s'applique pas aux métriques email. La réponse contient aussisummary: les totaux du owner sur toute la plage (avec les taux), pour éviter d'additionner les buckets ou de faire un second appel.timezone: Nom de fuseau horaire IANA (ex.America/Toronto). Interprètestartdate/enddatecomme des jours locaux de ce fuseau et groupegroupBydans ce fuseau. UTC par défaut.
Définition des métriques :
| Métrique | Description |
|---|---|
sent | Nombre total d'emails envoyés avec succès |
open | Nombre total d'ouvertures (inclut les ouvertures multiples d'un même contact) |
uniqueopen | Nombre de contacts uniques ayant ouvert l'email (compté une fois par contact) |
click | Nombre total de clics sur des liens (inclut les clics multiples d'un même contact) |
uniqueclick | Nombre de contacts uniques ayant cliqué sur un lien (compté une fois par contact) |
bounce | Nombre d'emails rebondis (hard et soft bounces) |
unsubscribe | Nombre de contacts qui se sont désabonnés |
spam | Nombre de plaintes pour spam |
openRate | uniqueopen / sent * 100, arrondi à 2 décimales, 0 lorsque sent vaut 0 |
clickRate | uniqueclick / sent * 100, arrondi à 2 décimales, 0 lorsque sent vaut 0 |
unsubscribeRate | unsubscribe / sent * 100, arrondi à 2 décimales, 0 lorsque sent vaut 0 |
Les champs de taux apparaissent sur la ligne compile=true, sur chaque bucket groupBy et sur chaque élément/summary de breakdown — toujours, que groupBy soit utilisé ou non.
Schémas de réponse
Métriques totales (compile=true, startdate/enddate optionnels)
[
{
"_id": <element_id>,
"sent": number,
"open": number,
"uniqueopen": number,
"click": number,
"uniqueclick": number,
"bounce": number,
"unsubscribe": number,
"spam": number,
"openRate": number,
"clickRate": number,
"unsubscribeRate": number
}
]
Métriques quotidiennes (startdate/enddate, groupBy=day)
[
{
"_id": { "group": <element_id>, "year": number, "month": number, "day": number },
"date": string, // début du bucket, ISO 8601 UTC (minuit local dans `timezone`, sinon UTC)
"sent": number,
"open": number,
"uniqueopen": number,
"click": number,
"uniqueclick": number,
"bounce": number,
"unsubscribe": number,
"spam": number,
"openRate": number,
"clickRate": number,
"unsubscribeRate": number
}
]
Métriques hebdomadaires (startdate/enddate, groupBy=week)
[
{
"_id": { "group": <element_id>, "isoYear": number, "isoWeek": number },
"date": string, // début du bucket : minuit local du lundi de la semaine ISO
"sent": number,
// ...mêmes métriques et taux que ci-dessus
}
]
Métriques mensuelles (startdate/enddate, groupBy=month)
[
{
"_id": { "group": <element_id>, "year": number, "month": number },
"date": string, // début du bucket : minuit local du 1er
"sent": number,
// ...mêmes métriques et taux que ci-dessus
}
]
Lorsque groupBy est fourni, la réponse est complétée par des zéros : exactement une ligne par bucket de startdate
à enddate inclusivement, en ordre croissant, avec toutes les métriques à 0 pour les buckets sans activité. Omettre
groupBy conserve l'ancien comportement (buckets par jour, mais seulement pour les jours ayant des données, sans champ date
ni champs de taux) pour les intégrations existantes.
Métriques ventilées (element_type=owner, breakdown=campaign|automation|folder|target)
{
"total": [ /* même forme que ci-dessus, pour le groupBy demandé */ ],
"items": [
{
"id": <campaign_or_automation_or_folder_or_email_id>,
"name": string | null, // résolu depuis la collection de l'élément ; null pour breakdown=target ou un document manquant
"type": number | null, // type de campagne, breakdown=campaign seulement
"start": Date | null, // date d'envoi de la campagne, lorsque définie
"created": Date | null,
"deleted": boolean, // les éléments supprimés (soft delete) conservent leurs métriques et sont signalés ici
"totals": {
"sent": number,
"open": number,
"uniqueopen": number,
"click": number,
"uniqueclick": number,
"bounce": number,
"unsubscribe": number,
"spam": number,
"openRate": number,
"clickRate": number,
"unsubscribeRate": number
}
}
],
"summary": {
// même forme que les `totals` d'un élément - les totaux du owner sur toute la plage, avec les taux
}
}
items ne liste que les éléments ayant au moins une métrique non nulle dans la plage, triés par sent décroissant. Il n'y a pas de limite au nombre d'éléments retournés — un client avec 2 000 campagnes reçoit 2 000 éléments. Chaque élément porte ses champs d'affichage (name, type, start, created, deleted) résolus dans la même agrégation ; inutile de lister les campagnes ou les automatisations séparément pour les nommer.
Obtenir les métriques totales d'une campagne
Pour récupérer les métriques totales agrégées d'une EmailCampaign, utilisez le paramètre compile=true :
- HTTP
- cURL
GET /v1/metric/campaign/<campaign_id>/email?compile=true HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
curl \
--location 'https://rest.leadfox.co/v1/metric/campaign/<campaign_id>/email?compile=true' \
--header 'Authorization: JWT <JWT>'
{
"_id": "<campaign_id>",
"sent": 1000,
"open": 250,
// ...
}
Retourne les métriques agrégées de toutes les variantes Email de l'EmailCampaign.
Utilisez target plutôt que campaign dans le path pour récupérer les métriques d'une variante Email précise :
GET /v1/metric/target/<email_id>/email?compile=true
Obtenir les métriques quotidiennes d'une campagne
Pour récupérer les métriques d'une EmailCampaign ventilées par jour, complétées par des zéros sur toute la plage :
- HTTP
- cURL
GET /v1/metric/campaign/<campaign_id>/email?startdate=2025-01-01&enddate=2025-01-31&groupBy=day HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
curl \
--location 'https://rest.leadfox.co/v1/metric/campaign/<campaign_id>/email?startdate=2025-01-01&enddate=2025-01-31&groupBy=day' \
--header 'Authorization: JWT <JWT>'
[
{
"_id": { "group": "<campaign_id>", "year": 2025, "month": 1, "day": 1 },
"date": "2025-01-01T00:00:00.000Z",
"sent": 100,
"open": 25,
// ...
},
{
"_id": { "group": "<campaign_id>", "year": 2025, "month": 1, "day": 2 },
"date": "2025-01-02T00:00:00.000Z",
"sent": 0,
"open": 0,
// aucune activité ce jour-là, toutes les métriques sont à 0 - la ligne est tout de même présente
}
// ...une ligne par jour jusqu'au 2025-01-31
]
Utilisez target plutôt que campaign dans le path pour récupérer les métriques quotidiennes d'une variante Email précise :
GET /v1/metric/target/<email_id>/email?...
Omettre groupBy conserve l'ancien comportement pour les intégrations existantes : des buckets par jour, mais seulement
pour les jours ayant des données (pas de zéros, pas de champ date). Passez groupBy=day (ou week/month) pour obtenir
la plage complète, complétée par des zéros, décrite ci-dessus.