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

ParamTypeDescription
fromISO8601 dateWindow start (filters started_at). Defaults to 30 days ago.
toISO8601 dateWindow end (inclusive). Defaults to today.
originenumemail | widget | api | playground. Invalid values silently dropped.
engagement_bucketenumno_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

BucketDefinition
no_showActive or abandoned status with 0 user messages — chat opened, never typed.
one_and_done1 user message — typed once, dropped off.
mid_flow2–7 user messages — engaged but didn't reach the end.
completedStatus is completed, regardless of message count.
long8+ user messages without completed/failed status.
failedStatus is failed (LLM/system error).

Origin definitions

OriginSource
emailConversation linked to a review request (shopper clicked an email link).
widgetStorefront widget (no email link).
apiDirect chat API call (no email link).
playgroundInternal merchant-side preview conversations.

Notes

  • The engagement_buckets aggregation excludes the engagement_bucket filter from its own GROUP BY so pill counts stay stable when a bucket is selected.
  • Same for by_origin and the origin filter.
  • totals.all_in_window is store + window only (no other filters); totals.matching_filters reflects all filter axes.
  • Percentages are computed within each block (so they sum to ~100%); they ignore the engagement_bucket and origin filters so pill counts and pill percentages stay stable when you click around.
  • *_pct values are clamped to [0.0, 100.0] and null when there's nothing in the window.
  • Aggregate-only response — no per-row PII surfaces.