Export events
Download your event history as a single CSV file — no pagination loop.
Every send, delivery, open, click, bounce and complaint lands in the event log. GET /v3/events reads it 300 rows at a time — fine for dashboards, painful for “give me everything from August”. This endpoint is the file-sized answer: start a background job, poll until it finishes, download one CSV. Typical uses: nightly warehouse/BI sync, compliance evidence (“prove the January invoices reached all 40,000 clients”), taking your data with you, and support investigations that span more than a few pages.
How it works
Three steps: 1) POST /v3/events/export with your filters — it answers immediately with an export_id. 2) Poll GET /v3/events/export/{id} until status is completed (the job runs in the background; large exports take a while). 3) Fetch the file from GET /v3/events/export/{id}/download. Generated files are kept for 7 days.
POST /v3/events/export
Body parameters (all optional)
| Parameter | Type | Required | Description |
|---|---|---|---|
since | ISO-8601 | Optional | Window start. Default: 30 days ago. May not reach past your plan’s event retention (30 days Free / 12 months paid) — an older start is rejected with retention_exceeded, never silently truncated. |
until | ISO-8601 | Optional | Window end. Default: now. |
events | string[] | Optional | Only these event types, e.g. ["bounced","complained"]. Default: all types. |
recipient | string | Optional | Only events for this recipient address (exact match). |
tag | string | Optional | Only events carrying this tag (event or parent message). |
metadata | object | Optional | Metadata filters, e.g. {"order_id":"1234"} — matches the metadata you attached at send time. Up to 3 key/value pairs (keys up to 64 chars of letters, digits, dot, dash, underscore; values up to 200 chars; exact match), same semantics as the metadata[key] query filters on the events API. |
format | string | Optional | csv — the default and only format for now. |
CSV columns
id, type, message_id, recipient, timestamp, tags, metadata, domain, created_at — the same field names the events API uses, so downstream schemas match. tags is semicolon-joined, metadata is the JSON object in one cell, domain is the sending domain. Cell values are escaped against Excel formula injection, so the file is safe to open directly in a spreadsheet.
Limits & idempotency
| Parameter | Type | Required | Description |
|---|---|---|---|
Row cap | 1,000,000 | Optional | An export matching more rows fails with a clear error_message — split the window (e.g. one export per week) and re-submit. |
Concurrent jobs | 3 | Optional | At most 3 event exports pending/running per account; a 4th returns 409 too_many_exports. |
Rate limit | 10/min | Optional | Same as the other export endpoints. |
Duplicate submits | deduped | Optional | Submitting an identical filter set while an equivalent job is pending or running returns the existing job’s export_id instead of starting a duplicate — retries are safe. |
Responses
| Status | Description |
|---|---|
202 | { export_id, status } — poll GET /v3/events/export/{id}. An equivalent in-flight job is returned with its current status. |
400 | retention_exceeded — since reaches past your plan’s event retention — or invalid filters. |
409 | too_many_exports — 3 exports already pending or running. |
429 | Rate limit exceeded (10 calls/minute). |
Code examples
curl -X POST https://api.wemail.io/v3/events/export \
-H "Authorization: Bearer afn_live_…" \
-H "Content-Type: application/json" \
-d '{
"since": "2026-08-01T00:00:00Z",
"until": "2026-08-31T23:59:59Z",
"events": ["bounced", "complained"],
"tag": "billing"
}'
# → 202 { "export_id": "7f3a2b1c-…", "status": "pending" }// Plain HTTP — SDK helpers for exports are on the way
const res = await fetch("https://api.wemail.io/v3/events/export", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WEMAIL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
since: "2026-08-01T00:00:00Z",
until: "2026-08-31T23:59:59Z",
events: ["bounced", "complained"],
tag: "billing",
}),
});
const { export_id } = await res.json();import os, requests
r = requests.post(
"https://api.wemail.io/v3/events/export",
headers={"Authorization": f"Bearer {os.environ['WEMAIL_API_KEY']}"},
json={
"since": "2026-08-01T00:00:00Z",
"until": "2026-08-31T23:59:59Z",
"events": ["bounced", "complained"],
"tag": "billing",
},
)
export_id = r.json()["export_id"]