Skip to main content

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

GET https://app.tuco.ai/api/analytics

Authentication

Bearer-token. Pass your API key (tuco_...) in the Authorization header:
curl -H "Authorization: Bearer tuco_..." https://app.tuco.ai/api/analytics

Query parameters

campaignId
string
Restrict the result to one campaign (MongoDB ObjectId as 24-char hex).
lineId
string
Restrict to a single sender line (MongoDB ObjectId as 24-char hex).
userId
string
Restrict to a single Clerk user ID who created the messages (user_…).
dateFrom
string
Inclusive lower bound, ISO 8601 (e.g. 2026-06-01T00:00:00Z). Filters on message.createdAt.
dateTo
string
Inclusive upper bound, ISO 8601.
agencyId
string
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.
All filters are intersected. Omit a filter to remove that constraint.

Response

{
  "success": true,
  "filter": {
    "campaignId": "60d5ec49e3a8a0001f9b1234",
    "dateFrom": "2026-06-01T00:00:00.000Z"
  },
  "metrics": {
    "reached": 1245,
    "sent": 3870,
    "fallback": 92,
    "failed": 14,
    "replied": 418,
    "uniqueReplied": 312,
    "repliedPct": 0.2506,
    "positiveReplied": 71,
    "positivePct": 0.2275
  },
  "explainer": {
    "reached": "Unique contacts that received at least one outbound message (status sent or delivered).",
    "sent": "Total outbound messages with status sent or delivered. One contact may count more than once.",
    "fallback": "Outbound messages that fell back to SMS or could not be sent via iMessage.",
    "failed": "Outbound messages that hit a hard send failure (technical error, blocked recipient, etc.).",
    "replied": "Total inbound messages from contacts in the window.",
    "uniqueReplied": "Distinct contacts that replied at least once.",
    "repliedPct": "uniqueReplied / reached. Reply rate by unique contact.",
    "positiveReplied": "Distinct contacts whose conversation carries a positive tag (interested, to respond, to-answer).",
    "positivePct": "positiveReplied / uniqueReplied. Share of replies that are warm."
  }
}

Metric definitions

reached
number
Distinct contacts (phone or email) that received at least one outbound message with status sent or delivered inside the filter window.
sent
number
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.
fallback
number
Outbound messages with status fallback or with fallbackSmsDispatched set. Both signal iMessage didn’t go through and SMS was attempted instead.
failed
number
Outbound messages with status failed — hard send failure (technical error, blocked recipient, transient-exhausted, etc.).
replied
number
Total inbound messages received inside the filter window. Includes multiple replies from the same contact.
uniqueReplied
number
Distinct contacts that replied at least once inside the window.
repliedPct
number
uniqueReplied / reached. A decimal between 0 and 1 (multiply by 100 for the display %). Returns 0 when reached is 0 — never divides by zero.
positiveReplied
number
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.
positivePct
number
positiveReplied / uniqueReplied. Share of repliers tagged warm. Returns 0 when uniqueReplied is 0.

Error responses

StatusCodeWhen
401UnauthorizedMissing or invalid API key / Clerk session
501AGENCY_NOT_AVAILABLEagencyId filter supplied — feature not yet shipped
500Aggregation failed; check Loki for the analytics.error event

Example: pull last-30-day numbers for one campaign

curl -s -H "Authorization: Bearer tuco_..." \
  "https://app.tuco.ai/api/analytics?campaignId=60d5ec49e3a8a0001f9b1234&dateFrom=$(date -u -v-30d +%Y-%m-%dT00:00:00Z)" \
  | jq '.metrics'

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 structured analytics.served event to Loki:
{
  "event": "analytics.served",
  "workspaceId": "org_…",
  "authMethod": "api_key",
  "filter": { "campaignId": "…", "dateFrom": "…", "dateTo": "…" },
  "metrics": { /* the full block */ },
  "durationMs": 101
}
Failures emit analytics.error with the error message and workspace id.