Reports and exports
ContentFlow keeps your segments, profiles, delivery results and analytics. This page covers every way to take them out: a CSV report built in the background and downloaded later, a report emailed on a schedule, the CSV behind an Analytics dashboard, and the Enterprise raw exports. All of it is on the dashboard and the management API, not the SDK.
- Reports → New report (or
POST /api/v1/reports) queues a CSV in the background; download it from Downloads when its status is Completed. - Reports → Scheduled emails a summary of the last day, week or month to up to 20 people; Send now sends one copy at once.
- Only admins and editors can run reports, and an editor sees and downloads only the reports they requested; delivery reports mask recipients for non-admins.
- Downloads are CSV only; the raw and compliance exports (JSON) need the Enterprise plan.
- The most common trap: delivery records are kept for 30 days, so a delivery report can't go further back. Keep the CSV if you need the history.
Ways to get data out
| You want | Use | Format |
|---|---|---|
| A list of segments, people, block changes, daily analytics or per-recipient delivery results | On-demand report: Reports → New report | CSV download |
| KPIs in stakeholders' inboxes every day, week or month | Scheduled report: Reports → Scheduled | HTML email |
| The numbers on the Analytics dashboard you're looking at | Export CSV on the Analytics page | CSV download |
| Every analytics event in a date range | Raw or compliance export (Enterprise) | JSON file |
| One person's devices and segments, from your backend | The read API: REST guide: read key | JSON |
| A call to your server when a campaign changes status | Webhooks: REST guide: webhooks | JSON |
Who can do what
Reports contain end-customer personal data, so the whole Reports surface is limited to admins and editors; a viewer sees Your role cannot run reports.
- On-demand reports: admins and editors can request them. An admin sees, downloads and deletes every report in the workspace; an editor only the ones they requested (anyone else's answers
403 FORBIDDEN_REPORT_OWNER, whether or not it exists). - Delivery reports mask recipients' email and phone for a non-admin requester, using the workspace's PII settings. Push tokens are never exported, for any role. The masking is decided when the report is built, by who requested it.
- Scheduled reports: admins and editors can list, create, edit, pause, enable and send them now; only admins can delete one.
API calls use a person's portal sign-in token (Authorization: Bearer …) and X-Tenant-Id; SDK, pk_, write and read keys don't open these routes. See Importing users and data: credentials.
On-demand reports
- Pick a Report type, a Report name, a Date range and the type's filters.
- The Management API validates the request and creates the report job as Queued.
If this step is skipped: A reversed date range, or a Custom report with no known column, is refused with 400 REPORT_INVALID_REQUEST and nothing is queued.
- The report moves to Processing while ContentFlow collects the rows it needs, depending on the type.
- The CSV is stored with the report job, with its row count.
If this step is skipped: If collecting the rows fails, the report is marked Failed with the reason, and you request it again.
- ContentFlow delivers a Report ready notification to the dashboard.
- The file is named
<type>-report-<date>.csv.
Downloads lists reports newest first, with Requested by, Requested, Completed, Rows and Status. Delete report removes the stored file.
Report types
Type (API type) | Filters | CSV columns |
|---|---|---|
Segments (segments) | Date range (segment creation date), Segment type (type) | id, name, type, conditionCount, logicalOperator, userCount, autoUpdate, updateFrequency, isActive, createdAt |
People (people) | Date range (profile last updated), Lifecycle, Region, Device (contains), In segment (segmentId), Marketing consent only (consentOnly) | userId, region, city, device, lifecycle, engagementScore, churnRisk, consentMarketing, segmentCount, segments, lastUpdated |
Custom columns (custom) | The People filters, plus Columns to include (columns, at least one; leave it out for all) | The People columns you pick |
Audit logs (audit_logs) | Date range, Block key | at, blockKey, title, instanceId, action, by, detail: block creates, publishes and pauses |
Analytics (analytics) | Date range | date, impressions, clicks, conversions, ctr, totalEvents, one row per day |
Delivery (delivery) | Date range, Channel, Status, Campaign | recipient, channel, provider, status, campaignId, sentAt, deliveredAt, readAt, failureReason, createdAt, one row per recipient |
- An open end date means today, and a date-only end includes that whole day.
- People, Custom and Delivery reports read at most 20,000 records.
- Delivery records are kept for 30 days, so a delivery report covers at most the last 30 days. A completed report's CSV is kept with the report, so it is the record of delivery history beyond that.
Reports API
export CF_API=https://api.contentflow.click/api/v1
# 1. Request a report (answers at once; status "queued")
curl -X POST $CF_API/reports \
-H "Authorization: Bearer $CF_PORTAL_TOKEN" -H "X-Tenant-Id: $CF_WORKSPACE_ID" \
-H 'Content-Type: application/json' \
-d '{"type":"delivery","name":"SMS in September",
"filters":{"dateFrom":"2026-09-01","dateTo":"2026-09-30","channel":"sms"}}'
# 2. Poll until "status":"completed" (or "failed")
curl $CF_API/reports/$REPORT_ID \
-H "Authorization: Bearer $CF_PORTAL_TOKEN" -H "X-Tenant-Id: $CF_WORKSPACE_ID"
# 3. Download the CSV
curl -o report.csv $CF_API/reports/$REPORT_ID/download \
-H "Authorization: Bearer $CF_PORTAL_TOKEN" -H "X-Tenant-Id: $CF_WORKSPACE_ID"GET /reports?page=&limit=&type=&status=lists reports: every report for an admin, your own for an editor.GET /reports/{id}/downloadanswers the CSV itself (text/csv), not JSON. A report that isn't ready answers409withREPORT_DOWNLOAD_FAILED.DELETE /reports/{id}deletes it.- Statuses:
queued,processing,completed,failed(witherror).
Scheduled reports
Reports → Scheduled → New report sets up an email that goes out on its own. Fields: Report name, Description (optional), Report type, Frequency (Daily, Weekly or Monthly), Day of week or Day of month (1 to 28), Send time (UTC), Recipients and Enabled.
| Report type | The email contains |
|---|---|
Overview (overview) | KPI totals and top campaigns |
Audience (audience) | KPI totals and top segments, no campaign table |
Full Report (full) | KPI totals, top campaigns and top segments |
- The email covers the last 24 hours for a daily report, the last 7 days for weekly and the last 30 days for monthly. Schedules are checked every hour.
- Older schedules can carry
campaignsorengagement; they send the same email as Overview and are no longer offered. - Up to 20 recipients per report and 10 scheduled reports per workspace.
- Send now builds and emails one copy straight away, even for a paused report. It can't be repeated within 5 minutes (Sent recently), and won't send while a send is running or when the last send never confirmed whether it was delivered (Last send did not confirm): check with the recipients before you send again.
- Pause and Enable switch the schedule; Edit and Delete (admin) change or remove it.
- With Test mode on, the dashboard won't enable a schedule or send one now, because the emails go to real recipients with live data.
Scheduled reports API
GET /api/v1/settings/scheduled-reports list (admin, editor)
GET /api/v1/settings/scheduled-reports/{id} one
POST /api/v1/settings/scheduled-reports create
PUT /api/v1/settings/scheduled-reports/{id} edit
PATCH /api/v1/settings/scheduled-reports/{id}/toggle { "enabled": false } pauses, true enables
POST /api/v1/settings/scheduled-reports/{id}/send-now email one copy now
DELETE /api/v1/settings/scheduled-reports/{id} delete (admin)
POST body: { "name": "Weekly summary", "reportType": "overview", "frequency": "weekly",
"dayOfWeek": 0, "hour": 9, "recipients": ["…"], "enabled": true }reportTypedefaults tooverview;dayOfWeek(0 to 6) is required for weekly anddayOfMonth(1 to 28) for monthly;houris UTC and defaults to 9.- Validation failures answer
400naming the field: an invalid email, more than 20 recipients, a missing day, or the 10-report limit. send-nowanswers429 REPORT_SEND_COOLDOWNwithRetry-Afterwithin 5 minutes of the last send,409 REPORT_SEND_IN_PROGRESSor409 REPORT_SEND_UNRESOLVED(don't retry: it may already have gone out), and502 REPORT_SEND_FAILEDwhen nothing was sent.
Analytics CSV
Export CSV in the Analytics page header downloads the dashboard you're looking at, for the selected range, as one CSV. It exports only the live rows that dashboard fetched and shows. When a view has nothing live to export, the button is off (Export is not available for this view yet).
Raw and compliance exports
On the Enterprise plan, two management API routes download the workspace's analytics data for a date range as a JSON file:
GET /api/v1/analytics/export/raw?startDate=2026-09-01&endDate=2026-09-30
GET /api/v1/analytics/export/compliance?startDate=…&endDate=… adds exportedAt and the workspace idOn another plan they answer 403 with UPGRADE_REQUIRED. They are not in the dashboard.
Data Explorer
Audience → Data Explorer is for looking at your audience in the dashboard rather than exporting it. Overview shows the total of known profiles and how many have an email, a phone, a push token and marketing consent; Fields shows the distribution of any field; Correlate cross-tabulates two fields. It is not available in Test mode. To take the rows out, use a People or Custom report.
When it doesn't work
| What you see | Why, and the fix |
|---|---|
Your role cannot run reports, or 403 on /reports | Viewers can't run reports. Ask an admin to change your role or run it for you. |
403 FORBIDDEN_REPORT_OWNER | The report was requested by someone else (or doesn't exist). Editors only see their own; ask an admin. |
400 REPORT_INVALID_REQUEST | The start date is after the end date (or after today with no end), or a Custom report names no known column. |
Download answers 409 REPORT_DOWNLOAD_FAILED (The report is not ready yet) | The report is still queued or processing, or failed. Poll GET /reports/{id} and download once it is completed. |
| A delivery report shows masked recipients | It was requested by a non-admin. An admin requests it again for full addresses; push tokens are never exported. |
| Send now: Sent recently or Last send did not confirm | Wait the 5-minute cooldown; for an unconfirmed send, check with recipients before sending again. |
Next
- Analytics: where the numbers in analytics reports and dashboards come from.
- Importing users and data: the other direction, loading people and attributes in.