Webhook
Principes de fonctionnement
Chaque balise Neyos OTRAC transmet ses données en temps réel vers votre serveur via des requêtes HTTP POST au format JSON. Chaque payload contient soit des données de télémétrie (points GPS, événements système), soit une mise à jour de l'état du tracker.
Flux de données
Serveur Neyos
Webhook & API
Plateforme Neyos
Votre application
Points clés
- Protocole : HTTPS POST uniquement
- Format : JSON (
Content-Type: application/json) - Authentification : URL unique par client
- Réponse attendue : HTTP 200 avec body
{"message": "ok"} - Temps de réponse recommandé : < 5 secondes
Configuration pas à pas
La configuration des webhooks se fait directement depuis l'interface Neyos (onglet Webhooks). Voici la procédure type :
- Connectez-vous à la plateforme Neyos.
- Accédez à l'onglet Webhook
- Cliquez sur .
- Indiquez l'URL cible de votre serveur, et cliquez sur
Activé - Votre webhook est maintenant en marche, les données sont redirigées vers le endpoint enregistré.
Votre endpoint doit
- Accepter les requêtes POST en HTTPS
- Parser le body JSON
- Répondre HTTP 200 avec le body
{"message": "ok"} - Traiter la requête en moins de 5 secondes
Types de webhooks
Chaque payload contient un champ type à la racine qui identifie le type de webhook.
| Type | Description | Fréquence |
|---|---|---|
message.created | Nouveau message de télémétrie (points GPS + événements) | À chaque envoi par la balise |
tracker.updated | Mise à jour de l'état du tracker | Après traitement d'un message.created |
message.created est généralement suivi d'un tracker.updated quelques millisecondes plus tard, reflétant le nouvel état du tracker après intégration des données reçues.message.created — Données de télémétrie
Ce webhook est le principal. Il contient les données collectées par la balise : positions GPS, événements système, et le contexte réseau/tracker au moment de la réception.
Structure racine
{
"type": "message.created",
"data": {
"id": "msg_XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"type": "datas",
"network": "gsm",
"mcc": 208,
"mnc": 10,
"rsrq": 61,
"battery": 70,
"temperature": 0,
"receivedAt": "2026-02-25T14:32:50.358+00:00",
"elements": [ ... ],
"networkOperator": { ... },
"tracker": { ... }
}
}
Champs data :
| Champ | Type | Description | Exemple |
|---|---|---|---|
id | string | Identifiant unique du message | msg_3AAKX57Y9c0KK5YuMxlAQhANjaS |
type | string | Toujours "datas" | datas |
network | string | Type de réseau utilisé | gsm |
mcc | integer | Mobile Country Code (pays) | 208 (France) |
mnc | integer | Mobile Network Code (opérateur) | 10 (SFR) |
rsrq | integer | Qualité du signal (30 faible → 70 excellent) | 61 |
battery | integer | Niveau de batterie (0-100 %) | 70 |
temperature | integer | Température interne en °C | 0 |
receivedAt | string | Date/heure de réception plateforme (ISO 8601) | 2026-02-25T14:32:50.358+00:00 |
elements | array | Tableau de points et événements | voir sections ci-dessous |
networkOperator | object | Détails opérateur réseau | voir section dédiée |
tracker | object | État complet du tracker | voir section dédiée |
Elements : Point GPS
Un élément point représente une position GPS horodatée capturée par la balise à un instant donné.
{
"id": "elm_3A6em1aqCXEqx7mmrIowhAVaQq2",
"type": "point",
"datas": {
"type": "point",
"timestamp": 1771917582000,
"tag": 9216,
"source": "GNSS",
"precision": "MS",
"latitude": 45.4570617,
"longitude": 4.4021235,
"accuracy": 18,
"satellites": 11,
"fix": 4,
"speed": "40.8",
"temperature": 19,
"heading": 230,
"altitude": 448,
"tags": {
"type": "POINT",
"status": "NEW",
"location": "RAM",
"priority": "NORMAL",
"gps": "DISPO",
"fix": "3D",
"buffer": "LIVE"
}
},
"messageId": "msg_3A6em6HE5ts0Ls1Vzq863IuD62x",
"trackerId": "tra_35pBms5aEyRZnLVAG7u7ZdmcCTC",
"createdAt": "2026-02-24T07:20:02.554+00:00"
}
Champs racine de l'élément point :
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant unique de l'élément |
type | string | Toujours "point" |
messageId | string | ID du message parent |
trackerId | string | ID du tracker émetteur |
createdAt | string | Date de création côté plateforme (ISO 8601) |
Champs datas d'un point :
| Champ | Type | Unité | Description |
|---|---|---|---|
type | string | - | Toujours "point" |
timestamp | integer | ms | Timestamp Unix en millisecondes |
tag | integer | - | Encodage bitmask des métadonnées |
source | string | - | Source de la position ("GNSS") |
precision | string | - | Précision temporelle (voir référence) |
latitude | number | degrés | Latitude WGS84. 0 si pas de fix |
longitude | number | degrés | Longitude WGS84. 0 si pas de fix |
accuracy | integer | m | Précision horizontale estimée. 0 si pas de fix |
satellites | integer | - | Nombre de satellites utilisés |
fix | integer | - | Type de fix GPS (voir référence) |
speed | string | km/h | Vitesse au sol. "0.0" si immobile ou pas de fix |
temperature | integer | °C | Température au moment de la capture |
heading | integer | degrés | Direction (0-360°, 0 = Nord) |
altitude | integer | m | Altitude au-dessus du niveau de la mer |
tags | object | - | Version lisible du bitmask tag (voir référence) |
Elements : Événement système
Un élément event représente un événement système survenu sur la balise.
{
"id": "elm_3AAKX0HlH7kOta90A7Ef5Mkwlq6",
"type": "event",
"datas": {
"type": "event",
"eventType": "power_off",
"code": 2,
"id": 9,
"timestamp": 1772030960172,
"precision": "MINUTE",
"source": "GNSS"
},
"messageId": "msg_3AAKX57Y9c0KK5YuMxlAQhANjaS",
"trackerId": "tra_35pBms5aEyRZnLVAG7u7ZdmcCTC",
"createdAt": "2026-02-25T14:32:50.363+00:00"
}
Champs communs (toujours présents) :
| Champ | Type | Description |
|---|---|---|
type | string | Toujours "event" |
eventType | string | Type de l'événement (voir référence) |
code | integer | Code numérique unique de l'événement |
id | integer | Numéro de séquence sur la balise |
timestamp | integer | Timestamp Unix en millisecondes |
precision | string | Précision temporelle (voir référence) |
source | string | Source de synchronisation temporelle |
Champs optionnels (selon le type d'événement) :
| Champ | Type | Présent pour | Description |
|---|---|---|---|
data | object | événements avec payload (shock_detection, battery_charging_*, sleep_scheduled, geofence_*, command_applied, config…) | Payload structuré spécifique au type d'événement (voir section dédiée) |
pt | object | événements émis avec un contexte GPS (button_1/2/3, sos, user_ok) | Position GPS au moment de l'événement (voir section dédiée) |
latitude, longitude, accuracy, satellites, fix | mixte | mêmes événements que pt | Duplication legacy des champs pt, aplatie à la racine de datas |
pt plutôt que les champs legacy aplatis. Les deux portent toujours les mêmes valeurs.Payloads data par événement
L'objet data est uniquement présent pour les événements qui transportent un payload spécifique. Sa structure dépend du eventType.
Événement Choc
{
"data": {
"norm": 6869,
"x": -3997,
"y": 3995,
"z": 3905,
"axis": "X"
}
}
| Champ | Type | Unité | Description |
|---|---|---|---|
norm | integer | mg | Magnitude crête de l'accélération (sqrt(x²+y²+z²)) |
x | integer | mg | Crête sur l'axe X (signée) |
y | integer | mg | Crête sur l'axe Y (signée) |
z | integer | mg | Crête sur l'axe Z (signée) |
axis | string | - | Axe portant la plus grande crête ("X", "Y" ou "Z") |
Événement Début de charge · Fin de charge · Batterie chargée · Batterie faible · Erreur batterie
{
"data": {
"soc": 4.2,
"voltage": 4173,
"current": 777.8,
"temp": 29
}
}
| Champ | Type | Unité | Description |
|---|---|---|---|
soc | number | % | État de charge (0.0 - 100.0) |
voltage | integer | mV | Tension batterie |
current | number | mA | Courant de charge/décharge (positif = charge, négatif = décharge) |
temp | integer | °C | Température batterie |
Événement Veille programmée
{
"data": {
"wake_at": 1776947580
}
}
| Champ | Type | Unité | Description |
|---|---|---|---|
wake_at | integer | secondes | Timestamp Unix UTC cible auquel la balise est programmée pour se réveiller. La balise entre en veille profonde juste après cet événement. |
Événement Entrée de zone · Sortie de zone · Excès de vitesse en zone
{
"data": {
"slot": 2,
"name": "warehouse",
"speed": 78
}
}
| Champ | Type | Unité | Description |
|---|---|---|---|
slot | integer | - | Index du slot de zone (0..N) |
name | string | - | Nom de la zone configuré sur la plateforme |
speed | integer | km/h | (overspeed uniquement) Vitesse au moment de la détection |
Événement Commande appliquée
{
"data": {
"results": [
{ "cmd_id": 1, "status": 0 },
{ "cmd_id": 2, "status": 4 }
]
}
}
Chaque entrée contient cmd_id (index de commande FOTA) et status (code retour NSE 0-5 : 0 = échec, 1 = ok, 2 = paramètre inconnu, 3 = valeur invalide, 4 = hors plage, 5 = mauvais format).
Événement Configuration
{
"data": "gnss --rate=30000\nsleep schedule --wake_at=0\n..."
}
data est ici une chaîne texte (CBOR tstr) contenant la configuration NSE courante sous forme de commandes shell. Peut être réparti sur plusieurs événements config si la configuration est longue.
Objet pt (contexte position)
Pour les événements liés aux boutons (et tout événement configuré pour embarquer la position GPS courante), un objet pt est inclus en plus des champs legacy aplatis :
{
"pt": {
"lat": 49.0088218,
"lon": 2.2842179,
"acc": 6,
"sats": 20,
"fix": 4
},
"latitude": 49.0088218,
"longitude": 2.2842179,
"accuracy": 6,
"satellites": 20,
"fix": 4
}
| Champ | Type | Unité | Description |
|---|---|---|---|
lat | number | degrés | Latitude WGS84 (0 si pas de fix) |
lon | number | degrés | Longitude WGS84 (0 si pas de fix) |
acc | integer | m | Précision horizontale estimée (peut valoir 499 en valeur de repli sans fix) |
sats | integer | - | Nombre de satellites utilisés |
fix | integer | - | Type de fix GPS (voir référence) |
0 (et acc peut valoir 499 comme sentinelle). L'événement est tout de même livré : seuls timestamp et eventType sont alors fiables.Opérateur réseau
L'objet networkOperator fournit les informations sur l'opérateur réseau utilisé par la balise au moment de l'envoi.
{
"networkOperator": {
"mcc": 208,
"mnc": 10,
"region": "Europe",
"country": "France",
"iso": "FR",
"operator": "Altice",
"brand": "SFR"
}
}
| Champ | Type | Description |
|---|---|---|
mcc | integer | Mobile Country Code |
mnc | integer | Mobile Network Code |
region | string | Région géographique |
country | string | Nom du pays |
iso | string | Code pays ISO 3166-1 alpha-2 |
operator | string | Nom du groupe opérateur |
brand | string | Marque commerciale |
État du tracker
L'objet tracker contient l'état complet de la balise au moment de la réception du message.
{
"tracker": {
"id": "tra_35pBms5aEyRZnLVAG7u7ZdmcCTC",
"serial": "90372",
"alias": "0001",
"createdAt": "2025-11-22T07:41:34.642+00:00",
"updatedAt": "2026-02-24T07:19:41.923+00:00",
"network": "gsm",
"battery": 71,
"temperature": 0,
"mcc": 208,
"mnc": 10,
"rsrq": 61,
"connected": true,
"connectedAt": "2026-02-24T07:02:46.902+00:00",
"sleep": false,
"sleepAt": null,
"charging": false,
"chargingAt": null,
"sentAt": "2026-02-24T07:19:41.908+00:00",
"lastPointAt": "2026-02-24T07:19:22.000+00:00",
"latitude": "45.4579552",
"longitude": "4.4046063",
"altitude": 443,
"speed": 34,
"configSentAt": null,
"customerId": "cus_38wA1qzOeV4Y5CotZNCP15z4J5E",
"configurationId": null,
"notes": null,
"zoneTrack": false
}
}
Identité
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant unique du tracker (tra_*) |
serial | string | Numéro de série matériel |
alias | string | Nom / alias assigné |
createdAt | string | Date d'enregistrement |
updatedAt | string | Dernière mise à jour d'état |
customerId | string | ID client propriétaire (cus_*) |
configurationId | string|null | ID configuration appliquée (cfn_*) |
notes | string|null | Notes libres associées au tracker |
État réseau
| Champ | Type | Description |
|---|---|---|
network | string | Type de réseau |
mcc | integer | Mobile Country Code |
mnc | integer | Mobile Network Code |
rsrq | integer | Qualité du signal |
connected | boolean | Tracker actuellement connecté |
connectedAt | string|null | Date de dernière connexion |
Batterie et alimentation
| Champ | Type | Description |
|---|---|---|
battery | integer | Niveau batterie (0-100 %) |
temperature | integer | Température interne (°C) |
charging | boolean | Tracker en charge |
chargingAt | string|null | Dernier changement d'état charge |
Veille
| Champ | Type | Description |
|---|---|---|
sleep | boolean | Tracker en mode veille |
sleepAt | string|null | Date de passage en veille |
Dernière position connue
| Champ | Type | Description |
|---|---|---|
latitude | string|null | Dernière latitude (null si jamais fixée) |
longitude | string|null | Dernière longitude (null si jamais fixée) |
altitude | integer | Dernière altitude (m) |
speed | integer | Dernière vitesse (km/h) |
lastPointAt | string | Date du dernier point enregistré |
Communication
| Champ | Type | Description |
|---|---|---|
sentAt | string | Date de la dernière transmission |
configSentAt | string|null | Date du dernier push de configuration |
Suivi de zones
| Champ | Type | Description |
|---|---|---|
zoneTrack | boolean | true si la balise est actuellement à l'intérieur d'une zone géofence suivie |
latitude et longitude de l'objet tracker sont de type string (contrairement aux éléments point où ce sont des number). Ils peuvent aussi être null si le tracker n'a jamais obtenu de fix GPS.tracker.updated — Mise à jour d'état
Ce webhook est envoyé après traitement d'un message.created, pour notifier que l'état du tracker a été mis à jour.
{
"type": "tracker.updated",
"data": {
"id": "tra_3A2Mu74SLWWg8cnRtNewiBIPKs9",
"serial": "90456",
"alias": "198",
"createdAt": "2026-02-22T18:53:51.615+00:00",
"updatedAt": "2026-02-27T19:13:08.987+00:00",
"network": "gsm",
"battery": 64,
"temperature": 0,
"mcc": 208,
"mnc": 10,
"rsrq": 56,
"connected": true,
"connectedAt": "2026-02-27T14:46:19.174+00:00",
"sleep": false,
"sleepAt": null,
"charging": false,
"chargingAt": null,
"sentAt": "2026-02-27T19:13:08.973+00:00",
"lastPointAt": "2026-02-27T19:09:16.359+00:00",
"latitude": null,
"longitude": null,
"altitude": 0,
"speed": 0,
"configSentAt": null,
"customerId": "cus_2tBdSTgP8giQ5s7bNNhN2ZvFOzv",
"configurationId": "cfn_3AGOZqTDYE3nnfw0EeM5yGUVUlW",
"notes": null
}
}
Les champs data sont identiques à ceux de l'objet tracker dans message.created (voir section ci-dessus).
tracker.updated pour maintenir en cache l'état courant de chaque tracker (connecté/déconnecté, batterie, dernière position, mode veille, etc.).Référence des champs
Le champ precision indique la précision du timestamp associé.
| Valeur | Description | Précision |
|---|---|---|
"MS" | Milliseconde | Timestamp à la milliseconde. Horloge synchronisée via GNSS. |
"SECOND" | Seconde | Timestamp à la seconde. |
"MINUTE" | Minute | Timestamp à la minute. Horloge interne (pas de sync GNSS récente). |
precision: "MS" a un timestamp très fiable (synchronisé satellite). Un point precision: "MINUTE" a un timestamp approximatif basé sur l'horloge interne de la balise.Les événements sont regroupés par catégorie. Le champ code est l'identifiant numérique unique envoyé par la balise ; eventType est le label lisible attribué par la plateforme. Les colonnes data et Position indiquent si l'événement transporte un payload spécifique (voir section dédiée) et/ou un objet pt de position GPS.
Alimentation et cycle de vie
| Badge | eventType | Code | data | Position | Description |
|---|---|---|---|---|---|
| Événement | power_on | 1 | non | non | Mise sous tension (boot ou redémarrage automatique) |
| Événement | power_off | 2 | non | non | Extinction (volontaire ou automatique) |
Veille / réveil
| Badge | eventType | Code | data | Position | Description |
|---|---|---|---|---|---|
| Événement | sleep_enter | 7 | non | non | Passage en veille légère (DODO) |
| Événement | sleep_leave | 8 | non | non | Sortie de veille (reprise d'activité) |
| Événement | deep_sleep_enter | 22 | non | non | Passage en veille profonde (consommation minimale) |
| Événement | sleep_cancelled | 23 | non | non | Une mise en veille programmée a été annulée avant exécution |
| Événement | sleep_scheduled | 39 | oui | non | Réveil programmé (data : timestamp UTC cible) |
Batterie
| Badge | eventType | Code | data | Position | Description |
|---|---|---|---|---|---|
| Événement | battery_low | 9 | oui | non | Niveau de batterie sous le seuil |
| Événement | battery_charging_start | 24 | oui | non | Début de charge (data : SoC, voltage, courant, temp) |
| Événement | battery_charging_stop | 25 | oui | non | Fin de charge (data : SoC, voltage, courant, temp) |
| Événement | battery_full | 26 | oui | non | Batterie pleine (≥ 99 %) |
| Événement | battery_error | 37 | oui | non | Erreur matérielle batterie (échec I2C ou init) |
Mouvement / choc
| Badge | eventType | Code | data | Position | Description |
|---|---|---|---|---|---|
| Événement | shock_detection | 3 | oui | non | Choc détecté par l'accéléromètre (data : norm, x, y, z, axis) |
| Événement | motion_start | 13 | non | non | Début de mouvement détecté |
| Événement | motion_stop | 14 | non | non | Fin de mouvement détectée |
| Événement | tamper | 15 | oui | non | Tentative d'altération détectée (priorité) |
Boutons utilisateur
Les 3 boutons physiques (button_1, button_2, button_3) sont configurables côté plateforme. Selon la configuration client, un même appui physique peut être remonté sous différents eventType : button_1/2/3, sos, user_ok, etc. Le code reflète l'événement logique configuré, pas l'index physique du bouton.
| Badge | eventType | Code | data | Position | Description |
|---|---|---|---|---|---|
| Événement | sos | 6 | oui | oui (pt) | Alerte SOS (priorité) |
| Événement | user_ok | 36 | non | oui (pt) | Confirmation utilisateur ("tout va bien") |
| Événement | button_1 | 29 | non | oui (pt) | Appui bouton physique 1, événement brut |
| Événement | button_2 | 30 | non | oui (pt) | Appui bouton physique 2, événement brut |
| Événement | button_3 | 31 | non | oui (pt) | Appui bouton physique 3, événement brut |
pt à l'intérieur de datas, et dupliquée à la racine (latitude/longitude/accuracy/satellites/fix) pour la compatibilité legacy. Sans fix GPS au moment de l'appui, tous les champs valent 0 (et accuracy peut valoir 499 comme sentinelle).GPS
| Badge | eventType | Code | data | Position | Description |
|---|---|---|---|---|---|
| Événement | gps_fix | 20 | non | non | Fix GPS acquis |
| Événement | gps_lost | 21 | non | non | Fix GPS perdu |
| Événement | ephem_acquired | 34 | non | non | Éphémérides acquises (seuil suffisant atteint) |
| Événement | sat_table_acquired | 35 | non | non | Almanach satellite complet acquis |
Géofence
| Badge | eventType | Code | data | Position | Description |
|---|---|---|---|---|---|
| Événement | geofence_in | 11 | oui | non | Entrée dans une zone géofence |
| Événement | geofence_out | 12 | oui | non | Sortie d'une zone géofence |
| Événement | geofence_overspeed | 38 | oui | non | Dépassement de vitesse à l'intérieur d'une zone (data : slot, name, speed) |
Configuration / FOTA
| Badge | eventType | Code | data | Position | Description |
|---|---|---|---|---|---|
| Événement | command_received | 27 | non | non | Commande(s) FOTA reçue(s) |
| Événement | command_applied | 28 | oui | non | Commande(s) FOTA appliquée(s) (data : codes de retour par commande) |
| Événement | config | 32 | oui | non | Snapshot de la configuration courante (data : texte NSE en CBOR tstr) |
| Événement | request_time_sync | 33 | non | non | La balise demande une synchronisation horaire au serveur |
sleep_leave (réveil) → activité normale (envoi de points) → sleep_enter (veille légère) → deep_sleep_enter (veille profonde) → sleep_leave (réveil suivant). Un sleep_scheduled est émis juste avant l'entrée en veille profonde quand le réveil a été programmé via la commande shell sleep schedule. power_off survient lors d'une extinction complète.5 est réservé (legacy BUTTON_1). Les codes au-delà de 39 sont réservés pour usage futur (max 50).Le champ fix indique le type de fix obtenu par le récepteur GNSS.
| Valeur | Description | Fiabilité |
|---|---|---|
0 | Pas de fix | Position invalide (lat/lon = 0). Ne pas afficher sur carte. |
2 | Fix 2D | Position horizontale uniquement. Altitude peu fiable. |
3 | Fix 3D | Position complète (lat, lon, altitude). Bonne fiabilité. |
4 | Fix 3D + DGPS | Position 3D avec corrections différentielles. Meilleure précision. |
fix >= 2. Privilégiez fix >= 3 pour une bonne précision.Champ tag (integer)
Le champ tag est un entier qui encode plusieurs métadonnées du point sous forme de bitmask. Une valeur de 0 signifie « aucune métadonnée » (point sans fix ou point basique).
| Valeur | Signification |
|---|---|
0 | Aucune métadonnée (typiquement un point sans fix) |
9216 | Point avec métadonnées complètes (voir objet tags) |
Objet tags (optionnel)
Quand tag != 0, l'objet tags fournit une version décodée, lisible du bitmask.
{
"tags": {
"type": "POINT",
"status": "NEW",
"location": "RAM",
"priority": "NORMAL",
"gps": "DISPO",
"fix": "3D",
"buffer": "LIVE"
}
}
| Champ | Valeurs possibles | Description |
|---|---|---|
type | "POINT" | Type d'élément |
status | "NEW" | Statut du point |
location | "RAM", "FLASH" | Stockage avant envoi |
priority | "NORMAL", "HIGH" | Priorité du point |
gps | "DISPO", "NO_FIX" | Disponibilité GPS au moment de la capture |
fix | "2D", "3D" | Type de fix GPS |
buffer | "LIVE", "HISTORY" | Point temps réel ou du buffer historique |
buffer : "LIVE" = point capturé et envoyé en temps réel. "HISTORY" = point stocké en mémoire (hors couverture réseau) et envoyé plus tard.| Valeur | Description |
|---|---|
"GNSS" | Timestamp synchronisé via le système GNSS (GPS/Galileo/GLONASS) |
Réponse attendue
Votre serveur doit répondre à chaque webhook avec :
- Code HTTP :
200 - Body :
{"message": "ok"} - Temps de réponse : idéalement < 1 seconde, maximum 5 secondes
HTTP/1.1 200 OK
Content-Type: application/json
{"message": "ok"}
data.id comme clé d'idempotence.Exemples complets
Point GPS valide (balise en mouvement)
{
"type": "message.created",
"data": {
"id": "msg_3A6em6HE5ts0Ls1Vzq863IuD62x",
"type": "datas",
"network": "gsm",
"mcc": 208,
"mnc": 10,
"rsrq": 61,
"battery": 71,
"temperature": 0,
"receivedAt": "2026-02-24T07:20:02.545+00:00",
"elements": [
{
"id": "elm_3A6em1aqCXEqx7mmrIowhAVaQq2",
"type": "point",
"datas": {
"type": "point",
"timestamp": 1771917582000,
"tag": 9216,
"source": "GNSS",
"precision": "MS",
"latitude": 45.4570617,
"longitude": 4.4021235,
"accuracy": 18,
"satellites": 11,
"fix": 4,
"speed": "40.8",
"temperature": 19,
"heading": 230,
"altitude": 448,
"tags": {
"type": "POINT",
"status": "NEW",
"location": "RAM",
"priority": "NORMAL",
"gps": "DISPO",
"fix": "3D",
"buffer": "LIVE"
}
},
"messageId": "msg_3A6em6HE5ts0Ls1Vzq863IuD62x",
"trackerId": "tra_35pBms5aEyRZnLVAG7u7ZdmcCTC",
"createdAt": "2026-02-24T07:20:02.554+00:00"
}
],
"networkOperator": {
"mcc": 208,
"mnc": 10,
"region": "Europe",
"country": "France",
"iso": "FR",
"operator": "Altice",
"brand": "SFR"
},
"tracker": {
"id": "tra_35pBms5aEyRZnLVAG7u7ZdmcCTC",
"serial": "90372",
"alias": "0001",
"battery": 71,
"connected": true,
"sleep": false,
"latitude": "45.4579552",
"longitude": "4.4046063",
"altitude": 443,
"speed": 34
}
}
}
Interprétation : Tracker 0001 (serial 90372) roule à 40,8 km/h, cap sud-ouest (heading 230), à 448 m d'altitude, avec 11 satellites et 18 m de précision. Batterie à 71 %.
Événements système (veille + extinction)
{
"type": "message.created",
"data": {
"id": "msg_3AAKX57Y9c0KK5YuMxlAQhANjaS",
"type": "datas",
"network": "gsm",
"battery": 70,
"receivedAt": "2026-02-25T14:32:50.358+00:00",
"elements": [
{
"type": "event",
"datas": {
"type": "event",
"eventType": "deep_sleep_enter",
"code": 22,
"id": 8,
"timestamp": 1772030676673,
"precision": "MINUTE",
"source": "GNSS"
}
},
{
"type": "event",
"datas": {
"type": "event",
"eventType": "power_off",
"code": 2,
"id": 9,
"timestamp": 1772030960172,
"precision": "MINUTE",
"source": "GNSS"
}
},
{
"type": "point",
"datas": {
"type": "point",
"timestamp": 1772030966384,
"tag": 0,
"latitude": 0,
"longitude": 0,
"fix": 0,
"satellites": 0,
"speed": "0.0",
"temperature": 25
}
}
]
}
}
Interprétation : La balise est entrée en veille profonde (event 8), puis s'est éteinte (event 9). Le point GPS associé n'a pas de fix (lat/lon = 0, fix = 0) car le GPS n'était pas disponible au moment de l'extinction.
Réveil avec succession de points sans fix
Une balise qui sort de veille envoie souvent une succession de points le temps d'acquérir un fix GPS. Tous ces points auront fix: 0 et des coordonnées à 0.
{
"elements": [
{
"type": "event",
"datas": {
"eventType": "sleep_leave",
"code": 8,
"id": 11,
"timestamp": 1772219306752,
"precision": "SECOND"
}
},
{ "type": "point", "datas": { "timestamp": 1772218605007, "fix": 0, "latitude": 0, "longitude": 0, "temperature": 27 } },
{ "type": "point", "datas": { "timestamp": 1772219307243, "fix": 0, "latitude": 0, "longitude": 0, "temperature": 24 } },
{ "type": "point", "datas": { "timestamp": 1772219308223, "fix": 0, "latitude": 0, "longitude": 0, "temperature": 24 } }
]
}
Interprétation : La balise se réveille (sleep_leave). Les points envoyés n'ont pas encore de fix GPS (le récepteur GNSS est en cours d'acquisition). Ces points ne doivent pas être affichés sur une carte.
fix == 0 pour n'afficher que les positions valides.Détection de choc (avec payload)
{
"type": "event",
"datas": {
"type": "event",
"eventType": "shock_detection",
"code": 3,
"id": 7,
"timestamp": 1778140491769,
"precision": "SECOND",
"source": "GNSS",
"data": {
"norm": 6869,
"x": -3997,
"y": 3995,
"z": 3905,
"axis": "X"
}
}
}
Interprétation : Un choc de magnitude crête 6869 mg a été détecté, principalement sur l'axe X.
Appui bouton (avec position)
{
"type": "event",
"datas": {
"type": "event",
"eventType": "button_3",
"code": 31,
"id": 6,
"timestamp": 1778140445246,
"precision": "SECOND",
"source": "GNSS",
"pt": {
"lat": 0,
"lon": 0,
"acc": 499,
"sats": 0,
"fix": 0
},
"latitude": 0,
"longitude": 0,
"accuracy": 499,
"satellites": 0,
"fix": 0
}
}
Interprétation : Le bouton 3 a été pressé. Aucun fix GPS n'était disponible au moment de l'appui (fix: 0, acc: 499 est la valeur sentinelle "no-fix").
eventType: "sos" (code 6), "user_ok" (code 36), etc. Les champs code et eventType reflètent toujours l'événement logique mappé sur le bouton.Début de charge (avec payload)
{
"type": "event",
"datas": {
"type": "event",
"eventType": "battery_charging_start",
"code": 24,
"id": 2,
"timestamp": 1778140272055,
"precision": "SECOND",
"source": "GNSS",
"data": {
"soc": 4.2,
"voltage": 4173,
"current": 777.8,
"temp": 29
}
}
}
Interprétation : Le câble de charge vient d'être branché. Batterie à 4,2 % SoC, tension 4173 mV, courant de charge +777,8 mA, température batterie 29 °C. Un événement battery_charging_stop (code 25) sera émis au débranchement, avec la même structure data.
Réveil programmé (avec timestamp cible)
{
"type": "event",
"datas": {
"type": "event",
"eventType": "sleep_scheduled",
"code": 39,
"id": 12,
"timestamp": 1776947400,
"precision": "SECOND",
"source": "GNSS",
"data": {
"wake_at": 1776947580
}
}
}
Interprétation : À 2026-04-23 12:30:00 UTC (timestamp de l'événement), un réveil programmé a été demandé via la commande shell sleep schedule. La balise se réveillera à 2026-04-23 12:33:00 UTC (wake_at). Juste après cet événement, elle entre en veille profonde (GNSS éteint, modem éteint) et attend l'heure cible pour émettre un sleep_leave au réveil.
sleep_scheduled est toujours suivi (après la période de veille profonde) d'un sleep_leave au moment du réveil effectif.Guide d'intégration
Algorithme de traitement recommandé
Réception POST webhook
│
├─> Vérifier Content-Type: application/json
│
├─> Parser le body JSON
│
├─> Lire le champ "type"
│ │
│ ├─> "message.created"
│ │ │
│ │ ├─> Pour chaque element dans "elements" :
│ │ │ │
│ │ │ ├─> Si type == "point" ET fix >= 2 :
│ │ │ │ Stocker la position GPS valide
│ │ │ │
│ │ │ ├─> Si type == "point" ET fix == 0 :
│ │ │ │ Ignorer (pas de position) ou stocker température seule
│ │ │ │
│ │ │ └─> Si type == "event" :
│ │ │ Traiter l'événement système
│ │ │
│ │ └─> Mettre à jour l'état du tracker (batterie, signal…)
│ │
│ └─> "tracker.updated"
│ │
│ └─> Mettre à jour le cache d'état du tracker
│
└─> Répondre HTTP 200 {"message": "ok"}
Règles de filtrage des points
| Condition | Action |
|---|---|
fix == 0 | Ignorer — pas de position GPS valide |
fix == 2 | À utiliser avec précaution — position 2D seulement (altitude peu fiable) |
fix >= 3 | Afficher — position fiable |
accuracy > 100 | Marquer "faible précision" |
satellites < 4 | Position potentiellement imprécise |
Conversion des timestamps
Le champ timestamp est un timestamp Unix en millisecondes (pas en secondes).
const ts_ms = 1771917582000;
const date = new Date(ts_ms);
// -> 2026-02-24T17:19:42.000Z
from datetime import datetime, timezone
ts_ms = 1771917582000
dt = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc)
# -> 2026-02-24T17:19:42+00:00
$ts_ms = 1771917582000;
$date = (new DateTime())->setTimestamp($ts_ms / 1000);
// -> 2026-02-24 17:19:42
long ts_ms = 1771917582000;
var date = DateTimeOffset.FromUnixTimeMilliseconds(ts_ms);
// -> 2026-02-24T17:19:42.000+00:00
long tsMs = 1771917582000L;
Instant instant = Instant.ofEpochMilli(tsMs);
// -> 2026-02-24T17:19:42Z
Idempotence
Chaque message et élément possède un id unique. Utilisez ces identifiants pour éviter les doublons.
| Niveau | Champ | Format | Exemple |
|---|---|---|---|
| Message | data.id | msg_* | msg_3AAKX57Y9c0KK5YuMxlAQhANjaS |
| Élément | elements[].id | elm_* | elm_3A6em1aqCXEqx7mmrIowhAVaQq2 |
| Tracker | tracker.id | tra_* | tra_35pBms5aEyRZnLVAG7u7ZdmcCTC |
| Client | tracker.customerId | cus_* | cus_38wA1qzOeV4Y5CotZNCP15z4J5E |
| Configuration | tracker.configurationId | cfn_* | cfn_3AGOZqTDYE3nnfw0EeM5yGUVUlW |
Questions fréquentes
Comment savoir si un point GPS est valide ?
Vérifiez que fix >= 2 ET latitude != 0 ET longitude != 0. Un point avec fix: 0 n'a pas de position GPS et ne doit pas être affiché sur une carte.
Pourquoi je reçois des points avec latitude/longitude à 0 ?
La balise envoie des points même sans fix GPS (par exemple juste après le réveil, ou en intérieur). Ces points contiennent quand même la température et le timestamp, mais pas de position valide.
Quelle est la différence entre receivedAt et le timestamp d'un élément ?
receivedAt: le moment où la plateforme cloud a reçu le message du trackertimestamp(d'un élément) : le moment où le tracker a capturé la donnée (point GPS ou événement)
Il peut y avoir un décalage si la balise était hors couverture réseau et a bufferisé les données.
Pourquoi je reçois un tracker.updated après chaque message.created ?
Le tracker.updated reflète le nouvel état du tracker après intégration des données du message. Utilisez-le pour maintenir un cache de l'état courant (batterie, position, connectivité, etc.).
Comment différencier un point "live" d'un point bufferisé ?
Si l'objet tags est présent, consultez le champ buffer :
"LIVE": point capturé et envoyé en temps réel"HISTORY": point stocké en mémoire et envoyé plus tard
Si tags est absent (tag = 0), le point est généralement un point sans fix (la distinction live/history n'est pas pertinente).
Que se passe-t-il si mon serveur ne répond pas à temps ?
Le webhook peut être rejoué. Assurez-vous que votre traitement est idempotent en utilisant les champs id du message et des éléments comme clés de déduplication.
Pourquoi le champ speed est une string dans les points mais un integer dans le tracker ?
C'est volontaire. Dans les éléments point, speed est une string avec décimales ("40.8"). Dans l'objet tracker, speed est un entier arrondi (34). Parsez en conséquence.
Comment interpréter le champ heading ?
Le heading est un cap en degrés (0-360) :
- 0 = Nord
- 90 = Est
- 180 = Sud
- 270 = Ouest
Un heading de 230 signifie que la balise se déplace vers le sud-ouest.
Un même message peut-il contenir à la fois des points et des événements ?
Oui. Le tableau elements peut contenir un mélange de point et event dans n'importe quel ordre. Un message typique après un réveil peut contenir un événement sleep_leave suivi de plusieurs points GPS.
Quel système de coordonnées est utilisé pour les positions GPS ?
Toutes les coordonnées utilisent le datum WGS84 (le standard mondial des systèmes GPS). Latitude et longitude sont exprimées en degrés décimaux.
Pourquoi un même bouton physique peut-il remonter des eventType différents selon les clients ?
Chaque bouton physique (button_1, button_2, button_3) est mappé sur un événement logique côté plateforme. Un client peut configurer le bouton 1 comme sos, le bouton 2 comme user_ok, le bouton 3 comme button_3 brut, etc. Les champs code et eventType reflètent toujours l'événement logique, pas l'index physique. Pour savoir quel bouton physique a été pressé indépendamment du mapping, consultez la configuration plateforme du tracker concerné.
Quelle différence entre l'objet pt et les champs legacy latitude/longitude dans un événement ?
Pour les événements émis avec un contexte GPS (appuis bouton, SOS), la position est envoyée deux fois pour la rétrocompatibilité : une fois sous forme d'objet structuré pt (pt.lat, pt.lon, pt.acc, pt.sats, pt.fix) et une fois sous forme de champs aplatis à la racine de datas (latitude, longitude, accuracy, satellites, fix). Les deux portent les mêmes valeurs. Privilégiez l'objet pt pour les nouvelles intégrations.
Pourquoi un événement contient-il parfois un objet data et parfois non ?
Les événements se répartissent en 3 catégories :
- Événements de cycle de vie (
power_on,power_off,sleep_enter,sleep_leave,deep_sleep_enter,gps_fix,gps_lost…) : pas de payload, l'eventTypeseul porte l'information. - Événements télémétriques (
shock_detection,battery_charging_start,geofence_in,sleep_scheduled…) : contiennent un objetdataavec des champs spécifiques au type d'événement. - Événements de type bouton (
button_1/2/3,sos,user_ok) : contiennent un objetptavec la position GPS au moment de l'appui. Peuvent aussi contenir undataselon leeventType.
La présence de data et pt est documentée par type d'événement dans le tableau "Types d'événements" (colonnes data / Position).
Comment savoir quand une balise sortira d'une veille profonde programmée ?
Quand un événement sleep_scheduled (code 39) arrive, parsez data.wake_at : c'est le timestamp Unix en secondes (UTC) auquel la balise est programmée pour se réveiller. La balise est injoignable entre sleep_scheduled et le prochain sleep_leave (qui se déclenche au réveil effectif, généralement à ±30 secondes de wake_at selon la granularité de polling).
Que signifie zoneTrack dans l'état du tracker ?
zoneTrack: true indique que la balise est actuellement à l'intérieur d'une des zones géofence qu'elle suit. C'est un signal booléen rapide pour les dashboards. Pour le détail (quelle zone, quand l'entrée a eu lieu, etc.), appuyez-vous sur les événements geofence_in / geofence_out.
Suivi et diagnostic
L'onglet Webhook de la plateforme vous permet de suivre en temps réel l'état de vos intégrations (statut, codes HTTP, latence, logs). Chaque webhook affiche :
- Statut d'activation (Enabled / Disabled)
- Type d'événements écoutés (
message.created,tracker.updated) - Statut HTTP renvoyé par votre serveur (200, 400, 500…)
- Temps de réponse moyen côté serveur
- Date et type du dernier envoi
- Succès ou échec des envois récents
Bonnes pratiques
Pour garantir une intégration robuste, nous recommandons :
- Sécurité : HTTPS obligatoire, filtrage IP recommandé
- Capacité : assurez-vous que votre infrastructure peut absorber les envois en cas de fort trafic
- Traitement asynchrone : répondez rapidement HTTP 200 puis traitez les messages en tâche de fond (queue, worker)
- Idempotence : utilisez
data.idcomme clé unique pour éviter les doublons - Logs : archivez les payloads reçus pour faciliter le support et le diagnostic