List inbound log events

One timeline of what happened to your inbound mail, newest first: accepted, routed, stored, forwarded, forward failed and rejected — filterable by type, domain and search.

The inbound log answers "what happened to that message?" without joining several endpoints. Each event carries the fields of its kind: accepted (the MX took the message: from, size_bytes, auth verdicts, attachments), routed (the route that matched — route_id null means no route matched and the message was kept by default), stored (kept for the poll API, with expires_at), forwarded / forward_failed (one forward attempt: url, status_code, duration_ms, attempt, terminal, manual, next_retry_at) and rejected (the MX refused a recipient or message: smtp_code, enhanced_code and reason). Rejections keep no sender details.

GET /v3/inbound/logs

Query parameters

ParameterTypeRequiredDescription
rangestringOptionalWindow back from now: 24h, 7d (default) or 30d.
typestringOptionalOne event type or a comma-separated list: accepted, routed, stored, forwarded, forward_failed, rejected. counts ignore it.
domainstringOptionalOnly events of this recipient domain (case-insensitive).
qstringOptionalSearch: a recipient substring, an inbound message ID, an RFC Message-ID or a forward URL substring.
cursorstringOptionalThe next_cursor of the previous page. A cursor only continues the walk it came from.
limitintegerOptionalPage size, 1–200. Default 100.

Pages walk backwards in time: has_more says whether older events follow and next_cursor fetches them. counts gives the number of events per type over the whole window (domain and q applied, type and cursor ignored), so one page is enough for a summary strip. reason on rejections is one of inbound_off, domain_unverified, plan_not_allowed, quota_exceeded, too_large, content_rejected. A send_only key cannot read inbound mail. Limit: 60 calls per minute per key.

Responses

StatusDescription
200OK. { items, has_more, next_cursor, counts }, newest first.
400validation_error — invalid filters; invalid_cursor — the cursor is not a next_cursor value.
401Missing or invalid API key.
403insufficient_scope — a send_only key cannot read inbound mail.
429Rate limit exceeded (60 calls per minute).

Code examples

cURL
# Forward attempts of the last 24 hours, failures included
curl -G https://api.wemail.io/v3/inbound/logs \
  -H "Authorization: Bearer afn_live_…" \
  --data-urlencode "range=24h" \
  --data-urlencode "type=forwarded,forward_failed" \
  --data-urlencode "limit=50"
Node.js
const url = new URL("https://api.wemail.io/v3/inbound/logs");
url.search = new URLSearchParams({ range: "24h", type: "forwarded,forward_failed", limit: "50" }).toString();
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.WEMAIL_API_KEY}` } });
const { items, counts, has_more, next_cursor } = await res.json();
for (const e of items) console.log(e.at, e.type, e.recipient, e.url, e.status_code, e.attempt, e.terminal);
console.log(counts.forward_failed, "failed attempts in the window", has_more ? next_cursor : "");
Python
import os, requests

r = requests.get(
    "https://api.wemail.io/v3/inbound/logs",
    headers={"Authorization": f"Bearer {os.environ['WEMAIL_API_KEY']}"},
    params={"range": "24h", "type": "forwarded,forward_failed", "limit": 50},
)
page = r.json()
for e in page["items"]:
    print(e["at"], e["type"], e["recipient"], e["url"], e["status_code"], e["attempt"], e["terminal"])
print(page["counts"]["forward_failed"], "failed attempts in the window")
Go
client, _ := wemail.NewClient(os.Getenv("WEMAIL_API_KEY"))
ctx := context.WithValue(context.Background(), wemail.ContextAccessToken, os.Getenv("WEMAIL_API_KEY"))
page, _, err := client.API.InboundAPI.ListInboundLogs(ctx).Limit(50).Execute()
for _, e := range page.Items { fmt.Println(e.At, e.Type, e.Recipient) }
ResponseExample response
{
  "items": [
    {
      "id": "fwd_9c2d4e6f1a3b4c5d8e7f0a1b2c3d4e5f",
      "type": "forward_failed",
      "at": "2026-11-04T08:15:02.000Z",
      "domain": "inbound.example.com",
      "recipient": "orders@inbound.example.com",
      "message_id": "6f1c2a1e-7d3b-4b7e-9f0e-2a4c8d9b1e55",
      "from": null,
      "size_bytes": null,
      "auth": null,
      "attachments": null,
      "route_id": "0b7e4c2d-9a1f-4e6b-8c3d-5f2a1b9e7d40",
      "route_name": "Orders → app",
      "route_priority": 10,
      "expression": "match_recipient("orders@inbound.example.com")",
      "expires_at": null,
      "url": "https://app.example.com/inbound",
      "status_code": 503,
      "duration_ms": 412,
      "attempt": 2,
      "terminal": false,
      "manual": false,
      "next_retry_at": "2026-11-04T08:25:02.000Z",
      "smtp_code": null,
      "enhanced_code": null,
      "reason": null
    },
    {
      "id": "acc_6f1c2a1e7d3b4b7e9f0e2a4c8d9b1e55",
      "type": "accepted",
      "at": "2026-11-04T08:14:58.000Z",
      "domain": "inbound.example.com",
      "recipient": "orders@inbound.example.com",
      "message_id": "6f1c2a1e-7d3b-4b7e-9f0e-2a4c8d9b1e55",
      "from": "customer@example.org",
      "size_bytes": 48213,
      "auth": { "spf": "pass", "dkim": "pass", "dmarc": "pass" },
      "attachments": 1,
      "route_id": null,
      "route_name": null,
      "route_priority": null,
      "expression": null,
      "expires_at": null,
      "url": null,
      "status_code": null,
      "duration_ms": null,
      "attempt": null,
      "terminal": null,
      "manual": null,
      "next_retry_at": null,
      "smtp_code": null,
      "enhanced_code": null,
      "reason": null
    }
  ],
  "has_more": true,
  "next_cursor": "eyJhdCI6IjIwMjYtMTEtMDRUMDg6MTQ6NTguMDAwWiIsImlkIjoiYWNjXzZmMWMifQ",
  "counts": { "accepted": 191, "routed": 188, "stored": 176, "forwarded": 185, "forward_failed": 6, "rejected": 3 }
}