Skip to main content

Analytics & Insights API

Read endpoints over the delivery, engagement, and conversion data the platform records for your workspace: campaign and journey funnels, attribution rollups, a best-time-to-send heatmap, holdout lift readouts, and chart annotations. Conversion tracking is configured through the same surface.

These endpoints are authenticated with a bearer token:

Authorization: Bearer YOUR_ACCESS_TOKEN

Timestamps are RFC 3339. Where a start / end window is accepted, both are optional and the window defaults to the last 30 days.


GET /api/v1/insights/funnel

Returns the engagement funnel for one campaign or journey: how many messages were sent, delivered, opened, clicked, and how many conversions (with revenue) were attributed back to it.

Query parameters

ParamTypeRequiredDescription
source_typestringYescampaign or journey.
source_idstringYesUUID of the campaign or journey (the ID, not the name).
startRFC 3339NoWindow start. Defaults to 30 days ago.
endRFC 3339NoWindow end. Defaults to now.

Response — 200 OK

{
"sent": 12000,
"delivered": 11800,
"opened": 4100,
"clicked": 950,
"converted": 120,
"revenue_cents": 458800
}

422 — missing or invalid source_type, or source_id is not a valid UUID.

GET /api/v1/insights/summary

Attribution summary grouped by campaign, journey, or channel: conversions and attributed revenue per source over the window.

Query parameters

ParamTypeRequiredDescription
group_bystringYescampaign, journey, or channel.
startRFC 3339NoWindow start. Defaults to 30 days ago.
endRFC 3339NoWindow end. Defaults to now.

Response — 200 OK

{
"rows": [
{
"source_id": "9c4e1f2a-7b6d-4c3e-8a1f-2b3c4d5e6f70",
"conversions": 120,
"revenue_cents": 458800
}
]
}

422 — missing or invalid group_by.

GET /api/v1/insights/heatmap

Best-time-to-send heatmap: engagement bucketed by weekday and hour (UTC) over a trailing window. Empty buckets are omitted from cells; fill the 7 × 24 grid client-side (weekday 0 = Sunday … 6 = Saturday, hour 0–23).

Query parameters

ParamTypeRequiredDescription
daysintNoTrailing window in days. Defaults to 90, capped at 365.

Response — 200 OK

{
"window_days": 90,
"cells": [
{ "weekday": 2, "hour": 9, "delivered": 1800, "opened": 640 }
]
}

GET /api/v1/insights/lift

Treated-versus-holdout lift readout for a send that was created with a holdout percentage. Compares the conversion rate of subscribers who received the message against the held-out control group.

Query parameters

ParamTypeRequiredDescription
job_idstringYesThe notification job ID of the send.

Response — 200 OK

{
"job_id": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e",
"treated": {
"size": 9500,
"converters": 240,
"conversion_rate": 0.0253,
"revenue_cents": 912000
},
"holdout": {
"size": 500,
"converters": 6,
"conversion_rate": 0.012,
"revenue_cents": 22800
},
"lift_percentage_points": 1.33,
"window_days": 7,
"conversion_configured": true
}
FieldTypeDescription
treated / holdoutobjectGroup size, converters within the attribution window, derived conversion_rate (0 when the group is empty), and conversion revenue.
lift_percentage_pointsnumberTreated conversion rate minus holdout rate, in percentage points.
window_daysnumberThe attribution window applied.
conversion_configuredbooleanfalse when the workspace has no conversion events configured — the readout is vacuously zero; configure a conversion event first.

422 — missing job_id.


Conversion configuration

Attribution needs to know which behavioral events count as conversions. Definitions apply workspace-wide.

GET /api/v1/insights/config

Response — 200 OK

{
"definitions": [
{
"event_name": "purchase",
"value_property": "total_cents",
"window_seconds": 604800
}
]
}

POST /api/v1/insights/config

Creates or updates a conversion event definition (upsert by event_name).

Request Body

{
"event_name": "purchase",
"value_property": "total_cents",
"window_seconds": 604800
}
FieldTypeRequiredDescription
event_namestringYesThe behavioral event name that counts as a conversion.
value_propertystringNoEvent property holding the revenue amount in cents.
window_secondsintNoAttribution window after a message touch.

Returns 204 No Content.

DELETE /api/v1/insights/config

Deletes a conversion event definition. The event name is passed as a query parameter (names may contain dots).

Query parameters

ParamTypeRequiredDescription
event_namestringYesName of the definition to delete.

Returns 204 No Content, or 404 if no definition with that name exists.


Chart annotations

Annotations are timestamped notes that render on analytics charts — some are recorded automatically by the platform (for example plan changes), and you can create your own.

The annotation object

FieldTypeDescription
idstringAnnotation UUID.
occurred_atstringWhen the annotated moment happened.
ends_atstringOptional range end; absent for point annotations.
textstringThe note text.
sourcestringauto (platform-recorded) or manual (user-created).
kindstringAnnotation kind; manual annotations are always custom.
visibilitystringtenant or agency_only.
ref_idstringOptional reference to the related object.
created_bystringUser who created a manual annotation.
created_atstringCreation timestamp.

GET /api/v1/annotations

Lists annotations overlapping a time range.

Query parameters

ParamTypeRequiredDescription
fromRFC 3339YesRange start.
toRFC 3339YesRange end; must not precede from.
kindsstringNoComma-separated kind filter, e.g. custom,plan_change.

Response — 200 OK

{
"annotations": [
{
"id": "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"occurred_at": "2026-07-20T09:00:00Z",
"text": "Summer campaign launch",
"source": "manual",
"kind": "custom",
"visibility": "tenant",
"created_at": "2026-07-20T09:05:00Z"
}
]
}

422from / to missing, not RFC 3339, or to precedes from.

POST /api/v1/annotations

Creates a manual annotation (kind is always custom).

Request Body

{
"occurred_at": "2026-07-20T09:00:00Z",
"ends_at": "2026-07-21T09:00:00Z",
"text": "Summer campaign launch",
"visibility": "tenant"
}
FieldTypeRequiredDescription
occurred_atRFC 3339YesWhen the annotated moment happened.
ends_atRFC 3339NoRange end for range annotations.
textstringYesNote text, up to 500 characters.
visibilitystringNoDefaults to tenant. agency_only may only be set from an agency session operating on a client workspace.

Returns 201 with the created annotation object. 403 — read-only session, or agency_only requested outside an agency session.

DELETE /api/v1/annotations/:id

Deletes a manual annotation. Platform-recorded (source: "auto") annotations cannot be deleted.

Returns 204 No Content, or 404 if the annotation does not exist.