Reports: generate now or schedule delivery
Orbit produces analytics reports two ways:- Ad hoc (generate now). Open Insights → Reports in the dashboard, pick a date range, and click a report card. The report renders in the page, downloads as CSV or PDF, and its metadata is saved to your account so it syncs across your devices.
- Scheduled (recurring email). A scheduled report emails a fixed
recipient list on a
daily,weekly, ormonthlycadence, with the metrics rendered in the body and a PDF attached.
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.
Generate a report now (ad hoc)
For a one-off report, you don’t need the API or a schedule at all:- Open Insights → Reports in the dashboard.
- Pick the reporting window with the 7d / 30d / 90d / 12m switcher. Reports honor the selected range, so the figures match the analytics KPIs for the same window.
- Click a report card. The report generates immediately and opens in the page viewer.
- Download it as CSV or PDF from the viewer toolbar.
Two SLA sections sit below the card grid on the same page:
- SLA attestation — a monthly attestation of your messaging delivery SLA. Pick a recent complete calendar month, read the summary, download as CSV or PDF.
- Queue SLA — per-queue service-level figures over a reporting window, with a paginated breach ledger. Pick a window, read the summary, download as CSV or PDF.
The saved-report lifecycle
Every report you generate is saved. The Report history table at the bottom of the page lists the most recent 50 reports per account, newest first, and syncs across devices — reports generated on one machine appear on any other machine where you sign in. A per-browser local cache shows the list instantly while the account copy loads. Only report metadata is persisted — the type, name, generated-at timestamp, and column headers. Row-level data is deliberately never saved: a report’s rows can contain customer phone numbers, email addresses, and contact names, so nothing that sensitive sits in browser storage or syncs to your account. The practical consequences:- Reopening a historical report shows its columns with zero rows, and the download buttons are disabled. Click Re-run report on the empty state to load fresh figures, then export.
- A report generated more than 24 hours ago is flagged Stale in the history table; regenerate it for accurate numbers.
- Deleting beyond the 50-report retention happens automatically — the oldest entries drop off as new reports are generated.
Downloads and formats
CSV filenames follow
<report-type>-YYYY-MM-DD.csv, stamped with the
report’s generation date. Timestamps in the viewer and history table are
rendered in your workspace timezone. Numeric CSV columns carry numbers or
empty cells — never N/A — so spreadsheet SUM and sort keep working.
Schedule or generate once?
- Generate now when you need a figure once — a board deck, a billing review, an incident report. It’s immediate: no recipients to manage, no schedule to clean up, and the saved history means you can re-run the same report next week in one click.
- Schedule when the same people need the same numbers every week or month without signing in — the report lands in their inbox at 09:00 local on the cadence tick. Scheduled delivery also reaches stakeholders who don’t have dashboard access, since recipients are plain email addresses.
type (messaging volume, deliverability, top contacts, spend) maps onto
the same figures the dashboard cards compute on demand.
Create a scheduled 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