API Externe
L'API Externe vous permet d'intégrer les données analytiques de Zenovay sur vos sites Web. Utilisez votre clé API pour récupérer les compteurs de visiteurs en direct, les résumés analytiques, les statistiques de pages, et bien plus.
URL de base
Toutes les requêtes vers l'API Externe doivent être adressées à :
https://api.zenovay.com/api/external/v1
Authentification
Les points de terminaison de l'API Externe nécessitent une clé API transmise dans l'en-tête de la requête :
curl -X GET 'https://api.zenovay.com/api/external/v1/websites' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json'Générez votre clé API à Paramètres → Sécurité → Clés API. Chaque clé peut avoir des permissions spécifiques (lecture, écriture, administrateur).
L'API Externe nécessite un plan payant. Les comptes du niveau gratuit reçoivent une réponse 403 API_PAID_PLAN_REQUIRED sur chaque point de terminaison. Passez à un plan Pro, Scale ou Enterprise pour utiliser les clés API programmatiquement.
Points de terminaison des comptes
Récupérer l'utilisation du compte
Récupérez vos statistiques d'utilisation du compte et vos limites :
/api/external/v1/usageRécupérer l'utilisation du compte et les limites
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"
}
}Points de terminaison des sites Web
Lister les sites Web
Récupérez tous les sites Web liés à votre compte :
/api/external/v1/websitesLister tous les sites Web suivis
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
}Récupérer les détails du site Web
Récupérez les détails d'un site Web spécifique :
/api/external/v1/websites/:websiteIdRécupérer les détails du site 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
}
}Points de terminaison analytiques
Récupérer le résumé analytique
Récupérez les données analytiques complètes pour un site Web :
/api/external/v1/analytics/:websiteIdRécupérer l'aperçu analytique
Paramètres de requête :
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
timeRange | string | Non | Plage de temps : today, 7d, 30d, 90d (défaut : 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
}Récupérer les données des visiteurs
Récupérez les informations sur les visiteurs avec filtrage optionnel :
/api/external/v1/analytics/:websiteId/visitorsRécupérer les données des visiteurs
Paramètres de requête :
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
timeRange | string | Non | Plage de temps : today, 7d, 30d, 90d |
limit | integer | Non | Nombre maximum de résultats (défaut : 50, max : 100) |
offset | integer | Non | Décalage de pagination |
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
}Récupérer les analyses de pages
Récupérez les statistiques au niveau des pages :
/api/external/v1/analytics/:websiteId/pagesRécupérer les pages principales
Paramètres de requête :
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
timeRange | string | Non | Plage de temps : today, 7d, 30d, 90d |
limit | integer | Non | Nombre maximum de résultats (défaut : 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
}
]
}Récupérer les données géographiques
Récupérez les données des visiteurs par pays :
/api/external/v1/analytics/:websiteId/countriesRécupérer la répartition géographique
Paramètres de requête :
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
timeRange | string | Non | Plage de temps : 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
}
]
}Récupérer la répartition technologique
Récupérez les statistiques des appareils, des navigateurs et des systèmes d'exploitation :
/api/external/v1/analytics/:websiteId/technologyRécupérer la répartition technologique
Paramètres de requête :
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
timeRange | string | Non | Plage de temps : 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 }
]
}Points de terminaison avancés
Récupérer les pages de la carte thermique
Listez les pages avec des données de carte thermique :
/api/external/v1/heatmaps/:websiteId/pagesLister les pages de la carte thermique
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"
}
]
}Récupérer les rediffusions de session
Listez les sessions enregistrées :
/api/external/v1/replays/:websiteId/sessionsLister les rediffusions de session
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
}Récupérer les groupes d'erreurs
Listez les groupes d'erreurs JavaScript :
/api/external/v1/errors/:websiteId/groupsLister les groupes d'erreurs
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 Stats (parité Plausible, Pro+)
L'API Stats expose trois points de terminaison compatibles avec Plausible pour les requêtes analytiques programmatiques. Utilisez-les pour construire des tableaux de bord personnalisés, intégrer des métriques en direct dans les outils de BI ou migrer depuis Plausible avec un minimum de modifications de code.
Plan requis : Pro, Scale ou Enterprise. Comme pour le reste de l'API Externe, les comptes du niveau gratuit reçoivent une réponse 403 API_PAID_PLAN_REQUIRED.
Points de terminaison
| Point de terminaison | Objectif |
|---|---|
GET /stats/aggregate | Métriques en nombre unique sur une période (totaux, taux, durées). |
GET /stats/timeseries | Série temporelle à buckets (une ligne par jour, heure ou mois). |
GET /stats/breakdown | Métriques groupées (pages principales, pays principaux, navigateurs principaux, …). |
Spec OpenAPI : /api/external/v1/openapi.json (en direct, public, aucune authentification requise pour la spec elle-même).
Paramètres courants
| Param | Obligatoire | Description |
|---|---|---|
site_id | oui | UUID du site Web. Trouvez-le dans l'URL de votre tableau de bord ou via GET /websites. |
period | oui | day, 7d, 30d, month, 6mo, 12mo, ou custom:YYYY-MM-DD,YYYY-MM-DD (max 366 jours). |
date | non | Ancre ISO 8601 pour la période (défaut = aujourd'hui). |
metrics | oui | Séparé par des virgules. Autorisé : visitors, pageviews, visit_duration, bounce_rate, events. |
filters | non | Style Plausible : country==US;browser==Chrome;page!=/admin. Voir Filtres ci-dessous. |
GET /stats/aggregate
Retourne les valeurs en nombre unique pour chaque métrique demandée sur une période.
/api/external/v1/stats/aggregateAgréguer les métriques sur une période
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
Retourne une ligne par bucket sur la période. L'intervalle par défaut est day ; interval=hour nécessite period=day ; interval=month nécessite une period de 6mo, 12mo, month, ou custom.
/api/external/v1/stats/timeseriesSérie temporelle à buckets
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 réponse est dense — les jours sans trafic apparaissent quand même avec visitors: 0. Cela garde les bibliothèques de graphiques heureuses sans remplissage d'écarts côté client.
GET /stats/breakdown
Retourne les métriques groupées par une dimension, triées par visiteurs décroissants.
/api/external/v1/stats/breakdownMétriques groupées (pages principales, pays principaux, …)
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"
}Valeurs property autorisées : event:page, visit:country, visit:browser, visit:device, visit:os, visit:source.
Pagination : limit est 1–1000 (défaut 100) ; page est indexé à partir de 1 (défaut 1).
Filtres
Clauses de filtre de style Plausible, jointes avec ; :
country==US— égal àcountry==US,CA,GB— égal à l'un debrowser!=Safari— non égal à
Clés autorisées : country, browser, device, os, source, utm_source, utm_medium, utm_campaign, page.
Limitation V1 : Lorsque filters est fourni, seule la métrique visitors est calculée ; les autres métriques retournent null avec un drapeau meta.note. Le support complet des filtres sur toutes les métriques sera disponible dans V2.
Exemple 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}`);Codes d'erreur
L'API Stats retourne des codes sur lesquels vous pouvez baser votre UX de dégradation :
| Code | HTTP | Quand |
|---|---|---|
MISSING_SITE_ID | 400 | Le paramètre de requête site_id est obligatoire. |
MISSING_METRICS | 400 | Le paramètre de requête metrics est obligatoire. |
MISSING_PERIOD | 400 | Le paramètre de requête period est obligatoire. |
MISSING_PROPERTY | 400 | /stats/breakdown nécessite property. |
INVALID_METRIC | 400 | L'une des métriques séparées par des virgules ne figure pas dans la liste autorisée. |
INVALID_PROPERTY | 400 | La propriété de répartition n'est pas autorisée. |
INVALID_PERIOD | 400 | La période n'est pas day/7d/30d/month/6mo/12mo/custom:.... |
INVALID_CUSTOM_PERIOD | 400 | Syntaxe custom: mal formée ou date(s) invalide(s). |
PERIOD_TOO_LONG | 400 | Période personnalisée > 366 jours. |
INTERVAL_PERIOD_MISMATCH | 400 | Par exemple interval=hour avec period=7d. |
UNKNOWN_FILTER_KEY | 400 | La clé de filtre ne figure pas dans la liste autorisée. |
EMPTY_FILTER_VALUE | 400 | La clause de filtre n'a pas de valeur. |
FORBIDDEN | 403 | Compte du niveau gratuit (l'API Externe nécessite un plan payant), ou site_id hors de la portée de la clé API. |
NOT_FOUND | 404 | Le site n'existe pas ou est caché pour cette clé. |
| (limite de débit) | 429 | Limite de débit par plan dépassée. L'en-tête Retry-After indique le temps d'attente. |
Migration depuis Plausible
La forme des paramètres est intentionnellement compatible avec Plausible :
| Plausible | Zenovay | Remarques |
|---|---|---|
site_id | site_id | Plausible utilise une chaîne de domaine ; Zenovay utilise un UUID. Mappez domain → site_id une fois via GET /websites. |
period, date | period, date | Même liste autorisée + custom:YYYY-MM-DD,YYYY-MM-DD. |
metrics | metrics | visitors, pageviews, bounce_rate, visit_duration de Plausible mappent tous 1:1. events est approximé en V1 comme pageviews. |
property | property | Même forme : event:page, visit:country, etc. |
filters (string v1) | filters | Même forme key==value;key!=value. Les filtres de tableau JSON v2 arrivent dans Zenovay V2. |
Exemple JavaScript
Intégrez les données analytiques sur votre site Web en utilisant JavaScript :
// Récupérer les données analytiques depuis votre backend
async function fetchAnalytics() {
const response = await fetch('/api/analytics', {
headers: {
'X-API-Key': 'YOUR_API_KEY' // Utilisez un proxy côté serveur pour protéger votre clé
}
});
const data = await response.json();
// Mettez à jour votre interface utilisateur
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) + '%';
}
// Actualiser toutes les 30 secondes
fetchAnalytics();
setInterval(fetchAnalytics, 30000);Note de sécurité : N'exposez jamais votre clé API dans le code côté client. Créez un point de terminaison proxy côté serveur qui appelle l'API Zenovay avec votre clé, puis ayez votre frontend qui appelle votre proxy.
Limites de débit
Limites de débit de l'API Externe par plan :
| Plan | Requêtes/minute (cible) | Limite mensuelle (cap dur) |
|---|---|---|
| Gratuit | N/A (API non disponible) | N/A |
| Pro | 30 | 10 000 |
| Scale | 60 | 100 000 |
| Enterprise | 120 | 1 000 000 |
Comment la limitation de débit est appliquée. Le nombre par minute est une cible, pas un plafond dur. Nous utilisons la limitation de débit d'arête de Cloudflare, qui est par centre de données avec une petite allocation de rafales — un client soutenu peut temporairement voir 1,5–3× le nombre affiché avant d'être limité, surtout lorsque les requêtes se déploient sur les régions. Le cap dur est le quota mensuel, appliqué atomiquement contre votre compte indépendamment du POP d'arête qui traite la requête. Planifiez les charges de travail sensibles à la capacité par rapport au quota mensuel ; traitez la cible par minute comme un signal de lissage.
Réponses d'erreur
| Code de statut | Description |
|---|---|
| 200 | Succès |
| 400 | Mauvaise requête - Paramètres invalides |
| 401 | Non autorisé - Clé API invalide ou manquante |
| 403 | Interdit - Permissions insuffisantes |
| 404 | Non trouvé - Site Web non trouvé |
| 429 | Trop de requêtes - Limite de débit dépassée |
| 500 | Erreur interne du serveur |
{
"error": {
"code": "unauthorized",
"message": "Invalid API key provided"
}
}Prochaines étapes
- Widgets - Intégrer les widgets prêts à l'emploi sur votre site
- Données en temps réel - Accéder aux données des visiteurs en direct sans authentification
- Limites de débit - Comprendre la limitation de débit des API