# Activity on an advanced (multichannel) campaign

Source: https://docs.emelia.io/docs/webhooks/campaign-activity

Guide: [Webhooks](https://docs.emelia.io/docs/webhooks.md)

Webhook event `advancedCampaignActivity`: Emelia sends an HTTP POST request to your URL.

Sent to URLs registered with `type: advanced`.

- `EMAIL_SENT`: email step sent (the documented name `MAIL_SENT` never fires).
- `OPENED`, `CLICKED`, `UNSUBSCRIBED`: same tracking rules as legacy email, delivered 30 to 60 seconds later; contact without `id`, no `sender`.
- `MAIL_REPLIED`: first email reply, with `reply`, `sentiment`, `sender`, `senderName`, `messageId`, `campaignId`.
- `BOUNCED`: bounce detected; no `campaign` field, `step` 0.
- `VISITED`, `INVITED`, `ACCEPTED`, `MESSAGE_SENT` (text in `content`), `INMAIL_SENT`, `LIKED`: LinkedIn actions.
- `LINKEDIN_REPLIED`: LinkedIn reply with `reply` and `sentiment`; `campaignId`, `linkedinUrlProfile` and `linkedinId` only when detected in real time.
- `WHATSAPP_MESSAGE_SENT`, `WHATSAPP_REPLIED`: WhatsApp message sent, reply received (`reply`).
- `CAMPAIGN_ENDING`: see the campaignEnding webhook.

Never sent: `SENT`, `MAIL_SENT`, `FOLLOWED`, `TASK_COMPLETED`, `TASK_FAILED`, `FAILED_ACTION`, `EXCLUDED`, `RE_REPLY_EMAIL`, `RE_REPLY_LINKEDIN`. Only the real time LinkedIn path retries (once, network errors).

**Delivery.** One `POST` per event and per registered URL, header `Content-Type: application/json`, JSON body, no signature or secret header, default User-Agent of the HTTP library. No timeout is set. Your response (status and body) is ignored: an HTTP error is never retried. Network errors are retried only for some events (see each list). No event ID, no ordering guarantee, no replay; a URL registered twice receives everything twice. Absent fields are omitted, never null.

## Payload

| Field | Type | Required | Description |
|---|---|---|---|
| `event` | enum: `EMAIL_SENT`, `OPENED`, `CLICKED`, `MAIL_REPLIED`, `BOUNCED`, `UNSUBSCRIBED`, `VISITED`, `INVITED`, `ACCEPTED`, `MESSAGE_SENT`, `INMAIL_SENT`, `LIKED`, `LINKEDIN_REPLIED`, `WHATSAPP_MESSAGE_SENT`, `WHATSAPP_REPLIED`, `CAMPAIGN_ENDING` | yes | Events delivered for advanced (multichannel) campaigns (`type: advanced`). The email sent event is `EMAIL_SENT` (not `SENT`, not `MAIL_SENT`). `CAMPAIGN_ENDING` is delivered with a different body (see the campaignEnding webhook). |
| `campaign` | string | no | Campaign name. Missing on BOUNCED (bug). |
| `campaignId` | string | no | Only on MAIL_REPLIED and on LinkedIn replies or acceptances detected in real time. |
| `senderName` | string | no | MAIL_REPLIED only. |
| `sender` | string | no | MAIL_REPLIED only: address of the Emelia mailbox that received the reply. |
| `contact` | object | yes | Contact of an advanced campaign: legacy custom fields (`custom`) first, then the standard fields. The set depends on the emitter: most events carry `id`, `firstName`, `lastName`, `email`, `company`; OPENED, CLICKED and UNSUBSCRIBED carry `linkedinUrlProfile` instead of `id`; replies and acceptances detected in real time add `linkedinUrlProfile` and `linkedinId`. No phone number. `company` comes only from a custom field whose name contains `company`, not from the lead company name. |
| `contact.id` | string | no | Absent on OPENED, CLICKED and UNSUBSCRIBED. |
| `contact.firstName` | string | no |  |
| `contact.lastName` | string | no |  |
| `contact.email` | string | no |  |
| `contact.linkedinUrlProfile` | string | no | Only on OPENED, CLICKED, UNSUBSCRIBED and real time LinkedIn replies or acceptances. |
| `contact.linkedinId` | string | no | Only on real time LinkedIn replies or acceptances. |
| `contact.company` | string | no |  |
| `date` | string (date-time) | yes | ISO 8601 UTC. Processing time for most events; message time for LinkedIn and WhatsApp replies; 30 to 60 seconds after the fact for OPENED, CLICKED and UNSUBSCRIBED. |
| `step` | integer | yes | Indicative only. Actions: position of the step in its branch (0 for the first step after the start). OPENED, CLICKED, UNSUBSCRIBED: same but counting the start node (EMAIL_SENT 0 then OPENED 1 for the same email). MAIL_REPLIED: index among the email steps. BOUNCED, WHATSAPP_REPLIED, LINKEDIN_REPLIED and most ACCEPTED: 0. |
| `reply` | string | no | MAIL_REPLIED, LINKEDIN_REPLIED, WHATSAPP_REPLIED. |
| `sentiment` | object | no | AI classification of a reply. Present only when reply classification is enabled on the account and AI credits remain. Classified by Jev, with Gemini as fallback; only the Gemini fallback can add `additionalData`. |
| `sentiment.classification` | enum: `INTERESTED`, `NOT_INTERESTED`, `NEUTRAL`, `OUT_OF_OFFICE`, `HOSTILE`, `DELEGATION`, `INCOMPREHENSION`, `QUESTION_ASK` | no |  |
| `sentiment.score` | number | no | Confidence of the classification. Range: 0 to 1. |
| `sentiment.additionalData` | object | no | Gemini fallback only: `delegationEmail` for DELEGATION, `returnDate` (DD/MM/YYYY) for OUT_OF_OFFICE. |
| `sentiment.additionalData.delegationEmail` | string | no |  |
| `sentiment.additionalData.returnDate` | string | no |  |
| `content` | string | no | MESSAGE_SENT only: text of the LinkedIn message sent. |
| `messageId` | string | no | MAIL_REPLIED only. |
| `link` | string | no | CLICKED only. |

**EMAIL_SENT**

```json
{
  "event": "EMAIL_SENT",
  "campaign": "Acme Q4 multichannel",
  "contact": {
    "companyName": "Acme",
    "id": "6703d2e5f6a7b8c9d0e1f2a3",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@acme.com",
    "company": "Acme"
  },
  "date": "2026-10-12T08:15:02.123Z",
  "step": 0
}
```

**OPENED (no contact id, no sender)**

```json
{
  "event": "OPENED",
  "campaign": "Acme Q4 multichannel",
  "contact": {
    "companyName": "Acme",
    "firstName": "John",
    "lastName": "Doe",
    "linkedinUrlProfile": "https://www.linkedin.com/in/john-doe-acme",
    "email": "john.doe@acme.com",
    "company": "Acme"
  },
  "date": "2026-10-12T09:01:45.000Z",
  "step": 1
}
```

**MAIL_REPLIED**

```json
{
  "event": "MAIL_REPLIED",
  "campaign": "Acme Q4 multichannel",
  "campaignId": "6651f0c2a1b2c3d4e5f60718",
  "senderName": "Jane Smith",
  "sender": "jane@acme-mail.com",
  "contact": {
    "companyName": "Acme",
    "id": "6703d2e5f6a7b8c9d0e1f2a3",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@acme.com",
    "company": "Acme"
  },
  "date": "2026-10-13T10:20:00.000Z",
  "step": 0,
  "reply": "Hi Jane, sounds interesting. Can we talk on Tuesday?",
  "sentiment": {
    "classification": "INTERESTED",
    "score": 0.92
  },
  "messageId": "<CAF7x2y3z@mail.acme.com>"
}
```

**INVITED**

```json
{
  "event": "INVITED",
  "campaign": "Acme Q4 multichannel",
  "contact": {
    "companyName": "Acme",
    "id": "6703d2e5f6a7b8c9d0e1f2a3",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@acme.com",
    "company": "Acme"
  },
  "date": "2026-10-12T08:40:00.000Z",
  "step": 1
}
```

**MESSAGE_SENT (with content)**

```json
{
  "event": "MESSAGE_SENT",
  "campaign": "Acme Q4 multichannel",
  "contact": {
    "companyName": "Acme",
    "id": "6703d2e5f6a7b8c9d0e1f2a3",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@acme.com",
    "company": "Acme"
  },
  "content": "Hi John, thanks for connecting. Quick question about Acme...",
  "date": "2026-10-14T08:30:00.000Z",
  "step": 3
}
```

**LINKEDIN_REPLIED detected in real time**

```json
{
  "event": "LINKEDIN_REPLIED",
  "campaign": "Acme Q4 multichannel",
  "campaignId": "6651f0c2a1b2c3d4e5f60718",
  "contact": {
    "companyName": "Acme",
    "id": "6703d2e5f6a7b8c9d0e1f2a3",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@acme.com",
    "company": "Acme",
    "linkedinUrlProfile": "https://www.linkedin.com/in/john-doe-acme",
    "linkedinId": "ACoAAB1x2y3zAcmeExample"
  },
  "date": "2026-10-15T07:45:12.000Z",
  "step": 0,
  "reply": "Hi, happy to chat next week.",
  "sentiment": {
    "classification": "INTERESTED",
    "score": 0.92
  }
}
```

**WHATSAPP_REPLIED**

```json
{
  "event": "WHATSAPP_REPLIED",
  "campaign": "Acme Q4 multichannel",
  "contact": {
    "companyName": "Acme",
    "id": "6703d2e5f6a7b8c9d0e1f2a3",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@acme.com",
    "company": "Acme"
  },
  "date": "2026-10-16T12:00:00.000Z",
  "step": 0,
  "reply": "Sure, call me tomorrow."
}
```

**BOUNCED (no campaign name)**

```json
{
  "event": "BOUNCED",
  "contact": {
    "companyName": "Acme",
    "id": "6703d2e5f6a7b8c9d0e1f2a3",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@acme.com",
    "company": "Acme"
  },
  "date": "2026-10-12T08:16:30.000Z",
  "step": 0
}
```
