# Track events on the timeline

> Where events come from, how they move an email's status, and the event feed that lets you pull them with a cursor.

Source: https://docs.minket.com/events/
Updated: 2026-10-29

Everything that happens to an email, a contact, a domain, a broadcast or an automation is one event on the project's timeline. [Webhooks](https://docs.minket.com/webhooks/) deliver the same event object the [feed](https://docs.minket.com/events/#the-feed) returns, `{ "type", "created_at", "data" }`, with the id and the mode added in the feed.

## Where events come from

| Source | Events |
|---|---|
| Amazon SES | `email.sent`, `email.delivered`, `email.delivery_delayed`, `email.bounced`, `email.complained`, `email.failed` (rejected or not rendered), `email.suppressed` (an address on SES's own suppression list, recorded as a suppression too) |
| Sending | `email.suppressed` (a recipient on the project's list), `email.failed`, `email.scheduled`, `email.canceled` |
| Tracking links | `email.opened`, `email.clicked` ([tracking](https://docs.minket.com/delivery/#open-and-click-tracking)) |
| Test keys | the sequence each test recipient plays ([Test mode](https://docs.minket.com/sending/#test-mode)) |
| Inbound, audience, broadcasts, automations | `email.received`, `contact.*`, `domain.*`, `broadcast.*`, `automation.*` |

Each source event is recorded once: SES redelivers events now and then, and a redelivered one changes nothing. Events carry the mode of the email (live or test) and its environment; project-level events have no environment. Bounces and complaints also count towards the project's rates ([When sending pauses](https://docs.minket.com/deliverability/#when-sending-pauses)), and the daily counts behind the overview (sent, delivered, bounced, complained, failed, opened, clicked, suppressed) are kept per project, environment, stream and mode. An SES event counts only for mail the platform sent for that project, through the project's own configuration set; anything else is dropped, so mail that sets the platform's tags itself cannot write to another project's timeline.

## Email status

An event moves the email's `status` to the one in the [event table](https://docs.minket.com/webhooks/#event-types), unless the email is already further along. The order is `queued`, `scheduled`, `sent`, `delivery_delayed`, `delivered`, `opened`, `clicked`, then `suppressed`, `canceled` and `failed`, then `bounced`, then `complained`. A later event with a lower rank never demotes the status, so a `delivered` that arrives after an open leaves the email `opened`.

## The feed

Webhooks push; the feed lets you pull. `GET /v1/events` returns the key's events, newest first, cursor-paginated, filtered by `types` (comma-separated), `email_id`, `contact_id` and `since`:

```sh tab=curl
curl "https://api.minket.com/v1/events?types=email.bounced,email.complained&since=2026-10-23T00:00:00Z&limit=100" \
  -H "Authorization: Bearer $MINKET_API_KEY"
```

```ts tab
const page = await minket.events.list({ types: "email.bounced,email.complained", limit: 100 });
for (const event of page.data) {
  // event.id, event.type, event.data
}
```

```json
{
  "object": "list",
  "data": [
    {
      "id": "019a2b3c-4d5e-7f60-8a9b-0c1d2e3f4a90",
      "mode": "live",
      "type": "email.bounced",
      "created_at": "2026-10-24T18:00:04.000Z",
      "data": {
        "email_id": "019a2b3c-4d5e-7f60-8a9b-0c1d2e3f4a5c",
        "created_at": "2026-10-24T18:00:00.000Z",
        "from": "Acme <billing@mail.acme.example>",
        "to": ["jane@example.com"],
        "subject": "Your receipt for order 10452",
        "bounce": { "type": "Permanent", "subType": "General", "message": "smtp; 550 5.1.1 user unknown" }
      }
    }
  ],
  "has_more": false
}
```

- A key sees its own mode only (a test key sees test events), its environment's events and the project-level ones. Full-access keys only.
- Events from the last 5 seconds are left out. Ids are time-ordered, and an event recorded a moment ago can commit after a later one; the lag means a reader never steps over it.
- To read older events, pass `after` with the last id you have. To follow new events, keep the newest id you have seen and ask for `before=<that id>`: the answer holds the events after it, newest first, with `has_more` when there are more than `limit`.
- `GET /v1/events/{id}` returns one event, without the lag, so an event id from a webhook can be read at once.

Use the feed to reconcile after your receiver was down, to backfill a new system, or instead of webhooks altogether. Events are kept for 13 months; test events from `POST /v1/webhooks/{id}/test` are not part of it.
