Analytics
Los reportes del panel: volumen y resolución de conversaciones, desempeño humano y de IA, uso de herramientas y de tokens, y latencia.
Descarga la proyección completa de la API pública: openapi.json.
Medir el workspace explica este recurso en prosa, con ejemplos ejecutables.
| Método | Ruta | Qué hace |
|---|---|---|
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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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
}
]
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
from | query | string | sí | date-time |
to | query | string | sí | date-time |
ai_agent_id | query | uuid | no |
curl https://api.vitrinadev.com/api/v1/analytics/overview \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (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
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
from | query | string | sí | date-time |
to | query | string | sí | date-time |
curl https://api.vitrinadev.com/api/v1/analytics/resolution-times \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (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
}
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
from | query | string | sí | date-time |
to | query | string | sí | date-time |
metric | query | conversations \ | messages \ | tickets_resolved \ |
curl https://api.vitrinadev.com/api/v1/analytics/timeseries \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"bucket": "2026-09-20",
"value": 24
},
{
"bucket": "2026-09-21",
"value": 31
},
{
"bucket": "2026-09-22",
"value": 18
}
]
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
from | query | string | sí | date-time |
to | query | string | sí | date-time |
curl https://api.vitrinadev.com/api/v1/analytics/token-usage \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (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
}
]
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
from | query | string | sí | date-time |
to | query | string | sí | 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"Ejemplo de respuesta (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
}
]
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
report_type | overview \ | conversations \ | agents \ |
range | object | sí |
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"
}
}'Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/leads
Lead capture
Leads created over the window and where they came from.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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"Ejemplo de respuesta (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"
}
}
}Responde: 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"Ejemplo de respuesta (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
}
]
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
month | query | string | no | patrón `^\d4-(0[1-9]\ |
curl https://api.vitrinadev.com/api/v1/insights/storefront \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (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"
}
}
}Responde: 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"Ejemplo de respuesta (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"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/tags
Volume by tag
Conversation counts grouped by the tags applied to them.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /insights/teams
Volume by team
Conversation counts grouped by the team they were routed to.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
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"Ejemplo de respuesta (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"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
Publicidad
Gasto, ROAS e ingresos atribuidos por campaña, el ranking de creativos y la salud de la atribución, más el tag único: el fragmento que pegas (o su instalador de Google Tag Manager) y si ya está enviando visitas. Lecturas de Atribu con la clave delegada del workspace.
API keys
Emitir, listar y revocar las credenciales con las que se llama a todo lo demás.