Send funnel
Totals plus per-template and per-day breakdowns with rates and deliverability warnings. Rates are null (not 0) when the denominator is zero, so "no data" stays distinguishable from "0%". Opens and clicks are rated against DELIVERED, not sent. Defaults to the last 7 days.
bearerAuth writeAuthorizationBearer <token>An API key from the dashboard under Settings → API keys, sent as Authorization: Bearer aem_….
Authorization has two independent axes.
The scope is ranked — a key satisfies any requirement at or below its own tier:
read— see messages, contacts and metrics. Changes nothing, and cannot send.write— everythingreaddoes, plus managing templates, contacts, automations, segments and suppressions. This is what editing a template needs.admin— everythingwritedoes, plus sending configuration: domains, senders, webhook registration, kill switch, daily cap, brand.
There is no approve scope. It was a rung once; it is not one now, and a key requested with it is rejected.
The approval grant (can_approve) is a separate boolean, not a rung. Delivering mail to a real inbox needs write and the grant. Keeping them on separate axes is what makes the review gate a control rather than a convention: a key that may propose is not automatically a key that may approve its own proposal.
Give your application the lowest tier that works. Most need write and the grant — the dashboard mints that combination as Send + manage; Manage only is the same rung with the grant withheld.
Scope: write
since?stringISO 8601 start (default: 7 days ago).
date-timeuntil?stringISO 8601 end (default: now).
date-timeMetrics.
application/json- response
period?totals?by_template?Keyed by template slug.
by_day?Keyed by YYYY-MM-DD.
warnings?array<string>Deliverability tripwires, phrased as actions.
truncated?booleanTrue when the window hit the query cap — narrow it for exact numbers. Always false when source is daily_rollup, which is pre-aggregated and has no cap to hit.
source?stringWhich engine answered. raw reads the message log directly and is exact to the second. daily_rollup is used once since reaches past the 30-day log retention window, past which the individual rows no longer exist — it is aggregated to whole UTC days, so period reports the snapped window rather than the one you asked for, and a warning says so. One engine always answers the whole range; the two are never mixed.
"raw""daily_rollup"curl -X GET 'https://sendandretain.com/api/v1/metrics'{ "period": { "since": "2019-08-24T14:15:22Z", "until": "2019-08-24T14:15:22Z" }, "totals": {}, "by_template": {}, "by_day": {}, "warnings": [ "Complaint rate above 0.08% — stop and investigate before sending more." ], "truncated": true, "source": "raw"}