Analytics
The dashboard's reports: conversation volume and resolution, human and AI performance, tool and token usage, and latency.
Download the full API pública projection: openapi.json.
Measure the workspace explains this resource in prose, with runnable examples.
| Method | Path | What it does |
|---|---|---|
GET | /analytics/latency | p50/p95/p99 latency by kind over the time window |
GET | /analytics/overview | Aggregate counts for a date range |
GET | /analytics/resolution-times | Ticket resolution latency stats (avg/p50/p95 + by_resolved_by) |
GET | /analytics/timeseries | Day-bucketed series for one metric |
GET | /analytics/token-usage | Daily token usage by model (prompt + completion + total) |
GET | /analytics/tools | Top tool calls in a date range |
GET | /insights/agents | Human agent performance |
GET | /insights/ai-agents | Per-AI-agent performance breakdown |
GET | /insights/bots | Aggregate AI handling |
GET | /insights/calls | Voice call statistics |
GET | /insights/channels | Volume by channel |
GET | /insights/conversations | Conversation volume and resolution |
GET | /insights/csat | Estimated satisfaction |
POST | /insights/generate-pdf | Render a report as a PDF |
GET | /insights/leads | Lead capture |
GET | /insights/overview/heatmap | Activity heatmap by day and hour |
GET | /insights/overview/live | Current live activity |
GET | /insights/schedules | List report schedules |
GET | /insights/sla | SLA compliance |
GET | /insights/sources | Volume by origin |
GET | /insights/storefront | Storefront performance for a calendar month |
GET | /insights/storefront/card | Storefront summary for the CRM dashboard "Mi sitio" card |
GET | /insights/tags | Volume by tag |
GET | /insights/teams | Volume by team |
GET /analytics/latency
p50/p95/p99 latency by kind over the time window
Operational timing, not business metrics: kind groups spans by name (agent_turn, tool_call, …) and each row carries count plus its p50_ms/p95_ms/p99_ms. since defaults to the last hour; omit kind to get every kind.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
since | query | string | no | date-time |
kind | query | string | no | mín. 1, máx. 60 |
curl https://api.vitrinadev.com/api/v1/analytics/latency \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"kind": "agent_turn",
"p50_ms": 1120,
"p95_ms": 3400,
"p99_ms": 5600,
"count": 940
},
{
"kind": "tool_call",
"p50_ms": 340,
"p95_ms": 980,
"p99_ms": 1800,
"count": 310
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /analytics/overview
Aggregate counts for a date range
Headline counts for from–to: conversations, messages, tickets resolved (split resolved_by_bot/_human/_auto), tool calls, distinct contacts, plus two derived rates — bot_resolution_rate (bot / every resolution) and tool_use_per_message. Optional ai_agent_id narrows every figure to one agent.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
from | query | string | yes | date-time |
to | query | string | yes | date-time |
ai_agent_id | query | uuid | no |
curl https://api.vitrinadev.com/api/v1/analytics/overview \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"conversations_count": 182,
"messages_count": 940,
"tickets_resolved_count": 140,
"resolved_by_bot": 96,
"resolved_by_human": 40,
"resolved_by_auto": 4,
"tool_calls_count": 310,
"distinct_contacts_count": 165,
"bot_resolution_rate": 0.6857,
"tool_use_per_message": 0.3298
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /analytics/resolution-times
Ticket resolution latency stats (avg/p50/p95 + by_resolved_by)
Time-to-resolution over from–to: count/avg_seconds/p50_seconds/p95_seconds overall, then the same four figures again per resolved_by value (bot/human/auto) in by_resolved_by — so "how fast is the bot vs. a human" is one call, not three.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
from | query | string | yes | date-time |
to | query | string | yes | date-time |
curl https://api.vitrinadev.com/api/v1/analytics/resolution-times \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"count": 140,
"avg_seconds": 512.4,
"p50_seconds": 260,
"p95_seconds": 1840,
"by_resolved_by": {
"bot": {
"count": 96,
"avg_seconds": 180.2,
"p50_seconds": 120,
"p95_seconds": 600
},
"human": {
"count": 40,
"avg_seconds": 1120.8,
"p50_seconds": 900,
"p95_seconds": 3200
},
"auto": {
"count": 4,
"avg_seconds": 30.1,
"p50_seconds": 28,
"p95_seconds": 60
}
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /analytics/timeseries
Day-bucketed series for one metric
metric selects one of conversations | messages | tickets_resolved | tool_calls; the response is one point per day in from–to — a day with no activity is a zero-valued point, not an absent one.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
from | query | string | yes | date-time |
to | query | string | yes | date-time |
metric | query | conversations \ | messages \ | tickets_resolved \ |
curl https://api.vitrinadev.com/api/v1/analytics/timeseries \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"bucket": "2026-09-20",
"value": 24
},
{
"bucket": "2026-09-21",
"value": 31
},
{
"bucket": "2026-09-22",
"value": 18
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /analytics/token-usage
Daily token usage by model (prompt + completion + total)
One row per (day, model) over from–to: prompt_tokens, completion_tokens, total_tokens. model is the OpenRouter model id the platform actually ran — every model this workspace’s agents run is flash-tier; the platform never routes a turn to a "pro"/reasoning-max model.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
from | query | string | yes | date-time |
to | query | string | yes | date-time |
curl https://api.vitrinadev.com/api/v1/analytics/token-usage \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"bucket": "2026-09-22",
"model": "xiaomi/mimo-v2.6-flash",
"prompt_tokens": 812000,
"completion_tokens": 96000,
"total_tokens": 908000
},
{
"bucket": "2026-09-22",
"model": "google/gemini-2.5-flash",
"prompt_tokens": 220000,
"completion_tokens": 31000,
"total_tokens": 251000
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /analytics/tools
Top tool calls in a date range
The most-called tools over from–to, ranked by call_count (default top 20, max 200 via limit). function_name is null for a call logged against a tool that has since been deleted.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
from | query | string | yes | date-time |
to | query | string | yes | date-time |
limit | query | integer | no | ≥ 1, ≤ 200, por defecto 20 |
curl https://api.vitrinadev.com/api/v1/analytics/tools \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"function_id": "b6b6b6b6-1000-4000-8000-000000000001",
"function_name": "search_vehicle_stock",
"call_count": 214
},
{
"function_id": "b6b6b6b6-1000-4000-8000-000000000002",
"function_name": "book_appointment",
"call_count": 58
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/agents
Human agent performance
Per-human-agent throughput and response times. /insights/ai-agents is the machine-side counterpart; the two are not comparable row for row, because a human is assigned a conversation and an AI agent runs turns within one.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/agents \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"user_id": "11111111-0000-4000-8000-000000000001",
"name": "Carolina Muñoz",
"email": "[email protected]",
"conversations": 8,
"replies": 5,
"avg_first_response_seconds": 733.76,
"avg_response_seconds": 28197.49,
"avg_resolution_seconds": 9891.67,
"avg_customer_wait_seconds": 733.76,
"resolutions": 4
}
],
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/ai-agents
Per-AI-agent performance breakdown
One row per ai_agent. /insights/bots answers the same question in aggregate — use that for a single headline number and this to find which agent moved it.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/ai-agents \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"ai_agent_id": "a3a3a3a3-0000-4000-8000-000000000001",
"name": "Asistente de ventas",
"status": "active",
"is_default": true,
"conversations": 12,
"responses": 30,
"avg_response_seconds": 4.2,
"automated_conversations": 8,
"handoffs": 2,
"resolutions": 4,
"tool_calls": 21,
"cost_usd": 0.0508,
"tokens": 322522,
"avg_gen_latency_ms": 7938,
"handoffs_requested": 2,
"handoffs_answered": 2
}
],
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/bots
Aggregate AI handling
AI handling across the workspace as one figure, not split by agent. The aggregate counterpart to /insights/ai-agents.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/bots \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"conversations": 12,
"automated_conversations": 8,
"total_conversations": 18,
"engaged_conversations": 11,
"deflection_rate": 0.44,
"total_responses": 30,
"avg_response_seconds": 4.2,
"resolutions": 4,
"handoff_rate": 0.17,
"resolved_by_bot": 3,
"resolved_by_human": 1,
"resolved_by_auto": 0,
"cost_usd": 0.0508,
"cost_per_conversation": 0.0042,
"tokens": 322522,
"avg_gen_latency_ms": 7938,
"tool_calls": 21,
"resolutions_series": [
{
"bucket": "2026-09-22",
"value": 3
}
],
"handoff_series": [
{
"bucket": "2026-09-22",
"value": 1
}
],
"cost_series": [
{
"bucket": "2026-09-22",
"value": 0.0064
}
]
},
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/calls
Voice call statistics
Voice-channel call stats for the window. Served by the voice insights service rather than the general reporting one, so its shape does not match the other reports.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/calls \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"range": {
"from": "2026-09-15T16:38:51.540Z",
"to": "2026-09-22T16:38:51.540Z"
},
"calls": {
"total": 6,
"answered": 5,
"avg_duration_s": 142,
"by_outcome": {
"completed": 5,
"no_answer": 1
},
"by_direction": {
"inbound": 4,
"outbound": 2
},
"by_amd": {}
},
"latency": {
"voice_to_voice": 820,
"voice_llm_turn": 410,
"voice_llm_first_token": 190,
"tool_execution": 260
}
},
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/channels
Volume by channel
Grouped by messaging channel (WhatsApp, Instagram, email, voice, …), so a channel with no traffic in the window is simply absent rather than present with a zero.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/channels \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"key": "00000000-0000-4000-8000-000000005001",
"label": "WhatsApp · Acme",
"conversations": 5,
"avg_first_response_seconds": 450.43,
"avg_resolution_seconds": 101.4,
"avg_customer_wait_seconds": 450.43,
"resolutions": 1
},
{
"key": "__none__",
"label": "Directo / sin canal",
"conversations": 4,
"avg_first_response_seconds": 0,
"avg_resolution_seconds": 0,
"avg_customer_wait_seconds": 0,
"resolutions": 0
}
],
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/conversations
Conversation volume and resolution
Volume, resolution and handling time over the window — the top-level view the other reports break down.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/conversations \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"conversations": {
"total": 18,
"delta_pct": 17,
"series": [
{
"bucket": "2026-09-21",
"value": 0
},
{
"bucket": "2026-09-22",
"value": 18
}
]
},
"messages_in": {
"total": 11,
"delta_pct": null,
"series": [
{
"bucket": "2026-09-22",
"value": 10
}
]
},
"messages_out": {
"total": 25,
"delta_pct": null,
"series": [
{
"bucket": "2026-09-22",
"value": 25
}
]
},
"first_response_seconds": {
"avg": 728.65,
"delta_pct": null,
"series": [
{
"bucket": "2026-09-22",
"value": 728.65
}
]
},
"first_response_p50_seconds": 388.36,
"first_response_p90_seconds": 1411.41,
"resolution_seconds": {
"avg": 9891.67,
"delta_pct": -91.3,
"series": [
{
"bucket": "2026-09-22",
"value": 9891.67
}
]
},
"resolutions": {
"total": 5,
"delta_pct": -16.7,
"series": [
{
"bucket": "2026-09-22",
"value": 4
}
]
},
"customer_wait_seconds": {
"avg": 728.65,
"delta_pct": null,
"series": [
{
"bucket": "2026-09-22",
"value": 728.65
}
]
},
"facturables": 4,
"solo_humano": 14
},
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/csat
Estimated satisfaction
CSAT is AI-ESTIMATED from the conversation, not collected from a survey — no customer was asked to rate anything. Read it as a model judgement about tone and outcome, which is why it exists for every conversation rather than the small fraction that would answer a survey.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/csat \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"total_responses": 9,
"satisfaction_score": 0.82,
"response_rate": 0.5,
"positive": 7,
"neutral": 1,
"negative": 1,
"recommend_rate": 0.78,
"avg_confidence": 0.9,
"review_requests_sent": 18,
"resolved_tickets": 5,
"distribution": {
"positive": 7,
"neutral": 1,
"negative": 1
},
"resolution_quality": {
"good": 8,
"poor": 1
},
"agent_performance": {},
"recent": []
},
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /insights/generate-pdf
Render a report as a PDF
The one endpoint on the tenant API that does not answer the \{ data \} envelope. It replies with raw application/pdf bytes and a Content-Disposition: attachment header, so a client that pipes every response through the usual JSON parse will fail here. On an error it reverts to the JSON error envelope, which means the response content-type is what tells the two apart.
Generation is SYNCHRONOUS: it queries the report, runs an LLM pass to write the narrative, then renders. The connection is held for all of that, there is no job id, and nothing is persisted — a client or proxy timeout loses the document with no way to retrieve it other than asking again. Treat a wide range as a slow request.
The LLM pass degrades rather than fails: if the narrative cannot be generated you still get a 200 and a complete PDF, with a Spanish note in place of the executive summary and every raw figure intact. So a successful response does not by itself mean the analysis is there.
range.preset is not a range selector — from/to alone decide the data. It is the window’s NAME: printed as the cover subtitle and passed into the summariser’s prompt, so a preset that disagrees with from/to mislabels the cover and misleads the narrative while the figures stay correct. Defaults to custom. Needs only analytics:read.
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
report_type | overview \ | conversations \ | agents \ |
range | object | yes |
curl -X POST https://api.vitrinadev.com/api/v1/insights/generate-pdf \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"report": "conversations",
"window": {
"preset": "7d"
},
"range": {
"preset": "7d"
}
}'Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/leads
Lead capture
Leads created over the window and where they came from.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/leads \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"open": 16,
"won": 2,
"lost": 1,
"unqualified": 0,
"total_value_open": 19407775,
"total_value_won": 4500000,
"total_value_open_by_currency": {
"CLP": 19399000
},
"total_value_won_by_currency": {
"CLP": 4500000
},
"is_mixed_currency": false,
"is_mixed_currency_open": false,
"win_rate": 0.67,
"avg_cycle_seconds": 432000,
"created_series": [
{
"bucket": "2026-09-22",
"value": 6
}
],
"won_series": [
{
"bucket": "2026-09-22",
"value": 1
}
],
"revenue_series": [
{
"bucket": "2026-09-22",
"value": 4500000,
"value_by_currency": {
"CLP": 4500000
},
"is_mixed_currency": false
}
],
"funnel": [
{
"stage_id": "55555555-0000-4000-8000-000000000001",
"stage_name": "Nuevo",
"position": 0,
"open_count": 9,
"total_value": 19401030,
"total_value_by_currency": {
"CLP": 19399000
},
"is_mixed_currency": false,
"median_time_in_stage_hours": 6.5
}
]
},
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/overview/heatmap
Activity heatmap by day and hour
The only report that accepts tz. Pass the viewer’s IANA zone (America/Santiago) and the day/hour buckets follow their wall clock; omit it and the grid is UTC, which shifts a Chilean workspace’s busy hours by three or four columns depending on DST. The name is validated by Postgres, so an unknown zone is a 500 rather than a 400.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no | |
tz | query | string | no | máx. 64, patrón ^[A-Za-z0-9_+\-/]+$ |
curl https://api.vitrinadev.com/api/v1/insights/overview/heatmap \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"buckets": [
{
"day": 1,
"hour": 10,
"conversations": 3
},
{
"day": 1,
"hour": 11,
"conversations": 5
}
]
},
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/overview/live
Current live activity
A now-snapshot: open conversations, who is waiting, what is in flight. The one report that takes NO range — it describes the present, so from/to would mean nothing and are not accepted.
curl https://api.vitrinadev.com/api/v1/insights/overview/live \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"open": 14,
"unattended": 0,
"unassigned": 1,
"pending": 0,
"agents_online": 1,
"agents_busy": 0,
"agents_offline": 4
},
"meta": {
"window": {
"kind": "instant",
"at": "2026-09-22T16:38:43.071Z",
"label": "ahora"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/schedules
List report schedules
The standing subscriptions that mail a rendered report out on a cadence. Unpaginated, and with no meta.total — this list is small by construction.
curl https://api.vitrinadev.com/api/v1/insights/schedules \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"id": "cccccccc-2000-4000-8000-000000000001",
"report_type": "conversations",
"range_preset": "7d",
"cadence": "weekly",
"recipients": [
"[email protected]"
],
"next_run_at": "2026-09-29T09:00:00.000Z",
"enabled": true
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/sla
SLA compliance
Breach and compliance counts against the workspace SLA policies. A window with no policy configured reports nothing to comply with, not full compliance.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/sla \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"has_policies": true,
"policy_count": 2,
"target_first_response_minutes": 15,
"target_resolution_minutes": 480,
"tracked": 18,
"breached": 2,
"hits": 16,
"hit_rate": 0.89,
"first_response": {
"evaluated": 18,
"breached": 1,
"hit_rate": 0.94
},
"resolution": {
"evaluated": 5,
"breached": 1,
"hit_rate": 0.8
},
"by_policy": [
{
"policy_id": "cccccccc-1000-4000-8000-000000000001",
"name": "SLA estándar",
"hit_rate": 0.89
}
],
"breaches": []
},
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/sources
Volume by origin
The same row shape as /insights/channels, grouped by where the conversation CAME FROM (mercadolibre, yapo, chileautos, ai_agent, website, …) rather than which messaging account it rode in on. The two are not interchangeable: marketplace leads all arrive on the same WhatsApp number, so /insights/channels collapses every paid origin into one row. Unlike channels there is no catalogue to zero-fill from, so an origin with no traffic is absent rather than present with a zero; __none__ is the no-origin bucket.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/sources \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"key": "__none__",
"label": "Directo / sin origen",
"conversations": 14,
"avg_first_response_seconds": 728.65,
"avg_resolution_seconds": 9891.67,
"avg_customer_wait_seconds": 728.65,
"resolutions": 4
},
{
"key": "website",
"label": "Sitio web",
"conversations": 4,
"avg_first_response_seconds": 0,
"avg_resolution_seconds": 0,
"avg_customer_wait_seconds": 0,
"resolutions": 0
}
],
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/storefront
Storefront performance for a calendar month
The one ranged report that does NOT take the ?window= vocabulary: it is monthly by construction, so it takes ?month=YYYY-MM and nothing else, defaulting to the month in progress. The month is the DEALERSHIP’s (America/Santiago), and the resolved bounds come back in meta.window.
⚠ analytics:read buys the numbers, not the people. The recent_leads rows carry contact_name/contact_phone, which are the contact’s own — without contacts:read both keys are DELETED from each row (absent, never null: what is missing is the reader, not the data). The MCP twin applies the same projection, so neither surface is the loose one.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
month | query | string | no | patrón `^\d4-(0[1-9]\ |
curl https://api.vitrinadev.com/api/v1/insights/storefront \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"storefront_visits": 240,
"storefront_leads": 4,
"conversion": {
"value": 0.017,
"numerator": {
"name": "storefront_leads",
"count": 4
},
"denominator": {
"name": "storefront_visits",
"count": 240
}
},
"visits_series": [
{
"bucket": "2026-09-22",
"value": 12
}
],
"leads_series": [
{
"bucket": "2026-09-22",
"value": 1
}
],
"top_vehicles": [
{
"vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
"views": 30
}
],
"recent_leads": [
{
"lead_id": "99999999-0000-4000-8000-000000000001",
"created_at": "2026-09-22T12:40:29.275Z",
"vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
"vehicle_label": "Peugeot 2008 2024"
}
],
"window": {
"kind": "calendar_month",
"month": "2026-09",
"from": "2026-09-01T04:00:00.000Z",
"to": "2026-10-01T03:00:00.000Z",
"tz": "America/Santiago",
"label": "septiembre 2026",
"as_of": "2026-09-22T16:38:51.570Z"
}
},
"meta": {
"window": {
"kind": "calendar_month",
"month": "2026-09",
"from": "2026-09-01T04:00:00.000Z",
"to": "2026-10-01T03:00:00.000Z",
"tz": "America/Santiago",
"label": "septiembre 2026",
"as_of": "2026-09-22T16:38:51.570Z"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/storefront/card
Storefront summary for the CRM dashboard "Mi sitio" card
A compact, ROLLING sibling of GET /insights/storefront (ticket 86e2rwqxw): a FIXED trailing 30-day period, plus the immediately-preceding 30-day period for a period-over-period comparison. Takes no query parameters — the window is not caller-chosen, unlike the calendar-month report. Returns visits/leads as \{current, previous\} raw counts (never a pre-computed delta), a zero-filled visits_series sparkline, and the top 5 (not 10) most-viewed vehicles. Carries NO personal data — no recent_leads, no contact fields — so unlike the full report this endpoint needs no contacts:read branch. Site status (published/draft, the dealer’s own domain) is deliberately not here: GET /tenant/sitio and GET /tenant/settings already serve it.
curl https://api.vitrinadev.com/api/v1/insights/storefront/card \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"period": {
"from": "2026-08-23T16:38:51.606Z",
"to": "2026-09-22T16:38:51.606Z",
"label": "últimos 30d"
},
"previous_period": {
"from": "2026-07-24T16:38:51.606Z",
"to": "2026-08-23T16:38:51.606Z",
"label": "período anterior"
},
"visits": {
"current": 240,
"previous": 180
},
"leads": {
"current": 4,
"previous": 2
},
"visits_series": [
{
"bucket": "2026-09-22",
"value": 12
}
],
"top_vehicles": [
{
"vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
"views": 30
}
],
"as_of": "2026-09-22T16:38:51.606Z"
},
"meta": {
"period": {
"from": "2026-08-23T16:38:51.606Z",
"to": "2026-09-22T16:38:51.606Z",
"label": "últimos 30d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/tags
Volume by tag
Conversation counts grouped by the tags applied to them.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/tags \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"key": "__none__",
"label": "Sin etiqueta",
"conversations": 17,
"avg_first_response_seconds": 728.65,
"avg_resolution_seconds": 9891.67,
"avg_customer_wait_seconds": 728.65,
"resolutions": 4
},
{
"key": "e1e1e1e1-9000-4000-8000-000000000001",
"label": "garantia",
"conversations": 1,
"avg_first_response_seconds": 0,
"avg_resolution_seconds": 0,
"avg_customer_wait_seconds": 0,
"resolutions": 0
}
],
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/teams
Volume by team
Conversation counts grouped by the team they were routed to.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
window | query | 24h \ | 7d \ | 30d \ |
month | query | string | no | patrón `^\d4-(0[1-9]\ |
year | query | string | no | patrón ^\d{4}$ |
from | query | string | no | |
to | query | string | no |
curl https://api.vitrinadev.com/api/v1/insights/teams \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"key": "__none__",
"label": "Sin equipo",
"conversations": 18,
"avg_first_response_seconds": 728.65,
"avg_resolution_seconds": 9891.67,
"avg_customer_wait_seconds": 728.65,
"resolutions": 4
},
{
"key": "cccccccc-0000-4000-8000-000000000001",
"label": "Marketing",
"conversations": 0,
"avg_first_response_seconds": 0,
"avg_resolution_seconds": 0,
"avg_customer_wait_seconds": 0,
"resolutions": 0
}
],
"meta": {
"window": {
"kind": "rolling",
"preset": "7d",
"hours": 168,
"from": "2026-09-15T16:38:51.000Z",
"to": "2026-09-22T16:38:51.000Z",
"label": "últimos 7d"
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
Ads
Spend, ROAS and attributed revenue by campaign, creative ranking and attribution health, plus the single tag: the snippet you paste (or its Google Tag Manager installer) and whether it is already sending visits. Reads from Atribu with the workspace's delegated key.
API keys
Mint, list and revoke the credentials every other call is made with.