> ## Documentation Index
> Fetch the complete documentation index at: https://docs.enginy.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Events (automations)

> Let ChatGPT and other MCP clients react to replies, accepted connection requests and other campaign activity through MCP Events.

Enginy MCP implements **MCP Events** (protocol revision `2026-07-28`). An MCP client subscribes to an event once,
and Enginy then pushes every matching occurrence to the client — so an agent can triage a reply or follow up on an
accepted connection request the moment it happens, instead of polling the inbox.

In ChatGPT this powers automations such as *"When a prospect replies, summarize the thread and draft an answer"*:
ChatGPT discovers the events below, subscribes on your behalf and runs your instructions for each event.

## Available events

| Event | Fires when |
| - | - |
| `message.replied` | A contact replies to a campaign conversation (LinkedIn, InMail, email, WhatsApp). |
| `connection_request.sent` | A campaign sends a LinkedIn connection request. |
| `connection_request.accepted` | A contact accepts a connection request sent by a campaign. |
| `post.liked` | A campaign step likes one of the contact's LinkedIn posts. |
| `profile.visited` | A campaign step visits the contact's LinkedIn profile. |

Every event accepts one optional filter, `campaignId`, to receive events from a single campaign only.

Each payload carries the same `contact` and `campaign` objects as [workspace webhooks](/api-reference/webhooks-guide),
plus a `conversationId` (and, for `message.replied`, `messageId` and `messageType`) so the agent can open the thread
or reply with the inbox tools.

When a contact is in several campaigns on the same LinkedIn or InMail thread (for example an archived campaign and
its rerun), a reply is sent once, naming the conversation you can open and, with a `campaignId` filter, the
conversation in that campaign. If that is not the conversation the reply was first recorded on, `messageId` is `null`;
read the conversation to get the message.

```json theme={null}
{
  "eventId": "evt_6a0c…",
  "name": "message.replied",
  "timestamp": "2026-09-30T10:05:00.000Z",
  "cursor": null,
  "data": {
    "conversationId": 81234,
    "messageId": 99120,
    "messageType": "LINKEDIN",
    "content": "Tuesday works — send me an invite.",
    "subject": null,
    "sentAt": "2026-09-30T10:04:58.000Z",
    "contact": { "id": 4412, "firstName": "Ada", "lastName": "Lovelace", "jobTitle": "CTO", "…": "…" },
    "campaign": { "id": 310, "name": "Q4 CTO outreach", "status": "ACTIVE" }
  }
}
```

## Who can use events

* **OAuth connections only.** Events belong to the person who connected the MCP client. Sessions authenticated
  with a [static API key](/mcp/api-key-auth), and sessions with an active readonly impersonation, do not
  advertise the `events` capability.
* **Scope:** the connection needs [`MESSAGING_READ`](/mcp/scopes), and the workspace MCP policy must allow it.
* **Row-level access is enforced per event.** A user restricted to specific identities only receives events for
  conversations they can see in the app, and a `campaignId` filter must be a campaign they can see.
* Access is re-checked before every delivery attempt, including events already queued or being retried:
  revoking the MCP connection, deactivating the user, losing access to the conversation, or pausing the workspace
  MCP policy stops delivery immediately. A subscription made while switched to another account through a
  multi-user account also stops if the connecting user or their own workspace loses MCP access, or their
  permission to switch accounts is revoked.

## Delivery details

For client developers implementing the receiving side:

* **Methods:** `events/list`, `events/subscribe` (webhook delivery only) and `events/unsubscribe`. The server
  declares `capabilities.events` on `server/discover`.
* **Verification:** before a subscription activates, Enginy POSTs `{"type":"verification","challenge":"…"}` to the
  callback URL; the endpoint must answer `2xx` with `{"challenge":"…"}`. A callback verified with the same secret is
  not re-challenged for 24 hours; a new or rotated secret is always challenged again.
* **Signing:** every request follows [Standard Webhooks](https://www.standardwebhooks.com) —
  `webhook-id` (the `eventId`), `webhook-timestamp`, `webhook-signature` (HMAC-SHA256 with the `whsec_` secret
  from `events/subscribe`) and `X-MCP-Subscription-Id`. After a secret rotation, requests are signed with both the
  new and the previous secret for 15 minutes.
* **Retries:** failed deliveries are retried with exponential backoff for about two hours with the same
  `eventId`. Only `410 Gone` and `413` are treated as final: they are not retried, and `410` deactivates the
  subscription until the client subscribes again.
* **Limits:** callback URLs must be public `https` URLs (no redirects are followed); up to 50 active subscriptions
  and 20 callback verifications per hour per user; subscriptions expire after the granted `refreshBefore` (default 7 days, at most 30) unless refreshed;
  event bodies stay under 256 KiB (long message bodies are truncated and flagged with `contentTruncated`).
* **No replay:** events are not replayable; `cursor` is always `null`.

<Note>
  MCP Events and [workspace webhooks](/api-reference/webhooks-guide) are fed by the same activity. Webhooks
  are configured by a workspace admin for a system integration; events are subscribed per user by an MCP
  client.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.