Events & logs
Every state change a message goes through is recorded as an event.
Every state change a message goes through is recorded as an event. Query history through the API or stream events in realtime via webhooks.
How far back the log reaches
Event history follows your plan’s data-retention window: 30 days on Free, 12 months on paid plans (the free workspace inside a paid organisation inherits the organisation’s 12 months). A since older than your window simply returns no earlier events — nothing errors. Suppression and unsubscribe records are kept indefinitely regardless of plan, and webhooks deliver every event in realtime if you want your own permanent archive. The same numbers are listed on the Limits page.
Need the log as a file instead of pages? Export events generates a full CSV of any window within retention — warehouse syncs, audits and data portability without a pagination loop.
GET /v3/events
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
event | string | Optional | Filter by type: queued, sent, delivered, opened, clicked, bounced, complained, unsubscribed, delayed, rejected, failed. |
recipient | string | Optional | Filter by recipient address (exact match). |
tag | string | Optional | Only count events carrying this tag (event or parent message). |
message_id | string | Optional | All events for a single message. |
metadata[key] | string | Optional | Metadata search: metadata[order_id]=1234 matches events whose message carries that metadata key/value (attached at send). Up to 3 filters per request; keys ≤64 chars (letters, digits, dot, dash, underscore), values ≤200 chars, exact match. Combines with all other filters. |
since | ISO-8601 | Optional | Only events at or after this timestamp. |
until | ISO-8601 | Optional | Only events at or before this timestamp. |
limit | integer | Optional | Page size, 1–300. Default 25. |
cursor | string | Optional | Pass the next_cursor from a previous response to fetch the next page. |
Cursor pagination
Results are ordered newest-first and paginated with an opaque keyset cursor rather than page numbers, so pages stay stable while new events stream in. Each response returns items, has_more, next_cursor (or null on the last page) and total_count (the total matching the filters, independent of the cursor). Keep requesting with cursor=next_cursor until has_more is false.
Retention
Events follow your plan’s data retention: 30 days on Free, 12 months on paid plans. The same window applies to webhook delivery history — if a webhook consumer missed events, you don’t need to re-derive them from this feed: resend the deliveries themselves (up to 90 days back) and your endpoint receives the original payloads again.
Responses
| Status | Description |
|---|---|
200 | OK. A cursor-paginated page of events with items, has_more, next_cursor and total_count. |
400 | Invalid query parameters. |
401 | Missing or invalid API key. |
Code examples
curl -G https://api.wemail.io/v3/events \
-H "Authorization: Bearer afn_live_…" \
--data-urlencode "tag=welcome" \
--data-urlencode "event=delivered" \
--data-urlencode "since=2026-05-01"const events = await wemail.events.list({
tag: "welcome",
event: "delivered",
since: "2026-05-01",
});
for (const e of events) console.log(e.recipient, e.timestamp);events = wemail.events.list(tag="welcome", event="delivered", since="2026-05-01")$events = $wemail->events->list(['tag' => 'welcome', 'event' => 'delivered']);events = wemail.events.list(tag: "welcome", event: "delivered")events, _ := client.Events.List(ctx, &wemail.EventParams{Tag: "welcome", Event: "delivered"})wemail.events().list(EventParams.builder().tag("welcome").event("delivered").build());var events = await wemail.Events.ListAsync(new EventParams { Tag = "welcome", Event = "delivered" });{
"items": [
{
"id": "evt_01HBYE7Q…",
"type": "delivered",
"message_id": "msg_01HBYE7K9Z4PMQDR3W",
"recipient": "alex@example.com",
"timestamp": "2026-05-10T09:42:21.000Z",
"tags": ["welcome", "v2"],
"metadata": null,
"created_at": "2026-05-10T09:42:21.412Z"
}
],
"has_more": true,
"next_cursor": "2026-05-10T09:42:21.000Z|evt_01HBYE7Q…",
"total_count": 1842
}