BitelioBitelio

Reading your send history

Query what you sent, and what happened to it, from code — including the rendered body

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

curl "https://api.bitelio.com/v1/emails?status=bounced&limit=50" \
  -H "Authorization: Bearer $BITELIO_API_KEY"
{
  "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

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 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.