Setup guide · GreenArrow
Everything needed to stream GreenArrow's Event Notification System into BigStats: the webhook configuration, the event types you should send, example payloads for each one, and the alerts they drive.
Looking for the overview instead? GreenArrow reporting.
Step 01
In BigStats, open Settings → Ingestion and create a key for this GreenArrow install. Keys are workspace-scoped; use separate keys per node if you want to trace where events came from. Send the key as ?key= or the X-BigStats-Key header.
Endpoint
POST https://bigstats.email/api/public/ingest/greenarrow?key=<INGEST_KEY>
Step 02
BigStats accepts one event per request or batches — a JSON array, newline-delimited JSON, or an object wrapper keyed by events, records or logs. Retries are safe: events are de-duplicated on event type, message id, recipient, timestamp and URL.
Step 03
The four required events are the minimum for correct rates and alerting. Opens and clicks are optional and only arrive if tracking is enabled in GreenArrow.
| GreenArrow event | BigStats event | Status | Why it matters |
|---|---|---|---|
| injection | injected | Required | Denominator for delivery, bounce and complaint rates. |
| delivery | delivered | Required | Delivery rate, ISP placement and delivery-rate-floor alerts. |
| bounce | bounced | Required | Hard/soft/block classification and bounce-rate alerts. |
| deferral | deferred | Required | Deferral-rate and throttling alerts before a bounce wave. |
| spam_complaint | complained | Recommended | Feedback-loop complaints and complaint-rate alerts. |
| unsubscribe | unsubscribed | Recommended | Unsubscribe-rate alerting and list-health reporting. |
| open | opened | Optional | Engagement reporting; requires open tracking enabled. |
| click | clicked | Optional | Click reporting with destination URL and user agent. |
| rejection | rejected | Optional | Suppression and pre-injection refusals, kept out of delivery stats. |
Step 04
Message accepted by GreenArrow Engine. Establishes the denominator for delivery, bounce and complaint rates.
injection → injected
{
"type": "injection",
"timestamp": "2026-08-11T14:02:11Z",
"recipient": "jordan@gmail.com",
"message_id": "01HZX9K7Q2W8N4C6",
"campaign_id": "weekly-digest-2026-08",
"mailing_id": "m-99231",
"subject": "Your weekly delivery digest",
"source_ip": "203.0.113.42",
"vmta": "pool-transactional"
}Batched events
{
"events": [
{ "type": "delivery", "recipient": "a@gmail.com", "message_id": "m-1",
"timestamp": "2026-08-11T14:02:18Z", "smtp_code": 250 },
{ "type": "bounce", "recipient": "b@gmail.com", "message_id": "m-2",
"timestamp": "2026-08-11T14:02:19Z", "smtp_code": 550,
"diagnostic_code": "550 5.1.1 user unknown" }
]
}Request formats
POST /api/public/ingest/greenarrow?key=ga_live_…
Content-Type: application/json
# the key may also be sent as the header: x-bigstats-key: ga_live_…
# a single notification …
{ "type": "delivery", "recipient": "jordan@gmail.com", "timestamp": 1785000012 }
# … or a batch: a JSON array, newline-delimited JSON,
# or an object wrapper using "events", "records" or "logs"Responses
HTTP/1.1 200 OK
{ "ok": true, "received": 2 }
# failures
401 { "error": "missing ingest key" } # no ?key= and no x-bigstats-key header
401 { "error": "invalid ingest key" } # unknown or deactivated key
400 { "error": "no events found in payload" }
413 { "error": "too many events in one batch" } # hard cap of 25,000 records per POST
500 { "error": "could not store events" } # safe to retry; duplicates are droppedField mapping
| GreenArrow field | BigStats column | Notes |
|---|---|---|
| type / event_type / event / action | event_type | delivery→delivered, bounce/hard_bounce/soft_bounce→bounced, deferral/tempfail→deferred, open→opened, click→clicked, unsubscribe→unsubscribed, spam_complaint/fbl→complained, rejection/blocked→rejected, injection→injected. Anything unrecognized lands as other. |
| timestamp / time / event_time / date | occurred_at | Unix seconds, milliseconds or an ISO 8601 string. Missing timestamps default to receipt time. |
| recipient / email / to / rcpt | recipient / recipient_domain / isp_group | Lowercased; the domain is split off and grouped into gmail · microsoft · yahoo · apple · corporate · other. |
| message_id / msg_id / queue_id / id | message_id | First match wins. Used in the dedupe hash with type, recipient, timestamp and url. |
| source_ip / sending_ip / vmta_ip / outbound_ip | sending_ip | The /24 is derived from it for MTA clustering. |
| vmta / virtual_mta / binding / pool | vmta | Drives the Shared Pools reporting. |
| remote_mta / receiving_mta / reporting_mta / mx_host | remote_mta | The receiving MX that answered. |
| smtp_code (or parsed from the response) | smtp_code | Validated to 200–599; falls back to the first 3-digit code inside the diagnostic text. |
| dsn / dsn_status / enhanced_status | dsn | Falls back to an enhanced status code parsed out of the diagnostic, e.g. 5.1.1. |
| diagnostic_code / response / smtp_response / reason | diagnostic | Full remote reply text retained for bounce forensics. |
| bounce_type / bounce_class / classification | bounce_type / bounce_category | Used as the declared hint; BigStats still classifies from the SMTP code and diagnostic into hard · soft · block plus a reason category. |
| campaign_id / campaign / mailing_name / list_id | campaign_id | First match wins. |
| mailing_id / mailing / job_id / batch_id | mailing_id | First match wins. |
| subject / message_subject | subject | Shown on event drill-down and exports. |
| url / link / click_url | url | Click destination; also part of the click dedupe key. |
| user_agent / ua / client | user_agent | Captured on opens and clicks. |
| (whole payload) | raw | The complete JSON notification is retained on the event row for drill-down and export. |
Step 05
Run a dry run first: it authenticates your key and returns the normalized event exactly as BigStats would store it. Then remove dry_run=1 and watch the live feed on the Settings page confirm events arriving.
curl
curl -s -X POST \
'https://bigstats.email/api/public/ingest/greenarrow?key=<INGEST_KEY>&dry_run=1' \
-H 'Content-Type: application/json' \
-d '{"type":"bounce","recipient":"test.user@gmail.com",
"timestamp":"2026-08-11T14:04:02Z","source_ip":"203.0.113.42",
"smtp_code":550,"dsn":"5.1.1",
"diagnostic_code":"550 5.1.1 The email account that you tried to reach does not exist."}'
# dry_run authenticates and normalizes the payload but stores nothing:
# { "ok": true, "dry_run": true, "received": 1, "events": [ … ] }Step 06
Once events are flowing, alerting runs on them automatically — open Alert settings to set thresholds and recipients.