API Externa
La API Externa te permite incrustar datos de análisis de Zenovay en sitios web orientados al cliente. Usa tu clave de API para obtener conteos de visitantes en vivo, resúmenes de análisis, estadísticas de páginas y más.
URL Base
Todos las solicitudes a la API Externa deben realizarse a:
https://api.zenovay.com/api/external/v1
Autenticación
Los puntos finales de la API Externa requieren una clave de API pasada en el encabezado de la solicitud:
curl -X GET 'https://api.zenovay.com/api/external/v1/websites' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json'Genera tu clave de API en Settings → Security → API keys. Cada clave puede tener permisos específicos (lectura, escritura, administrador).
La API Externa requiere un plan de pago. Las cuentas de nivel gratuito reciben una respuesta 403 API_PAID_PLAN_REQUIRED en cada punto final. Actualiza a Pro, Scale o Enterprise para usar claves de API de forma programática.
Puntos Finales de Cuenta
Obtener Uso de Cuenta
Recupera las estadísticas de uso y límites de tu cuenta:
/api/external/v1/usageObtener uso de cuenta y límites
curl -X GET 'https://api.zenovay.com/api/external/v1/usage' \
-H 'X-API-Key: YOUR_API_KEY'{
"usage": {
"websites": 5,
"pageviews_this_month": 125000,
"events_this_month": 45000
},
"limits": {
"websites": 10,
"pageviews_per_month": 500000,
"events_per_month": 100000
},
"plan": "pro",
"period": {
"start": "2025-01-01T00:00:00Z",
"end": "2025-01-31T23:59:59Z"
}
}Puntos Finales de Sitios Web
Listar Sitios Web
Obtén todos los sitios web vinculados a tu cuenta:
/api/external/v1/websitesListar todos los sitios web rastreados
curl -X GET 'https://api.zenovay.com/api/external/v1/websites' \
-H 'X-API-Key: YOUR_API_KEY'{
"websites": [
{
"id": "ws_abc123",
"domain": "example.com",
"name": "Example Website",
"tracking_code": "ZV_XXXXXXXXXXX",
"created_at": "2025-01-01T00:00:00Z",
"live_visitors": 42
},
{
"id": "ws_def456",
"domain": "shop.example.com",
"name": "Example Shop",
"tracking_code": "ZV_YYYYYYYYYYY",
"created_at": "2025-01-10T00:00:00Z",
"live_visitors": 18
}
],
"total": 2
}Obtener Detalles del Sitio Web
Recupera los detalles de un sitio web específico:
/api/external/v1/websites/:websiteIdObtener detalles del sitio web
curl -X GET 'https://api.zenovay.com/api/external/v1/websites/ws_abc123' \
-H 'X-API-Key: YOUR_API_KEY'{
"website": {
"id": "ws_abc123",
"domain": "example.com",
"name": "Example Website",
"tracking_code": "ZV_XXXXXXXXXXX",
"created_at": "2025-01-01T00:00:00Z",
"settings": {
"track_outbound_links": true,
"track_downloads": true,
"session_replay": true
}
},
"stats": {
"live_visitors": 42,
"today_pageviews": 1234,
"today_visitors": 567
}
}Puntos Finales de Análisis
Obtener Resumen de Análisis
Recupera datos de análisis completos para un sitio web:
/api/external/v1/analytics/:websiteIdObtener descripción general del análisis
Parámetros de Consulta:
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
timeRange | string | No | Rango de tiempo: today, 7d, 30d, 90d (predeterminado: 7d) |
curl -X GET 'https://api.zenovay.com/api/external/v1/analytics/ws_abc123?timeRange=30d' \
-H 'X-API-Key: YOUR_API_KEY'{
"summary": {
"visitors": 12543,
"pageviews": 45231,
"sessions": 15420,
"bounce_rate": 0.42,
"avg_session_duration": 185,
"pages_per_session": 2.9
},
"period": {
"start": "2024-12-21T00:00:00Z",
"end": "2025-01-20T23:59:59Z"
},
"live_visitors": 42
}Obtener Datos de Visitantes
Recupera información de visitantes con filtrado opcional:
/api/external/v1/analytics/:websiteId/visitorsObtener datos de visitantes
Parámetros de Consulta:
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
timeRange | string | No | Rango de tiempo: today, 7d, 30d, 90d |
limit | integer | No | Resultados máximos (predeterminado: 50, máximo: 100) |
offset | integer | No | Desplazamiento de paginación |
curl -X GET 'https://api.zenovay.com/api/external/v1/analytics/ws_abc123/visitors?timeRange=7d&limit=10' \
-H 'X-API-Key: YOUR_API_KEY'{
"visitors": [
{
"visitor_id": "vis_abc123",
"first_seen": "2025-01-15T10:00:00Z",
"last_seen": "2025-01-20T14:30:00Z",
"total_sessions": 8,
"total_pageviews": 45,
"value_score": 87,
"country": "US",
"device": "desktop"
}
],
"total": 1234,
"limit": 10,
"offset": 0
}Obtener Análisis de Páginas
Recupera estadísticas a nivel de página:
/api/external/v1/analytics/:websiteId/pagesObtener páginas principales
Parámetros de Consulta:
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
timeRange | string | No | Rango de tiempo: today, 7d, 30d, 90d |
limit | integer | No | Resultados máximos (predeterminado: 20) |
curl -X GET 'https://api.zenovay.com/api/external/v1/analytics/ws_abc123/pages?timeRange=7d&limit=10' \
-H 'X-API-Key: YOUR_API_KEY'{
"pages": [
{
"path": "/",
"title": "Home",
"views": 5423,
"unique_visitors": 3241,
"avg_time_on_page": 125,
"bounce_rate": 0.35
},
{
"path": "/pricing",
"title": "Pricing",
"views": 2134,
"unique_visitors": 1876,
"avg_time_on_page": 210,
"bounce_rate": 0.28
}
]
}Obtener Datos Geográficos
Recupera datos de visitantes por país:
/api/external/v1/analytics/:websiteId/countriesObtener desglose geográfico
Parámetros de Consulta:
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
timeRange | string | No | Rango de tiempo: today, 7d, 30d, 90d |
curl -X GET 'https://api.zenovay.com/api/external/v1/analytics/ws_abc123/countries?timeRange=30d' \
-H 'X-API-Key: YOUR_API_KEY'{
"countries": [
{
"code": "US",
"name": "United States",
"visitors": 4521,
"percentage": 36.1
},
{
"code": "GB",
"name": "United Kingdom",
"visitors": 1823,
"percentage": 14.5
},
{
"code": "DE",
"name": "Germany",
"visitors": 1456,
"percentage": 11.6
}
]
}Obtener Desglose Tecnológico
Recupera estadísticas de dispositivos, navegadores y sistemas operativos:
/api/external/v1/analytics/:websiteId/technologyObtener desglose tecnológico
Parámetros de Consulta:
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
timeRange | string | No | Rango de tiempo: today, 7d, 30d, 90d |
curl -X GET 'https://api.zenovay.com/api/external/v1/analytics/ws_abc123/technology?timeRange=7d' \
-H 'X-API-Key: YOUR_API_KEY'{
"devices": [
{ "type": "desktop", "visitors": 7234, "percentage": 57.7 },
{ "type": "mobile", "visitors": 4521, "percentage": 36.1 },
{ "type": "tablet", "visitors": 788, "percentage": 6.3 }
],
"browsers": [
{ "name": "Chrome", "visitors": 6543, "percentage": 52.2 },
{ "name": "Safari", "visitors": 3421, "percentage": 27.3 },
{ "name": "Firefox", "visitors": 1234, "percentage": 9.8 }
],
"operating_systems": [
{ "name": "Windows", "visitors": 4521, "percentage": 36.1 },
{ "name": "macOS", "visitors": 3234, "percentage": 25.8 },
{ "name": "iOS", "visitors": 2876, "percentage": 22.9 }
]
}Puntos Finales Avanzados
Obtener Páginas de Mapa de Calor
Listar páginas con datos de mapa de calor:
/api/external/v1/heatmaps/:websiteId/pagesListar páginas del mapa de calor
curl -X GET 'https://api.zenovay.com/api/external/v1/heatmaps/ws_abc123/pages' \
-H 'X-API-Key: YOUR_API_KEY'{
"pages": [
{
"url": "/",
"title": "Home",
"total_clicks": 12543,
"total_sessions": 4521,
"last_updated": "2025-01-20T14:30:00Z"
},
{
"url": "/pricing",
"title": "Pricing",
"total_clicks": 8765,
"total_sessions": 2134,
"last_updated": "2025-01-20T14:25:00Z"
}
]
}Obtener Reproducciones de Sesión
Listar sesiones grabadas:
/api/external/v1/replays/:websiteId/sessionsListar reproducciones de sesión
curl -X GET 'https://api.zenovay.com/api/external/v1/replays/ws_abc123/sessions' \
-H 'X-API-Key: YOUR_API_KEY'{
"sessions": [
{
"session_id": "sess_abc123",
"visitor_id": "vis_xyz789",
"started_at": "2025-01-20T14:00:00Z",
"duration": 245,
"pages_visited": 5,
"country": "US",
"device": "desktop"
}
],
"total": 156
}Obtener Grupos de Errores
Listar grupos de errores de JavaScript:
/api/external/v1/errors/:websiteId/groupsListar grupos de errores
curl -X GET 'https://api.zenovay.com/api/external/v1/errors/ws_abc123/groups' \
-H 'X-API-Key: YOUR_API_KEY'{
"groups": [
{
"fingerprint": "err_abc123",
"message": "Cannot read property 'length' of undefined",
"type": "TypeError",
"occurrences": 45,
"affected_users": 23,
"first_seen": "2025-01-15T10:00:00Z",
"last_seen": "2025-01-20T14:30:00Z"
}
],
"total": 12
}API de Estadísticas (compatibilidad con Plausible, Pro+)
La API de Estadísticas expone tres puntos finales compatibles con Plausible para consultas de análisis programáticas. Úsalos para crear paneles personalizados, incrustar métricas en vivo en herramientas de BI o migrar desde Plausible con cambios de código mínimos.
Plan requerido: Pro, Scale o Enterprise. Al igual que el resto de la API Externa, las cuentas de nivel gratuito reciben una respuesta 403 API_PAID_PLAN_REQUIRED.
Puntos Finales
| Punto Final | Propósito |
|---|---|
GET /stats/aggregate | Métricas de un único número durante un período (totales, tasas, duraciones). |
GET /stats/timeseries | Series agrupadas por tiempo (una fila por día, hora o mes). |
GET /stats/breakdown | Métricas agrupadas por dimensión (páginas principales, países principales, navegadores principales, …). |
Especificación OpenAPI: /api/external/v1/openapi.json (en vivo, público, no requiere autenticación para la especificación en sí).
Parámetros comunes
| Parámetro | Requerido | Descripción |
|---|---|---|
site_id | sí | UUID del sitio web. Encuéntralo en la URL de tu panel o mediante GET /websites. |
period | sí | day, 7d, 30d, month, 6mo, 12mo, o custom:YYYY-MM-DD,YYYY-MM-DD (máximo 366 días). |
date | no | Ancla ISO 8601 para el período (predeterminado = hoy). |
metrics | sí | Separados por comas. Permitidos: visitors, pageviews, visit_duration, bounce_rate, events. |
filters | no | Estilo Plausible: country==US;browser==Chrome;page!=/admin. Ver Filtros abajo. |
GET /stats/aggregate
Devuelve valores de un solo número para cada métrica solicitada durante un período.
/api/external/v1/stats/aggregateMétricas agregadas durante un período
curl -G 'https://api.zenovay.com/api/external/v1/stats/aggregate' \
-H 'X-API-Key: YOUR_API_KEY' \
--data-urlencode 'site_id=00000000-0000-0000-0000-000000000001' \
--data-urlencode 'period=7d' \
--data-urlencode 'metrics=visitors,pageviews,bounce_rate'{
"success": true,
"data": {
"results": {
"visitors": { "value": 12453 },
"pageviews": { "value": 38219 },
"bounce_rate": { "value": 42.1 }
},
"meta": {
"period": "7d",
"period_start": "2026-05-07T00:00:00.000Z",
"period_end": "2026-05-13T23:59:59.999Z",
"filters_applied": []
}
},
"timestamp": "2026-05-14T08:30:00.000Z"
}GET /stats/timeseries
Devuelve una fila por cubo durante el período. El predeterminado es interval=day; interval=hour requiere period=day; interval=month requiere un period de 6mo, 12mo, month, o custom.
/api/external/v1/stats/timeseriesSeries de métricas agrupadas por tiempo
curl -G 'https://api.zenovay.com/api/external/v1/stats/timeseries' \
-H 'X-API-Key: YOUR_API_KEY' \
--data-urlencode 'site_id=00000000-0000-0000-0000-000000000001' \
--data-urlencode 'period=30d' \
--data-urlencode 'metrics=visitors,pageviews' \
--data-urlencode 'interval=day'{
"success": true,
"data": {
"results": [
{ "date": "2026-04-14", "visitors": 1820, "pageviews": 5640 },
{ "date": "2026-04-15", "visitors": 1933, "pageviews": 5921 }
],
"meta": {
"period": "30d",
"interval": "day",
"period_start": "2026-04-14T00:00:00.000Z",
"period_end": "2026-05-13T23:59:59.999Z",
"filters_applied": []
}
},
"timestamp": "2026-05-14T08:30:00.000Z"
}La respuesta es densa — los días con cero tráfico aún aparecen con visitors: 0. Esto mantiene felices las bibliotecas de gráficos sin necesidad de llenar espacios en el lado del cliente.
GET /stats/breakdown
Devuelve métricas agrupadas por una dimensión, ordenadas por visitantes en orden descendente.
/api/external/v1/stats/breakdownMétricas agrupadas (páginas principales, países principales, …)
curl -G 'https://api.zenovay.com/api/external/v1/stats/breakdown' \
-H 'X-API-Key: YOUR_API_KEY' \
--data-urlencode 'site_id=00000000-0000-0000-0000-000000000001' \
--data-urlencode 'period=7d' \
--data-urlencode 'property=event:page' \
--data-urlencode 'metrics=visitors,pageviews' \
--data-urlencode 'limit=10'{
"success": true,
"data": {
"results": [
{ "page": "/pricing", "visitors": 4421, "pageviews": 4421 },
{ "page": "/blog/launch", "visitors": 2018, "pageviews": 2018 }
],
"meta": {
"period": "7d",
"property": "event:page",
"pagination": { "page": 1, "limit": 10, "total": 47, "has_more": true }
}
},
"timestamp": "2026-05-14T08:30:00.000Z"
}Valores de property permitidos: event:page, visit:country, visit:browser, visit:device, visit:os, visit:source.
Paginación: limit es 1–1000 (predeterminado 100); page es 1-indexado (predeterminado 1).
Filtros
Cláusulas de filtro estilo Plausible, unidas con ;:
country==US— igual acountry==US,CA,GB— igual a uno debrowser!=Safari— no es igual a
Claves permitidas: country, browser, device, os, source, utm_source, utm_medium, utm_campaign, page.
Limitación de V1: Cuando se proporciona filters, solo se calcula la métrica visitors; otras métricas devuelven null con una bandera meta.note. El soporte de filtros completo en todas las métricas llega en V2.
Ejemplo de JavaScript
async function getAggregate(siteId, period = '7d', metrics = ['visitors', 'pageviews']) {
const url = new URL('https://api.zenovay.com/api/external/v1/stats/aggregate');
url.searchParams.set('site_id', siteId);
url.searchParams.set('period', period);
url.searchParams.set('metrics', metrics.join(','));
const res = await fetch(url, {
headers: { 'X-API-Key': process.env.ZENOVAY_API_KEY }
});
if (!res.ok) {
const err = await res.json();
throw new Error(`${err.error.code}: ${err.error.message}`);
}
return res.json();
}
const data = await getAggregate('00000000-0000-0000-0000-000000000001', '7d');
console.log(`Visitors: ${data.data.results.visitors.value}`);Códigos de error
La API de Estadísticas devuelve códigos en los que puedes cambiar para una UX elegante:
| Código | HTTP | Cuándo |
|---|---|---|
MISSING_SITE_ID | 400 | El parámetro de consulta site_id es requerido. |
MISSING_METRICS | 400 | El parámetro de consulta metrics es requerido. |
MISSING_PERIOD | 400 | El parámetro de consulta period es requerido. |
MISSING_PROPERTY | 400 | /stats/breakdown requiere property. |
INVALID_METRIC | 400 | Una de las métricas separadas por comas no está en la lista permitida. |
INVALID_PROPERTY | 400 | La propiedad de desglose no está permitida. |
INVALID_PERIOD | 400 | El período no es day/7d/30d/month/6mo/12mo/custom:.... |
INVALID_CUSTOM_PERIOD | 400 | Sintaxis de custom: con formato incorrecto o fechas inválidas. |
PERIOD_TOO_LONG | 400 | Período personalizado > 366 días. |
INTERVAL_PERIOD_MISMATCH | 400 | Por ejemplo, interval=hour con period=7d. |
UNKNOWN_FILTER_KEY | 400 | La clave de filtro no está en la lista permitida. |
EMPTY_FILTER_VALUE | 400 | La cláusula de filtro no tiene valor. |
FORBIDDEN | 403 | Cuenta de nivel gratuito (la API Externa requiere un plan de pago), o site_id fuera del ámbito de la clave de API. |
NOT_FOUND | 404 | El sitio no existe u está oculto para esta clave. |
| (límite de velocidad) | 429 | Límite de velocidad por nivel excedido. El encabezado Retry-After indica el tiempo de espera. |
Migración desde Plausible
La forma de los parámetros es intencionalmente compatible con Plausible:
| Plausible | Zenovay | Notas |
|---|---|---|
site_id | site_id | Plausible usa una cadena de dominio; Zenovay usa un UUID. Mapea domain → site_id una vez mediante GET /websites. |
period, date | period, date | Misma lista permitida + custom:YYYY-MM-DD,YYYY-MM-DD. |
metrics | metrics | Los visitors, pageviews, bounce_rate, visit_duration de Plausible se asignan 1:1. events se aproxima como pageviews en V1. |
property | property | Misma forma: event:page, visit:country, etc. |
filters (cadena v1) | filters | Misma forma key==value;key!=value. Los filtros de matriz JSON v2 llegan en Zenovay V2. |
Ejemplo de JavaScript
Incrustar datos de análisis en tu sitio web usando JavaScript:
// Obtener datos de análisis desde tu backend
async function fetchAnalytics() {
const response = await fetch('/api/analytics', {
headers: {
'X-API-Key': 'YOUR_API_KEY' // Usa un proxy del lado del servidor para proteger tu clave
}
});
const data = await response.json();
// Actualizar tu interfaz
document.getElementById('live-visitors').textContent = data.live_visitors;
document.getElementById('total-pageviews').textContent = data.summary.pageviews.toLocaleString();
document.getElementById('bounce-rate').textContent = (data.summary.bounce_rate * 100).toFixed(1) + '%';
}
// Actualizar cada 30 segundos
fetchAnalytics();
setInterval(fetchAnalytics, 30000);Nota de Seguridad: Nunca expongas tu clave de API en código del lado del cliente. Crea un punto final proxy del lado del servidor que llame a la API de Zenovay con tu clave, luego haz que tu frontend llame a tu proxy.
Límites de Velocidad
Límites de velocidad de la API Externa por plan:
| Plan | Solicitudes/Minuto (objetivo) | Límite Mensual (límite estricto) |
|---|---|---|
| Gratuito | N/A (API no disponible) | N/A |
| Pro | 30 | 10,000 |
| Scale | 60 | 100,000 |
| Enterprise | 120 | 1,000,000 |
Cómo se aplica la limitación de velocidad. El número por minuto es un objetivo, no un techo duro. Usamos el límite de velocidad de borde de Cloudflare, que es por centro de datos con una pequeña tolerancia de ráfaga — un cliente sostenido puede ver transitoriamente 1.5–3× el número del titular antes de ser limitado, especialmente cuando las solicitudes se distribuyen en regiones. El límite estricto es la cuota mensual, aplicada atómicamente contra tu cuenta independientemente de qué POP de borde sirva la solicitud. Planifica cargas de trabajo sensibles a la capacidad contra la cuota mensual; trata el objetivo por minuto como una señal de suavizado.
Respuestas de Error
| Código de Estado | Descripción |
|---|---|
| 200 | Éxito |
| 400 | Solicitud Incorrecta - Parámetros inválidos |
| 401 | No Autorizado - Clave de API inválida o faltante |
| 403 | Prohibido - Permisos insuficientes |
| 404 | No Encontrado - Sitio web no encontrado |
| 429 | Demasiadas Solicitudes - Límite de velocidad excedido |
| 500 | Error Interno del Servidor |
{
"error": {
"code": "unauthorized",
"message": "Invalid API key provided"
}
}Siguientes Pasos
- Widgets - Incrustar widgets listos para usar en tu sitio
- Datos en Tiempo Real - Acceder a datos de visitantes en vivo sin autenticación
- Límites de Velocidad - Entender la limitación de velocidad de la API