POST | /v1/analytics/events | Ingest an analytics event. Accepts the NATIVE event shape, a platform-event envelope ({source:platform-event, event_type, entity_id, user_id, properties}), or a voice-metric envelope ({source:voice-metric, event_type:call_start |
| | |
GET | /v1/analytics/events | Newest-first event feed (org-scoped), optionally filtered by event_type / user_id. |
DELETE | /v1/analytics/events | GDPR Art-17 right-to-be-forgotten — erase a DATA SUBJECT's WHOLE analytics footprint within the org, keyed source-AGNOSTICALLY on user_id and/or consent_ref (so BOTH the live 'platform-event' bucket and the migrated 'platform_news_events' bucket are erased). FIRST-PARTY admin only (trusted-service token; an end-user JWT cannot erase). FAIL-CLOSED — at least one selector is REQUIRED (a blank selector is refused, never a blanket wipe). entity_id is NOT a valid selector (not person-identifying). dry_run=true previews the per-bucket footprint WITHOUT deleting. Selectors accepted as query params or JSON body. |
| | |
GET | /v1/analytics/subject-footprint | GDPR Art-15 access preview + the 2-bucket correspondence probe — per-source (bucket) event count for a data subject (user_id and/or consent_ref) within the org, NON-mutating. Proves a subject's user_id spans BOTH the 'platform-event' and 'platform_news_events' buckets (the precondition for a source-agnostic erase). FIRST-PARTY admin only. FAIL-CLOSED (>= one selector). |
| | |
GET | /v1/analytics/summary | Aggregated dashboard summary (event_count, unique_users, primary/cost totals, by_type). Window defaults to 30 days. |
GET | /v1/analytics/trends | Daily measure series + first/second-half comparison. |
GET | /v1/analytics/heatmap | 7×24 DOW×hour event-count heatmap + peak hour/day (subsumes JS /usage-heatmap + call /peak-hours). |
GET | /v1/analytics/forecast | Usage/cost forecast (least-squares linear regression + weekday/weekend seasonal multiplier + R² + 80% confidence interval + trend) — ports the voice JS forecaster. Needs >= min data points (default 7). |
| | |
GET | /v1/analytics/anomalies | Detect usage anomalies (z-score, 4 severity bands + pattern-change) — ports the voice JS anomaly-detector. list_persisted=true returns stored anomalies (resolved filter); persist=true saves detected ones. |
| | |
POST | /v1/analytics/anomalies/{anomaly_id}/resolve | Mark a persisted anomaly resolved (org-scoped). |
GET | /v1/analytics/cost-simulation | Cost across usage scenarios (Current/±20/±50) × the configured tier catalog — ports tier-recommender simulateCosts. Defaults to the forecasted usage when units omitted. Returns no_tier_catalog when unset. |
| | |
GET | /v1/analytics/tier-recommendation | Recommend the cheapest tier for the forecasted usage + savings + should-change gate (min-savings + days-into-cycle) — ports tier-recommender. Returns no_tier_catalog when unset. |
| | |
GET | /v1/analytics/cost | Cost breakdown by the configured component split (parameterized from voice's 70/30 LLM/voice). |
GET | /v1/analytics/cohorts | List cohorts (org-scoped). |
POST | /v1/analytics/cohorts | Create a cohort (name + criteria_type + criteria). |
GET | /v1/analytics/cohorts/{cohort_id} | Get one cohort. |
DELETE | /v1/analytics/cohorts/{cohort_id} | Delete a cohort. |
GET | /v1/analytics/cohorts/{cohort_id}/members | Resolved cohort membership (user_ids) over the event ledger. |
GET | /v1/analytics/cohorts/{cohort_id}/retention | Cohort retention (D1/D7/D30 by default) — ports get_retention_analysis. |
GET | /v1/analytics/funnels | List funnels (org-scoped). |
POST | /v1/analytics/funnels | Create a funnel (name + steps[]). |
GET | /v1/analytics/funnels/{funnel_id} | Get one funnel. |
DELETE | /v1/analytics/funnels/{funnel_id} | Delete a funnel. |
POST | /v1/analytics/funnels/{funnel_id}/track | Record a funnel step occurrence (dedup first-occurrence-wins per org/funnel/step/user). |
GET | /v1/analytics/funnels/{funnel_id}/conversion | Per-step conversion + drop-off over the ordered funnel. |
GET | /v1/analytics/models | List predictive models (org-scoped). |
POST | /v1/analytics/models | Upsert a predictive model (backs the platform's in-memory model store with persistence). |
GET | /v1/analytics/models/{model_id} | Get one predictive model. |
GET | /v1/analytics/export | Export events as JSON or CSV (org-scoped) — ports the voice sealed export surface. |
POST | /v1/analytics/erase-by-consent | GDPR Art-17 erasure — delete every event tagged (organization_id, consent_ref). FIRST-PARTY admin only (requires the trusted-service token; an end-user JWT cannot erase). Ports the voice sealed erase-by-consent. |
| | |
GET | /v1/analytics/stream | Org-scoped realtime SSE stream of ingested events (text/event-stream). Subsumes the voice sealed Socket.IO realtime-metric-stream capability at the capability tier (in-process fan-out; the Redis-Sentinel HA transport substrate is a deploy-scale concern, deliberately simplified here). |
| | |
GET | /v1/analytics/reports/customer | Per-customer engagement + usage report for the caller's org over a rolling window |
POST | /v1/funnel-events | Ingest a FLEET-scoped pre-org signup funnel event from the console. Unlike every other route here this one is NOT org-scoped: an attempt_id is minted before any user or organization exists, so there is no tenant to resolve and no organization_id is stored. It therefore accepts the first-party service token ONLY — never an end-user identity JWT, which would let any authenticated tenant write fleet rows. Idempotent on (attempt_id, type); one attempt legitimately emits both submitted and failed. |
| | |
POST | /v1/journey-events | Ingest a batch of JOURNEY events for a registered journey-event contract. Like /v1/funnel-events and unlike every org-scoped route here, this is not tenant-scoped: most of a journey happens before an organization exists, so journey_id is the spine and the first-party service token is the only accepted credential. The accepted contract ids, event names, envelope fields and forbidden keys are NOT defined here — they come from the contract documents the service has registered, which is what lets a second product join the stream without a change to this capability. Dedup is on the emitter-minted event_id, so at-least-once delivery is safe. |
| | |
GET | /v1/journey-funnels/{funnel_id} | Stage counts for a registered funnel, in the funnel definition's declared order. Counts are DISTINCT journeys per stage, never rows — an impression event fires once per card, so a row count would make the top of the funnel a function of page layout. A stage with no events is returned with 0 rather than omitted. |
| | |
GET | /v1/journeys/{journey_id} | one journey's events, oldest first — the read behind attribution continuity |
GET | /health | liveness + store/tenancy posture |
GET | /metrics | Prometheus exposition |