Skip to main content
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.events.list({ limit: 10 });
console.log(result);
{
  "data": [
    {
      "id": "evt_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "type": "<type>",
      "workspace_id": "wsk_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "agent_id": "agt_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "thread_id": "thrd_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "source_message_id": "msg_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "intent": "<intent>",
      "urgency": 0,
      "injection_score": 0,
      "sender_reputation": 0,
      "entities": {},
      "injection_categories": ["<injection_categories>"],
      "classifier_model": "<classifier_model>",
      "quarantined": false,
      "test_mode": false,
      "data": {},
      "created_at": "2026-10-04T12:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": "<next_cursor>"
}

List events

GET/v1/eventsscope · read
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.events.list({ limit: 10 });
console.log(result);
{
  "data": [
    {
      "id": "evt_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "type": "<type>",
      "workspace_id": "wsk_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "agent_id": "agt_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "thread_id": "thrd_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "source_message_id": "msg_01JZX8K3M9Q4P7VN2YB6RTDC0E",
      "intent": "<intent>",
      "urgency": 0,
      "injection_score": 0,
      "sender_reputation": 0,
      "entities": {},
      "injection_categories": ["<injection_categories>"],
      "classifier_model": "<classifier_model>",
      "quarantined": false,
      "test_mode": false,
      "data": {},
      "created_at": "2026-10-04T12:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": "<next_cursor>"
}

Query Parameters

limitinteger

Page size (1–100).

Default: 25

cursorstring

Opaque cursor from a previous page's next_cursor.

event_typestring

Filter by exact event type.

agent_idstring

Filter by agent id or name.

sincestring

Only events created at or after this time: an ISO 8601 time such as 2026-10-05T07:00:00Z or 2026-10-05T16:00:00+09:00, or a date (2026-10-05, midnight UTC). A time with no offset is UTC, and its seconds and milliseconds may be left out. Any other value answers 400 invalid_param_value. The event stream's since is different: a position the stream gave, or an event id.

Response

dataobject[]

The items on this page, at most limit of them.

Show propertiesHide properties
idstring

Event id (evt_…). A webhook delivery carries it as id and in the X-Mails-Event-Id header, the same on every retry and redelivery.

typestring

Event type. The types emitted: message.sent, message.scheduled, message.delivered, message.delayed, message.bounced, message.complained, message.failed, message.received, message.received.unauthenticated, message.received.over_limit, reply.received, draft.scheduled, draft.sending, draft.sent, draft.failed, suppression.added, webhook.test, thread.created, thread.updated, thread.deleted. message.sent is raised for every message that goes out, a scheduled draft's included (which raises draft.sent too). message.scheduled is raised for every message scheduled for later (by a send, a batch item or a reply), and again when one is rescheduled, with the new scheduled_at and the previous_scheduled_at it replaced. message.delivered is raised once per recipient when the receiving side reports the delivery, and at once for a send recorded as delivered when it was sent. message.delayed reports a transient bounce (the message may still be delivered), once per recipient however often the delay is reported; a webhook endpoint gets it, like the thread events, only when it lists it by name. message.received.over_limit reports mail received while the workspace was over a limit; its data says which (over_limit), whether the text was kept (content_kept), and who sent it (from and envelope_from, as on the inbound events), and carries no subject or body: the injection scan did not read that mail. For the same reason thread.created for received mail gives its subject only when the scan read the mail and did not quarantine it, and null otherwise.

workspace_idstring

The workspace the event belongs to (wsk_…).

agent_idstring

The agent the event is about (agt_…). Absent when it has none, as on webhook.test.

thread_idstring

The thread the message behind the event belongs to (thrd_…), when it has one.

source_message_idstring

The message the event is about: the sent message (msg_…) on events about a send, the received one (rcv_…) on inbound events. Absent on events that carry no message, such as the thread events and webhook.test.

intentstring

What an inbound message wants, on message.received, reply.received and message.received.unauthenticated only. Fixed values when it was not read for intent: general_reply for a reply in a thread, unknown when the rules layer settled it, unclassified when the agent's classify_inbound is off or the classifier could not run.

urgencynumber

Urgency score 0–1 (higher = more time-sensitive).

injection_scorenumber

Prompt-injection score 0–1 (inbound events). The scan reads the subject and the first 100,000 characters of the body: the openings of its text part, of its HTML part's text and of the text that HTML hides come first, then the rest of each. Anything past 100,000 characters is not scanned.

sender_reputationnumber

Trust score for the sender of an inbound message, 0–1 (higher = more trusted), on the same events as intent. The classifier's estimate when it read the message for intent; otherwise a preset, such as 0.3 for a sender that failed authentication.

entitiesobject

Extracted entities as key→value pairs (object) — present when intent classification ran.

injection_categoriesstring[]

Prompt-injection categories flagged — single-event GET only.

classifier_modelstring

What scored the message: a model name; a value starting rules-layer when the rules layer settled the intent; injection-scan-only; or scan-unavailable when the scan could not run. On every event read and in webhook deliveries.

quarantinedboolean

Inbound events only: the firewall's verdict, true when the message's injection score crossed the quarantine threshold. injection_score is the evidence; this is the decision.

test_modeboolean

True when a test key (mk_test_…) or test mail raised the event, and on every webhook.test event. thread.updated and thread.deleted take the thread's own mode instead: true when the thread holds no live mail.

dataobject

Full typed-event payload (shape varies by type). Inbound events (message.received, reply.received, message.received.unauthenticated) carry from, the first mailbox of the email's From header, which the checks below are about (it is proven only when dmarc is pass; when no raw email reached us it is read from the From header our mail server passed on, and the envelope sender stands in only when there was none), and envelope_from, the envelope sender (SMTP MAIL FROM), where bounces go and which a sending service often sets to its own bounce address: replies go to the Reply-To or to from, never there. They carry the sender's authentication as we checked it from the email itself, never from a header in it: dkim (pass when a DKIM signature verifies, whichever domain signed it; fail; none for an unsigned email; or unknown when it could not be checked), dkim_domain (the domain of a passing DKIM signature that matches the domain of the From header, or null), dmarc (none when the From domain publishes no DMARC record; otherwise pass when a DKIM signature aligned with the From domain verifies, and unknown, never fail, when none does: SPF is not checked, and a sender that relies on SPF alone is not evidence of forgery) and spf (unknown: mail reaches us through Cloudflare, and the sending server's address is not known). message.received.unauthenticated replaces message.received or reply.received when no DKIM signature aligned with the From domain verifies and the From domain's DMARC policy is quarantine or reject: those domains promise signed mail, so this is the forged-sender case, and auth_failed is true. Every other sender gets no such event. spf_pass and dkim_pass are the same as true, false or null. Mail forwarded to an agent (forwarding mode) is judged the same way, since a forward that leaves the message as it was keeps the sender's signature (its envelope_from is the forwarding service's own address); arc is the ARC chain as we checked it (pass, fail, none or unknown), and trusted_forwarder names the mail service (google_workspace, microsoft_365, fastmail or zoho) whose ARC seal, on a chain that validates, reports that DMARC passed for the From domain when the mail reached it, or null. Such mail never gets message.received.unauthenticated, even when the forward broke the sender's signature; dkim, dkim_domain and dmarc still say only what we verified ourselves.

created_atstring

When the event was recorded (UTC); the since filter of GET /v1/events compares against it.

has_moreboolean

True when more items follow this page: pass next_cursor as cursor to get them.

next_cursorstring

Pass as cursor to fetch the next page. Absent on the last page.

Was this page helpful?