Scheduled reports: cadence, recipients, and the send-now path
A scheduled report is an analytics rollup Orbit emails to a fixed recipient list on a recurring cadence. Each report has a name, a report type (the metrics section it contains), a frequency (daily, weekly, or
monthly), a recipients list of 1–50 email addresses, and an optional
IANA timezone the cadence anchors to. The report arrives as an email
with the metrics rendered in the body and a PDF attached.
Report types:
All scheduled-report endpoints live under
/api/v1/analytics/scheduled-reports.
This is the only write surface for scheduled reports — the older
/api/v1/reports/scheduled CRUD was removed; any report it created was
migrated automatically, so nothing was lost.
Create a report
Create one withPOST /api/v1/analytics/scheduled-reports:
recipientsaccepts an array of emails or one comma-separated string; duplicates (case-insensitive) are dropped. Every entry must be a valid email, and the list is capped at 50 addresses. Expect a400(VALIDATION_ERROR) when a recipient is malformed.timezoneis optional. When set, the cadence anchor is validated as an IANA zone name (America/New_York,Asia/Tehran, …). When omitted, the cadence anchors to UTC.enableddefaults totrue; create with"enabled": falseto stage a report without sending it.filtersis an optional JSON object. Forcustomreports it carries the saved-query definition, andfilters.datasetmust bemessagesorqueue_performancewhen present.
How the cadence tick is computed
Every report fires at 09:00 local time — never at the moment you created it, and never a raw interval likeNOW() + 30 days:
daily→ next day at 09:00weekly→ the start of next week at 09:00monthly→ the first day of the next month at 09:00
next_send_at instant has already arrived — for example
right after a send-now request, or in the short window between a tick
becoming due and the scheduler claiming it — the API does not echo that
past/now value back. Because send-now works by marking the report due, the
raw value would otherwise read as “now” (or a past instant) even though the
recurring schedule didn’t change. Instead the API returns the upcoming
cadence tick, so the value you read (and the dashboard renders) is always
the next real 09:00 tick, never a transient due-time.
Edit cadence, recipients, or sections
PATCH /api/v1/analytics/scheduled-reports/{id} accepts any subset of
fields; omitted fields keep their current values. The endpoint requires at
least one field.
- Frequency changes re-anchor the schedule. When you change
frequency, the next tick is recomputed from the last send (or from now if the report never sent), floored so the result can never be in the past. So switching a stale weekly report to daily makes the next tick tomorrow at 09:00 — not next week minus the elapsed days. It also never triggers an immediate send as a side effect. - Recipient edits replace the list.
recipientsis replaced wholesale, not merged — pass the full final list on every update. The same 1–50 unique-valid-email rules apply.
Send-now: what it does and doesn’t do
send-now marks the report due; the scheduler worker picks it up on its
next tick and delivers it. It does not build and send the email inside
your HTTP request — the response returns immediately with
{ "queued": true }, keeping send/retry logic out of the API tier. Poll
GET /api/v1/analytics/scheduled-reports and watch last_sent_at to see
when it actually lands.
It also doesn’t move the cadence. Because the list endpoint presents the
upcoming 09:00 tick whenever a report is due, a daily report keeps showing
“tomorrow 09:00” after send-now rather than collapsing to “a few minutes
from now.”
Delete
{ "id": "sr_01H…", "deleted": true }.
Deleting stops all future sends; previously sent emails are of course
unaffected. To pause a report without losing its recipient list and
schedule, set "enabled": false on a PATCH instead of deleting it.
Role gate
Reads (GET) are open to any authenticated member of the organization.
Writes — create, update, delete, and send-now — require the owner or
admin role. A scheduled report emails recipient-level metrics (top
contacts, spend, error breakdowns) to an arbitrary list of addresses the
creator chooses: that is a data-egress path, so it’s restricted to roles
trusted to export org data. If viewer-role tokens could create reports, a
read-only member could exfiltrate the same analytics to any mailbox. The
role check comes back as a 403 on write endpoints for developer/viewer
keys and members.
Troubleshooting
See also
- Analytics API reference — endpoint table for
/api/v1/analytics/scheduled-reports - Production go-live checklist — launch gates before live traffic