Conversations API
Last updated: April 26, 2026
Conversations are the AI-guided chat sessions that produce reviews. The API exposes aggregate funnel stats — read-only, aggregate-only, scoped to your store. For per-conversation transcripts, see the moderation-side GET /api/v1/reviews/:id/transcript in the Reviews API.
Conversation Funnel Stats
GET /api/v1/conversations/stats
Aggregate counts for the AI review-chat funnel over a date window. Returns engagement buckets (no_show, one_and_done, mid_flow, completed, long, failed) and counts by origin (email, widget, api, playground). Pair origin=email with bucket counts to diagnose email-driven chat friction. Read-only — non-GET verbs return 405 with Allow: GET.
Query parameters
| Param | Type | Description |
|---|---|---|
from | ISO8601 date | Window start (filters started_at). Defaults to 30 days ago. |
to | ISO8601 date | Window end (inclusive). Defaults to today. |
origin | enum | email | widget | api | playground. Invalid values silently dropped. |
engagement_bucket | enum | no_show | one_and_done | mid_flow | completed | long | failed. |
has_initial_draft | "true" | Conversations where the AI produced an initial draft. |
has_final_draft | "true" | Conversations where the shopper submitted (final draft saved). |
has_support_request | "true" | Conversations that opened a support request. |
Window cap: (to − from) > 90 days returns 422 window_too_large. from > to returns 422 invalid_window.
Example
curl "https://api.betterreviews.app/api/v1/conversations/stats?origin=email&from=2026-04-01" \
-H "X-API-Key: YOUR_API_KEY" Response (200)
{
"store_id": 123,
"window": {"from": "2026-04-01", "to": "2026-04-26", "days": 25},
"filters_applied": {
"origin": "email",
"engagement_bucket": null,
"has_initial_draft": null,
"has_final_draft": null,
"has_support_request": null
},
"totals": {"all_in_window": 1234, "matching_filters": 456},
"engagement_buckets": {
"no_show": 12,
"one_and_done": 34,
"mid_flow": 56,
"completed": 200,
"long": 78,
"failed": 12
},
"engagement_buckets_pct": {
"no_show_pct": 3.16,
"one_and_done_pct": 8.95,
"mid_flow_pct": 14.74,
"completed_pct": 52.63,
"long_pct": 20.53,
"failed_pct": 3.16
},
"by_origin": {"email": 200, "widget": 100, "api": 0, "playground": 0},
"by_origin_pct": {
"email_pct": 66.67,
"widget_pct": 33.33,
"api_pct": 0.0,
"playground_pct": 0.0
}
} Engagement bucket definitions
| Bucket | Definition |
|---|---|
no_show | Active or abandoned status with 0 user messages — chat opened, never typed. |
one_and_done | 1 user message — typed once, dropped off. |
mid_flow | 2–7 user messages — engaged but didn't reach the end. |
completed | Status is completed, regardless of message count. |
long | 8+ user messages without completed/failed status. |
failed | Status is failed (LLM/system error). |
Origin definitions
| Origin | Source |
|---|---|
email | Conversation linked to a review request (shopper clicked an email link). |
widget | Storefront widget (no email link). |
api | Direct chat API call (no email link). |
playground | Internal merchant-side preview conversations. |
Notes
- The
engagement_bucketsaggregation excludes theengagement_bucketfilter from its own GROUP BY so pill counts stay stable when a bucket is selected. - Same for
by_originand theoriginfilter. totals.all_in_windowis store + window only (no other filters);totals.matching_filtersreflects all filter axes.- Percentages are computed within each block (so they sum to ~100%); they ignore the
engagement_bucketandoriginfilters so pill counts and pill percentages stay stable when you click around. *_pctvalues are clamped to[0.0, 100.0]andnullwhen there's nothing in the window.- Aggregate-only response — no per-row PII surfaces.