Emailing
Pre-requisites
Required when creating
- At least one
Foldercreated to organize your campaigns. - At least one
Emailcreated to be used in the campaign.
Required before sending
- At least one
Listcreated containing theContactsyou want to send the email to.
Steps to create an EmailCampaign
1 - Create a Folder resource (if needed)
If you do not already have a Folder, you must create one first by making a POST request to the /v1/folder/ endpoint.
- 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>", //<--- use this ID in the next steps
"name": "<folder_name>",
"description": "<folder_description>"
// ...
}
2 - Create your Email resource
Before creating an EmailCampaign, you must create at least one Email resource containing the email design by making a POST request to the /v1/email/ endpoint.
- HTTP
- cURL
POST /v1/email/ HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"name": "Name of the email",
"description": "Description of the email",
"subject": "Subject of the email",
"preheader": "Preheader text that will appear after the subject",
"fromemail": "[email protected]",
"fromname": "Name of the sender",
"unsubscribetext": "Click here to unsubscribe",
"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": "Name of the email",
"description": "Description of the email",
"subject": "Subject of the email",
"preheader": "Preheader text that will appear after the subject",
"fromemail": "[email protected]",
"fromname": "Name of the sender",
"unsubscribetext": "Click here to unsubscribe",
"editor": "bee",
"body": "<bee_html>",
"json": "<bee_json>"
}'
{
"_id": "<email_id>", //<--- use this ID in the next steps
"name": "Name of the email",
// ...
}
HTML & JSON
We recommend using our visual editor to create the design for the Email resource, it will generate both the HTML body & json attributes. That said, static content is rarely what people want when using the API. To create a dynamic email design we recommend the following options :
Simple Text Replacements
For simple use cases, use our visual editor to create a base design and use it as a template for your dynamic content. Add easily identifiable placeholders like {{my_custom_text}} in the content. We already use the "mustaches" {{...}} syntax as merge tags for contact properties during rendering and strip out any unknown tags before sending. This can be useful for simple text replacements.
Example, you create an EmailCampaign & Email via the UI with Hello {{firstname}}, here is your special offer: {{special_offer_code}} in a text block. You will use this Email as a template. Fetch it and only replace the {{special_offer_code}} tag with your own promo code in both the json & body which you will use to create a new EmailCampaign & Email resources via the API. You kept the {{firstname}} tag as is, it will be replaced when sending with the actual contact's first name by our rendering engine as expected.
This approach is simple but limited to text replacements only, if you need more complex dynamic content with HTML you should consider the next option.
HTML Block
Same approach as above but instead of a text block, use an HTML block. Add a placeholder tag like {{dynamic_content}}. In your code, fetch the Email resource, replace the {{dynamic_content}} tag in both the json &body with your own generated HTML content. You can generate complex HTML content with your own code/templates.
Be careful to generate valid HTML for mail clients which isn't the same as regular web HTML.
3 - Create your EmailCampaign resource
Finally, you can create your EmailCampaign by making a POST request to the /v1/campaign/ endpoint using the Folder ID from step 1 and the Email ID(s) from step 2.
- HTTP
- cURL
POST /v1/campaign/ HTTP/1.1
Host: rest.leadfox.co
Authorization: JWT <jwt>
Content-Type: application/json
{
"name": "Name of the email campaign",
"description": "Description of the email campaign",
"type": 2, /* EMAIL */
"status": "d", /* DRAFT */
"folder": "<folder_id>",
"start": "2026-01-01T00:00:00.000Z",
"batchConfiguration": { "type": "none" },
/* Email variants (A/B testing) */
"emails": [
{ "email": "<email_id>", "weight": 100 }
],
/* Lists of contacts to send to */
"lists": [
{ "list": "<list_id>" }
],
/* Mailing List (if GDPR feature is enabled) */
"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": "Name of the email campaign",
"description": "Description of the email campaign",
"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": "Name of the email campaign",
// ...
}
Our system always assumes that an Email belongs to a single EmailCampaign.
Do not share an Email entity between multiple EmailCampaigns, always create separate entities. If you want to use the same design, simply duplicate the Email entity first. The simplest way to do this is to make a GET request to retrieve the existing Email entity, extract the json & body attributes, then make a POST request to create a new one with the extracted data.
Special "All Contacts" List
By setting the list attribute to null, you will use the special "All Contacts" to send the EmailCampaign to all Contacts of the 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 }] }'
By design, we made it explicit to avoid sending accidentally to all Contacts if no List is specified (campaign.lists is empty).
Excluding Lists
You can exclude specific Lists from your campaign by setting excluded: true. This is useful when you want to target a broad audience but exclude certain segments.
Example: Include one list, exclude another
{
"lists": [
{ "list": "<include_list_id>" },
{ "list": "<exclude_list_id>", "excluded": true }
]
}
Example: Send to all contacts except a specific list
{
"lists": [
{ "list": null },
{ "list": "<exclude_list_id>", "excluded": true }
]
}
Sending your EmailCampaign
Schedule
Setting the start attribute of the EmailCampaign allows you to schedule when the sending should start. To send immediately use the current (or past) datetime.
Flow Control
Setting the batchConfiguration attribute of the EmailCampaign allows you to configure the flow control.
- none (Default)
- fixed_count
- fixed_size
No batching, send as fast as possible all at once.
{ "batchConfiguration": { "type": "none" } }
Send a fixed number of batches with an optional delay (ISO 8601 Duration) between each batch.
When you have a fixed time window to send and want to spread the load.
In the example below, it will send 12 batches with a 1 hour delay between each batch.
{ "batchConfiguration": { "type": "fixed_count", "count": 12, "delay": "PT1H" } }
Send batches of 500 emails with a 10 min delay (ISO 8601 Duration) between each batch.
When you want to limit the number of emails sent per time unit.
In the example below, it will send batches of 500 emails every hour until it's done.
{ "batchConfiguration": { "type": "fixed_size", "size": 500, "delay": "PT1H" }}
Send
When you are ready, simply update the EmailCampaign's status to 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" }
}'
Retrieving EmailCampaign Metrics
After sending an EmailCampaign, you can retrieve performance metrics to analyze your campaign's effectiveness.
Metric API Endpoint
GET /v1/metric/<element_type>/<element_id>/email
Path Parameters:
element_type:campaign- Metrics for anEmailCampaign(all variants)target- Metrics for a specificEmailvariant
element_id: The ID of the element (Campaign or Email)
Query Parameters:
compile=true: Get aggregated totals across all timestartdate+enddate: Get daily metrics for a date range (ISO 8601 format)
Metric Definitions:
| Metric | Description |
|---|---|
sent | Total number of emails successfully sent |
open | Total number of email opens (includes multiple opens by same contact) |
uniqueopen | Number of unique contacts who opened the email (counted once per contact) |
click | Total number of link clicks (includes multiple clicks by same contact) |
uniqueclick | Number of unique contacts who clicked a link (counted once per contact) |
bounce | Number of emails that bounced (hard and soft bounces) |
unsubscribe | Number of contacts who unsubscribed |
spam | Number of spam complaints |
Response Schemas
Total Metrics (compile=true, optional startdate/enddate)
[
{
"_id": <element_id>,
"sent": number,
"open": number,
"uniqueopen": number,
"click": number,
"uniqueclick": number,
"bounce": number,
"unsubscribe": number,
"spam": number
}
]
Daily Metrics (startdate/enddate)
[
{
"_id": { "group": <element_id>, "year": number, "month": number, "day": number },
"sent": number,
"open": number,
"uniqueopen": number,
"click": number,
"uniqueclick": number,
"bounce": number,
"unsubscribe": number,
"spam": number
}
]
Get Total Metrics for a Campaign
To retrieve the total aggregated metrics for an EmailCampaign, use the compile=true parameter:
- 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,
// ...
}
This returns metrics aggregated across all Email variants in the EmailCampaign.
Use target instead of campaign in the path to retrieve metrics for a specific Email variant:
GET /v1/metric/target/<email_id>/email?compile=true
Get Daily Metrics for a Campaign
To retrieve metrics broken down by day for an EmailCampaign:
- HTTP
- cURL
GET /v1/metric/campaign/<campaign_id>/email?startdate=2025-01-01&enddate=2025-01-31 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' \
--header 'Authorization: JWT <JWT>'
[
{
"_id": { "group": "<campaign_id>", "year": 2025, "month": 1, "day": 1 },
"sent": 100,
"open": 25,
// ...
},
{
"_id": { "group": "<campaign_id>", "year": 2025, "month": 1, "day": 2 },
"sent": 100,
"open": 22,
// ...
}
]
Use target instead of campaign in the path to retrieve daily metrics for a specific Email variant:
GET /v1/metric/target/<email_id>/email?...
Daily metrics only include days that have data. Days with no activity will not appear in the response.