Replies
Get the replies of your Emelia campaigns as they come, read them in batches or as a CSV, see what was sent, and answer from the right mailbox.
Replies reach you in several ways. Pick by need:
| Need | Use |
|---|---|
| React the moment someone answers (CRM, Slack, routing) | Webhooks on MAIL_REPLIED, LINKEDIN_REPLIED and WHATSAPP_REPLIED |
| Process replies in batches, every hour or every morning | The activity feed of each campaign, below |
| Every reply of a campaign in one file | Export as CSV with type=replies |
The Python examples use one session:
import os
import requests
session = requests.Session()
session.headers["Authorization"] = os.environ["EMELIA_API_KEY"]Read the replies of a campaign
GET/advanced/campaigns/{campaignId}/activities
The feed returns 30 activities per page, newest first, with page starting at 0. An empty activities array means you reached the end. Pass types=MAIL_REPLIED,LINKEDIN_REPLIED,WHATSAPP_REPLIED (comma separated) to get the replies of every channel in one pass.
curl "https://api.emelia.io/advanced/campaigns/6650f1a2b839d80011c5a0f1/activities?types=MAIL_REPLIED,LINKEDIN_REPLIED&page=0" \
-H "Authorization: $EMELIA_API_KEY"A reply looks like this:
{
"_id": "6650f1a2b839d80011c5e001",
"event": "MAIL_REPLIED",
"date": "2026-10-08T09:12:00.000Z",
"step": 2,
"version": 0,
"contact": {
"_id": "6650f1a2b839d80011c5d001",
"email": "claire.fontaine@nexora.io",
"firstName": "Claire",
"lastName": "Fontaine"
},
"customData": {},
"reply": {
"subject": "Re: Quick question about Nexora",
"text": "Sounds good, call me Tuesday.",
"content": "<p>Sounds good, call me Tuesday.</p>",
"senderName": "Claire Fontaine"
}
}reply.textis the plain text,reply.contentthe HTML.- Filter one contact with
contactId, or search by name, email or LinkedIn URL withsearch. - The feed is cached for up to 10 minutes: a reply that just arrived can take a few minutes to show here. Webhooks are immediate.
See what was sent
To show a reply next to the message that triggered it, rebuild the content of a send activity (SENT, MESSAGE_SENT, INMAIL_SENT, INVITED or WHATSAPP_MESSAGE_SENT):
/advanced/campaigns/{campaignId}/activities/{activityId}/message
curl https://api.emelia.io/advanced/campaigns/6650f1a2b839d80011c5a0f1/activities/6650f1a2b839d80011c5e002/message \
-H "Authorization: $EMELIA_API_KEY"The content is not stored: it is rebuilt from the step and the contact, so it can differ if either changed since. This route answers 404 {"error": "NOT_FOUND"} or 422 {"error": "NO_MESSAGE"} instead of the usual format.
Answer an email reply
POST/emails/reply
This route sends an email from one of your connected mailboxes, whatever the campaign. It comes from the previous system and is marked deprecated in the reference, but it is the route to answer a reply by API today.
| Field | Description |
|---|---|
content | Required. The HTML of your answer. Use <br> or <p> for line breaks. |
providerId or senderEmail | Required, one of the two: the mailbox that sends. providerId is the _id from List email providers. |
messageId | The Message-ID of the email you answer. With it, your answer is threaded, with the quoted history. If Emelia cannot find it, the call fails with "Original message not found". |
to, subject | Required without messageId. |
cc, bcc, attachments | Optional. attachments is a list of { "name", "url" }. |
scheduledAt | Optional ISO date: schedules the send instead of sending now. |
curl -X POST https://api.emelia.io/emails/reply \
-H "Authorization: $EMELIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"senderEmail": "marie.martin@yourcompany.com",
"to": ["claire.fontaine@nexora.io"],
"subject": "Re: Quick question about Nexora",
"content": "Hi Claire,<br><br>Tuesday 10am works. I just sent the invite.<br><br>Marie"
}'Answer from the mailbox that received the reply. The MAIL_REPLIED webhook gives it (sender) along with the messageId of the reply.
Stop a sequence after a reply
By default, a reply by email, LinkedIn or WhatsApp ends the sequence for that contact (eventToStop in the settings). Someone who asks not to be contacted again belongs in the blacklist: it protects all your future campaigns too.