Tracker d'événements généraliste. Utilisez-le pour tout ce que vous voulez analyser et qui n'est pas une inscription :
Vues de page
Soumissions de formulaires lead
Click-tracking sur landing pages
Événements custom définis par le marchand
Si vos données ont une identité utilisateur significative (une adresse email), utilisez plutôt /v1/signups : chaque adresse email n'y est comptée qu'une fois par boutique. Les numéros de téléphone n'y sont pas dédupliqués. /v1/events est pour le volume élevé sans identité.
Auth
Clé publique + HMAC. Même schéma que /v1/signups. Votre backend signe chaque appel.
⚠️ Attention — Deux choses qui bloquent une clé toute neuve
Barrière pilote. L'API est réservée au pilote en production. Une clé que DZBuild n'a pas inscrite renvoie
403 forbidden"API is in pilot mode; key not enrolled"à chaque appel.Délai d'activation. Une clé publique fraîchement émise n'est pas utilisable à l'instant où elle est créée. Tant qu'elle n'est pas activée pour ces endpoints, vous obtenez
401 unauthorized"Invalid or revoked public key". Contactez le support juste après en avoir créé une pour la faire activer.
Révoquer une clé publique ne l'arrête pas à lui seul : les appels signés continuent d'être acceptés jusqu'à ce que le support la désactive. Prévenez le support chaque fois que vous révoquez une clé publique.
Corps
{
"name": "lead_submitted",
"properties": { "plan": "pro", "country": "DZ", "form": "footer" },
"nonce": "32-hex-single-use"
}
Champ | Type | Requis | Notes |
| string ≤ 64 octets | ✅ | Nom d'événement. |
| object | Valeurs sérialisables JSON. Stockées telles quelles. | |
| 32-hex string | ✅ | Utilisez la même valeur que l'en-tête |
Les requêtes POST doivent aussi porter un en-tête Idempotency-Key (≤ 64 caractères, charset [A-Za-z0-9_-:.]). Sans lui, vous obtenez 400 bad_request et l'événement n'est jamais mis en file. Le nonce de 32 caractères hex que vous générez déjà est une valeur valide — réutilisez-le.
name est stocké avec chaque événement, mais aucun endpoint de l'API ni aucun écran du dashboard ne liste les événements stockés : ce que vous pouvez relire, avec une clé plateforme, c'est le compteur mensuel de GET /v1/usage (usage.event.total). Restez quand même sur un vocabulaire petit et stable, et évitez de générer les noms dynamiquement (ex. viewed_product_42 est mauvais ; utilisez name="viewed_product" avec properties.product_id=42).
Réponse 202
{
"data": { "status": "queued", "kind": "event", "store_id": 13 },
"meta": { "request_id": "...", "api_version": "v1", "edge": true }
}
Même flow que les signups : accepté en ~30 ms, stocké sous environ 5 s.
Dédup
La dédup porte sur le nonce seul, par boutique. Pas de dédup par email.
Un doublon est purement et simplement jeté : rien n'est stocké, aucun compteur de consommation ne bouge, et rien dans l'API ne vous le signale. L'appel a quand même renvoyé 202, parce que la dédup arrive après l'acceptation. Le doublon vous est donc invisible — générez toujours un nonce frais.
Le nonce est gardé en deux temps, avec des durées de vie différentes :
Pendant 1 heure, un nonce réutilisé est rejeté d'emblée avec
401 unauthorized"Nonce reused".Pour toujours ensuite, un nonce recyclé est accepté avec
202puis silencieusement écarté — pas d'erreur, et pas d'événement.
Exemple : tracking de vues de page (Node.js, server-side)
import crypto from 'node:crypto';export async function trackEvent(name, properties = {}) {
const KEY_ID = process.env.DZ_PUBLIC_KEY;
const SECRET = process.env.DZ_SIGNING_SECRET;
const nonce = crypto.randomBytes(16).toString('hex');
const ts = Math.floor(Date.now() / 1000).toString();
const body = JSON.stringify({ name, properties, nonce });
const hash = crypto.createHash('sha256').update(body).digest('hex');
const sig = crypto.createHmac('sha256', SECRET).update(`${KEY_ID}\n${nonce}\n${ts}\n${hash}`).digest('hex'); await fetch('https://api.dzbuild.app/v1/events', {
method: 'POST',
headers: {
'Authorization': `DZ-Public ${KEY_ID}`,
'X-DZ-Timestamp': ts, 'X-DZ-Nonce': nonce, 'X-DZ-Signature': sig,
'Idempotency-Key': nonce, // obligatoire sur chaque POST
'Content-Type': 'application/json',
},
body,
});
}// Dans un middleware Express :
app.use((req, res, next) => {
trackEvent('page_view', { path: req.path, ua: req.get('user-agent') }).catch(() => {});
next();
});
Notez qu'on n'attend pas l'appel depuis le middleware page-view — fire-and-forget pour ne pas bloquer la requête utilisateur. L'API répond en ~30 ms de toute façon, mais ça protège contre les soucis réseau transitoires.
Ce qui compte dans votre quota
Chaque appel /v1/events qui aboutit réellement incrémente usage.event.total ET usage.event.billable. Pas de tier « lectures gratuites puis écritures facturables » ici — les events sont facturables dès la requête 1. Les doublons (même nonce) ne bougent ni l'un ni l'autre, puisqu'ils ne sont jamais stockés.
Si le volume monte, batchez côté vous : stockez dans votre propre queue et tirez un appel /v1/events par event logique en lots de 1 (l'API n'accepte pas de batch). Chaque appel compte dans la limite par minute de la boutique, partagée par toutes ses clés.
Erreurs
Mêmes que /v1/signups. Voir Erreurs. Les trois qui piègent le plus sur cet endpoint :
HTTP | Code / Message | Cause |
400 |
| En-tête manquant |
400 |
| Trop long, ou utilise des caractères hors de cet ensemble (les |
403 |
| Clé non inscrite au pilote |
Quand ne pas utiliser /v1/events
Pour les commandes vitrine — le dashboard du marchand les enregistre déjà, et les dupliquer ici ne fait que gonfler votre compteur d'events. Notez que les commandes vitrine ne déclenchent pas de webhook
order.createden API v1 ; seules les commandes créées viaPOST /v1/ordersle font (voir le Catalogue d'événements).Pour les événements server-internes non liés aux données marchand (CPU, hits cache). Utilisez un vrai APM.
Pour les volumes massifs (plus d'1M d'events/jour). Construisez votre pipeline analytique et exportez seulement les agrégats ici.