Skip to main content
Nuntly emits webhook events for receiving activity so your application can react in real time. You subscribe to these events through the same webhook configuration used for sending events.

Available events

EventDescription
message.receivedA new email was received and processed.
message.security.flaggedA received message failed one or more security checks (SPF, DKIM, spam, or virus).
message.agent.triggeredA received message was routed to an AI agent inbox.
message.sentA message was sent from an inbox.

Event payloads

All receiving events follow the same envelope structure. The type field identifies the event, and the data field contains the event-specific payload.

message.received

Emitted when a new email is received and processed.
{
  "type": "message.received",
  "data": {
    "messageId": "imsg_01kabn43yqyxn2bx4ve84mczd3",
    "threadId": "thr_01kabn43yqyxn2bx4ve84mczd3",
    "inboxId": "ibx_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "fromAddress": "sender@example.com",
    "fromName": "Jane Doe",
    "toAddresses": [
      { "address": "support@yourdomain.com" }
    ],
    "subject": "Question about my account",
    "receivedAt": "2025-01-15T10:30:00.000Z",
    "attachmentCount": 0,
    "spamVerdict": "PASS",
    "virusVerdict": "PASS"
  }
}

message.security.flagged

Emitted when a received message fails one or more security checks: SPF, DKIM, spam verdict, or virus scan. The message is still stored but flagged.
{
  "type": "message.security.flagged",
  "data": {
    "messageId": "imsg_01kabn43yqyxn2bx4ve84mczd3",
    "threadId": "thr_01kabn43yqyxn2bx4ve84mczd3",
    "inboxId": "ibx_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "fromAddress": "suspicious@example.com",
    "subject": "Suspicious message",
    "receivedAt": "2025-01-15T10:30:00.000Z",
    "spamVerdict": "FAIL",
    "spfVerdict": "FAIL",
    "dkimVerdict": "FAIL",
    "virusVerdict": "PASS"
  }
}

message.agent.triggered

Emitted when a message arrives at an inbox that has an AI agent assigned. This event is sent in addition to the message.received event.
{
  "type": "message.agent.triggered",
  "data": {
    "messageId": "imsg_01kabn43yqyxn2bx4ve84mczd3",
    "threadId": "thr_01kabn43yqyxn2bx4ve84mczd3",
    "inboxId": "ibx_01kabn43yqyxn2bx4ve84mczd3",
    "agentId": "my-support-agent",
    "domainName": "yourdomain.com",
    "fromAddress": "customer@example.com",
    "subject": "Help with my order",
    "receivedAt": "2025-01-15T10:30:00.000Z"
  }
}

message.sent

Emitted when a message is sent from an inbox (via send, reply, or forward).
{
  "type": "message.sent",
  "data": {
    "messageId": "imsg_01kabn43yqyxn2bx4ve84mczd3",
    "threadId": "thr_01kabn43yqyxn2bx4ve84mczd3",
    "inboxId": "ibx_01kabn43yqyxn2bx4ve84mczd3",
    "domainName": "yourdomain.com",
    "fromAddress": "support@yourdomain.com",
    "toAddresses": [
      { "address": "customer@example.com", "name": "Jane Doe" }
    ],
    "subject": "Re: Help with my order",
    "sentAt": "2025-01-15T10:35:00.000Z"
  }
}

Subscribe to receiving events

Add receiving events to your webhook configuration the same way you add sending events. You can subscribe through the dashboard or the SDK.
import { Nuntly } from '@nuntly/sdk';

const nuntly = new Nuntly({
  apiKey: process.env.NUNTLY_API_KEY,
});

const webhook = await nuntly.webhooks.create({
  name: 'Receiving listener',
  endpointUrl: 'https://yourapp.com/api/webhooks/receiving',
  status: 'enabled',
  events: [
    'message.received',
    'message.security.flagged',
    'message.agent.triggered',
    'message.sent',
  ],
});

console.log('Webhook ID:', webhook.id);
console.log('Signing secret:', webhook.signingSecret);
The signing secret is displayed only once. Store it securely. You need it to verify incoming webhook requests.

Handle receiving events

Use the same signature verification flow as sending events. See handle webhook events for the full implementation pattern. Here is a condensed example handling receiving events:
// Inside your webhook handler (after signature verification)
const event = JSON.parse(payload);

switch (event.type) {
  case 'message.received':
    console.log(`New message from ${event.data.fromAddress}: ${event.data.subject}`);
    break;
  case 'message.security.flagged':
    console.log(`Flagged message from ${event.data.fromAddress} (spam: ${event.data.spamVerdict})`);
    break;
  case 'message.agent.triggered':
    console.log(`Agent ${event.data.agentId} triggered for message ${event.data.messageId}`);
    // Trigger your AI agent processing
    break;
  case 'message.sent':
    console.log(`Message sent to ${event.data.toAddresses.map(a => a.address).join(', ')}`);
    break;
}

Learn more