# Reading your send history (/guides/email-logs)

Webhooks tell you when something happens to a message. This lets you ask afterwards, which is the
half you need at three in the morning when a customer says nothing arrived — by then the webhook
has already been and gone.

## Listing

```bash
curl "https://api.bitelio.com/v1/emails?status=bounced&limit=50" \
  -H "Authorization: Bearer $BITELIO_API_KEY"
```

```json
{
  "data": [
    {
      "id": "…",
      "to": "customer@example.com",
      "subject": "Your receipt",
      "status": "BOUNCED",
      "error": "550 5.1.1 user unknown",
      "createdAt": "2026-09-01T09:14:22.108Z",
      "bouncedAt": "2026-09-01T09:14:25.902Z"
    }
  ],
  "nextCursor": "…"
}
```

Page with `cursor`, passing back the `nextCursor` you were given, verbatim — it is opaque, and it
is `null` on the last page. There is no offset parameter: nothing prunes this table, so an offset
deep into a large project's history is a query that gets slower every month.

Filters: `status`, `mode`, `to`, `since`, `until`, `limit` (up to 100).

## Reading one, body included

```bash
curl "https://api.bitelio.com/v1/emails/$EMAIL_ID" \
  -H "Authorization: Bearer $BITELIO_API_KEY"
```

This is the one that answers the real question. The list tells you *whether* something was sent;
this returns the exact HTML that went out, after variables were substituted, blocks were resolved
and your brand was applied. Most "the email looks wrong" reports are answered by reading it.

The body is not in the list response — it is hundreds of kilobytes a page.

## Test sends are hidden by default

`mode` is `live` unless you say otherwise. Pass `mode=test` for [test-key](/guides/api-keys) sends
only, or `mode=all` for both. A test send is interesting for ten minutes and noise for ever after,
which is why it is not the default.

## What you cannot do

**There is no search by subject or body.** Over a table with millions of rows that is either a scan
or a full-text index nobody maintains, and we would rather say so than offer it and be slow. Filter
by recipient, status and date instead.

**`to` only matches your own contacts.** The address is resolved to a contact in your project
first, so an address you have never written to returns an empty page rather than an error.

## Permission

The endpoints need the **`emails:view`** scope. It is separate from `analytics:view` because that
one is aggregates, and reading a body is reading a recipient's personal data — only Owners and
Admins hold it by default.

<Cards>
  <Card title="Webhooks" href="/webhooks">
    The push half: get told when a message is delivered, opened or bounces
  </Card>

  <Card title="API keys" href="/guides/api-keys">
    Scoping a key, and what a test key does
  </Card>
</Cards>
