Overview
GET /api/analytics returns one consolidated metric block for your workspace,
filterable down to a single campaign, sender line, sending user, or date
window. The same numbers power the /analytics page in the dashboard and
the analytics MCP tool, so a UI chart, an MCP question, and a curl call all
agree.
Reply rate and positive rate are computed as unique-by-contact ratios.
A contact who got 5 messages still counts as 1 toward “reached”, and one
contact who replies 10 times still counts as 1 toward “uniqueReplied”.
Endpoint
Authentication
Bearer-token. Pass your API key (tuco_...) in the Authorization header:
Query parameters
Restrict the result to one campaign (MongoDB ObjectId as 24-char hex).
Restrict to a single sender line (MongoDB ObjectId as 24-char hex).
Restrict to a single Clerk user ID who created the messages (
user_…).Inclusive lower bound, ISO 8601 (e.g.
2026-06-01T00:00:00Z). Filters on
message.createdAt.Inclusive upper bound, ISO 8601.
Reserved for the multi-workspace agency rollup that ships later. Today the
endpoint returns 501 Not Implemented if this parameter is supplied;
call without it to get your own workspace’s numbers.
Response
Metric definitions
Distinct contacts (phone or email) that received at least one outbound
message with status
sent or delivered inside the filter window.Total outbound messages with status
sent or delivered. Not de-duplicated
by contact — a 7-step campaign over 1,000 contacts can show sent ≈ 7,000.Outbound messages with status
fallback or with fallbackSmsDispatched
set. Both signal iMessage didn’t go through and SMS was attempted instead.Outbound messages with status
failed — hard send failure (technical
error, blocked recipient, transient-exhausted, etc.).Total inbound messages received inside the filter window. Includes
multiple replies from the same contact.
Distinct contacts that replied at least once inside the window.
uniqueReplied / reached. A decimal between 0 and 1 (multiply by 100 for
the display %). Returns 0 when reached is 0 — never divides by zero.Distinct contacts among
uniqueReplied whose conversation document carries
at least one positive tag: interested, to respond, to-answer, or
to_answer (case-insensitive exact match). Tags are written by Tuco’s
reply classifier and by Unibox operators.positiveReplied / uniqueReplied. Share of repliers tagged warm. Returns
0 when uniqueReplied is 0.Error responses
| Status | Code | When |
|---|---|---|
401 | Unauthorized | Missing or invalid API key / Clerk session |
501 | AGENCY_NOT_AVAILABLE | agencyId filter supplied — feature not yet shipped |
500 | — | Aggregation failed; check Loki for the analytics.error event |
Example: pull last-30-day numbers for one campaign
Example: via MCP
Configure the Tuco MCP server and ask any MCP-compatible AI assistant:
“Show analytics for campaign 60d5ec49e3a8a0001f9b1234 over the last 30
days.”
The assistant calls the analytics MCP tool, which hits this endpoint with
your API key and returns the same metric block.
Observability
Every successful call emits a structuredanalytics.served event to Loki:
analytics.error with the error message and workspace id.