# Retrieve a send

Read the outcome of an already-admitted send with GET /v1/email/:messageId.

**GET https://api.e-comms.dev/v1/email/:messageId**

The outcome of a send already admitted. Costs no quota: an organization over its limit can still read what it already sent.

Status: `200`

### Path parameters

- `messageId` `string` — Required. The id POST /v1/email returned in its own results[].messageId.

### Query parameters

None.

### Headers

- `Authorization` `string` — Required. `Bearer ek_live_<key>`.

### Request attributes

None.

### Response attributes

- `id` `string` — Required. The same id as the path parameter.
- `address` `string` — Required. This addressee's own address.
- `status` `string` — Required. claimed, sent, suppressed, failed or unknown — see Notes.
- `deliveryStatus` `string | null` — Required. null until the first webhook delivery. After that, deferred, delivered, rejected, bounced or complained — see Notes.
- `failureReason` `string | null` — Required. null unless status is failed, where it carries the provider's own reason.
- `createdAt` `string` — Required. When the send was admitted. Never null.
- `sentAt` `string | null` — Required. null until the send attempt itself succeeded or failed.
- `deliveredAt` `string | null` — Required. null until deliveryStatus reaches delivered.

## Notes

- **`status` is about the send attempt, not the delivery.** `claimed` is the only value before
  the provider is ever called; `sent` and `failed` describe whether that call succeeded;
  `unknown` is what an interruption between the claim and the provider's answer leaves behind,
  after a bounded retry already had its chance — never a failed delivery on its own.
- **`deliveryStatus` is a ladder that never moves backward**, the same one the
  [webhooks reference](/en/docs/reference/webhooks) documents: `deferred`, `delivered`,
  `rejected`, `bounced` and `complained`, in the order a late complaint can still arrive after
  a delivery already on record.
- **Costs no quota:** an organization over its limit can still read what it already sent.
- **Reading needs its own permission.** This route requires `messages:read`; sending requires `messages:send`. A key issued only `messages:send` can send but gets a `403` when retrieving a send, so issue the key with both permissions if it will do both.

## Errors

| Status | Code | Cause |
| --- | --- | --- |
| `403` | `forbidden` | The key was not issued `messages:read`. A key issued only `messages:send` gets this 403 when reading. |
| `404` | `not_found` | The message does not exist, or exists for another organization — the response never reveals which. |

## Request

```bash
curl https://api.e-comms.dev/v1/email/01a0ba31-3fe4-7cc4-a1c6-64bdaaa5d99c \
  -H "Authorization: Bearer ek_live_<your-key>"
```

```js
const response = await fetch(
  "https://api.e-comms.dev/v1/email/01a0ba31-3fe4-7cc4-a1c6-64bdaaa5d99c",
  { headers: { Authorization: "Bearer ek_live_<your-key>" } },
)

const body = await response.json()
```

```python
import requests

response = requests.get(
    "https://api.e-comms.dev/v1/email/01a0ba31-3fe4-7cc4-a1c6-64bdaaa5d99c",
    headers={"Authorization": "Bearer ek_live_<your-key>"},
)

body = response.json()
```

## Response `200` — Found

```json
{
  "id": "01a0ba31-3fe4-7cc4-a1c6-64bdaaa5d99c",
  "address": "ana@example.com",
  "status": "sent",
  "deliveryStatus": "delivered",
  "failureReason": null,
  "createdAt": "2026-09-19T12:00:00Z",
  "sentAt": "2026-09-19T12:00:01Z",
  "deliveredAt": "2026-09-19T12:00:04Z"
}
```

## Response `404` — Not found

```json
{
  "code": "not_found",
  "message": "The message does not exist, or exists for another organization.",
  "details": null,
  "requestId": "01a0ba31-3fe4-7cc4-a1c6-64bdaaa5d99c"
}
```
