---
title: "List and retrieve"
description: "Find messages, and see what became of one."
url: "https://openemail.uk/docs/api/emails/list"
area: "API"
category: "Emails"
---

# List and retrieve

Find messages, and see what became of one.

**Also documents:** `GET /emails`, `GET /emails/{id}`, `GET /emails/{id}/events`

## Listing

`GET /emails`, newest first. Filter with `status` (comma-separated) and `from`. Pagination is keyset, not offset: pass the `nextCursor` you were given. Offset paging silently skips rows when new messages arrive while you page.

**GET /emails?status=failed&limit=10**

```
{ "object": "list", "data": [ … ], "hasMore": true, "nextCursor": "msg_01j8…" }
```

A row that was tracked also carries a compact `tracking` object: `opens`, `clicks`, `opened`, `clicked`, `openCount`, `clickCount`, `firstOpenAt`. A row that was not carries no `tracking` key at all: `openCount: 0` on a message that never held a pixel reads as "nobody opened it", which is a claim we are in no position to make.

## Retrieving one

`GET /emails/{id}` returns the message with per-recipient delivery state, and the FULL tracking report rather than the list summary, since one retrieve can afford the per-recipient breakdown and the links. An id that does not exist is a `404`, never a fabricated success.

| Recipient status | Means |
| --- | --- |
| pending | Not yet transmitted. |
| delivered | Handed to the transport for this address. |
| failed | The transport refused it. |
| uncertain | A transport failed part-way and cannot say which recipients it reached. Shown as itself rather than guessed either way. |

## Events

`GET /emails/{id}/events` returns the trail, oldest first: `email.accepted`, `email.queued`, `email.scheduled`, `email.sent`, `email.failed`, `email.cancelled`, `email.rescheduled`, and, on a tracked message, `email.opened`, `email.clicked` and `email.downloaded` as they happen. To be told rather than to poll for them, register a webhook.
