Logo Neyos

Webhook

Les webhooks permettent de rediriger automatiquement les messages générés par vos balises vers vos propres systèmes via HTTP POST. Ils transmettent des données brutes (position, événements, état système) au format JSON, prêtes à être exploitées dans vos applications métiers.

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

Restauration du flux de données
Historique sous deux mois
Mise à disposition sécurisé

Webhook & API

Routage des données
Authentification sécurisée
Lecture et écriture des flux
Neyos

Plateforme Neyos

Prise en main rapide
Tableau de bord et configuration
Facturation simplifiée

Votre application

Des données pour vos métiers
En temps réel
Adapté à vos usages

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 :

  1. Connectez-vous à la plateforme Neyos.
  2. Accédez à l'onglet Webhook
  3. Cliquez sur .
  4. Indiquez l'URL cible de votre serveur, et cliquez sur Activé
  5. Votre webhook est maintenant en marche, les données sont redirigées vers le endpoint enregistré.

Votre endpoint doit

  1. Accepter les requêtes POST en HTTPS
  2. Parser le body JSON
  3. Répondre HTTP 200 avec le body {"message": "ok"}
  4. 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.

TypeDescriptionFréquence
message.createdNouveau message de télémétrie (points GPS + événements)À chaque envoi par la balise
tracker.updatedMise à jour de l'état du trackerAprès traitement d'un message.created
Un 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 :

ChampTypeDescriptionExemple
idstringIdentifiant unique du messagemsg_3AAKX57Y9c0KK5YuMxlAQhANjaS
typestringToujours "datas"datas
networkstringType de réseau utiliségsm
mccintegerMobile Country Code (pays)208 (France)
mncintegerMobile Network Code (opérateur)10 (SFR)
rsrqintegerQualité du signal (30 faible → 70 excellent)61
batteryintegerNiveau de batterie (0-100 %)70
temperatureintegerTempérature interne en °C0
receivedAtstringDate/heure de réception plateforme (ISO 8601)2026-02-25T14:32:50.358+00:00
elementsarrayTableau de points et événementsvoir sections ci-dessous
networkOperatorobjectDétails opérateur réseauvoir section dédiée
trackerobjectÉtat complet du trackervoir 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 :

ChampTypeDescription
idstringIdentifiant unique de l'élément
typestringToujours "point"
messageIdstringID du message parent
trackerIdstringID du tracker émetteur
createdAtstringDate de création côté plateforme (ISO 8601)

Champs datas d'un point :

ChampTypeUnitéDescription
typestring-Toujours "point"
timestampintegermsTimestamp Unix en millisecondes
taginteger-Encodage bitmask des métadonnées
sourcestring-Source de la position ("GNSS")
precisionstring-Précision temporelle (voir référence)
latitudenumberdegrésLatitude WGS84. 0 si pas de fix
longitudenumberdegrésLongitude WGS84. 0 si pas de fix
accuracyintegermPrécision horizontale estimée. 0 si pas de fix
satellitesinteger-Nombre de satellites utilisés
fixinteger-Type de fix GPS (voir référence)
speedstringkm/hVitesse au sol. "0.0" si immobile ou pas de fix
temperatureinteger°CTempérature au moment de la capture
headingintegerdegrésDirection (0-360°, 0 = Nord)
altitudeintegermAltitude au-dessus du niveau de la mer
tagsobject-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) :

ChampTypeDescription
typestringToujours "event"
eventTypestringType de l'événement (voir référence)
codeintegerCode numérique unique de l'événement
idintegerNuméro de séquence sur la balise
timestampintegerTimestamp Unix en millisecondes
precisionstringPrécision temporelle (voir référence)
sourcestringSource de synchronisation temporelle

Champs optionnels (selon le type d'événement) :

ChampTypePrésent pourDescription
dataobjecté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)
ptobjecté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, fixmixtemêmes événements que ptDuplication legacy des champs pt, aplatie à la racine de datas
Pour les nouvelles intégrations, privilégiez l'objet 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"
  }
}
ChampTypeUnitéDescription
normintegermgMagnitude crête de l'accélération (sqrt(x²+y²+z²))
xintegermgCrête sur l'axe X (signée)
yintegermgCrête sur l'axe Y (signée)
zintegermgCrête sur l'axe Z (signée)
axisstring-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
  }
}
ChampTypeUnitéDescription
socnumber%État de charge (0.0 - 100.0)
voltageintegermVTension batterie
currentnumbermACourant de charge/décharge (positif = charge, négatif = décharge)
tempinteger°CTempérature batterie

Événement Veille programmée

{
  "data": {
    "wake_at": 1776947580
  }
}
ChampTypeUnitéDescription
wake_atintegersecondesTimestamp 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
  }
}
ChampTypeUnitéDescription
slotinteger-Index du slot de zone (0..N)
namestring-Nom de la zone configuré sur la plateforme
speedintegerkm/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
}
ChampTypeUnitéDescription
latnumberdegrésLatitude WGS84 (0 si pas de fix)
lonnumberdegrésLongitude WGS84 (0 si pas de fix)
accintegermPrécision horizontale estimée (peut valoir 499 en valeur de repli sans fix)
satsinteger-Nombre de satellites utilisés
fixinteger-Type de fix GPS (voir référence)
Pas de fix au moment de l'appui — quand l'utilisateur presse un bouton sans fix GPS, tous les champs de position valent 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"
  }
}
ChampTypeDescription
mccintegerMobile Country Code
mncintegerMobile Network Code
regionstringRégion géographique
countrystringNom du pays
isostringCode pays ISO 3166-1 alpha-2
operatorstringNom du groupe opérateur
brandstringMarque 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é

ChampTypeDescription
idstringIdentifiant unique du tracker (tra_*)
serialstringNuméro de série matériel
aliasstringNom / alias assigné
createdAtstringDate d'enregistrement
updatedAtstringDernière mise à jour d'état
customerIdstringID client propriétaire (cus_*)
configurationIdstring|nullID configuration appliquée (cfn_*)
notesstring|nullNotes libres associées au tracker

État réseau

ChampTypeDescription
networkstringType de réseau
mccintegerMobile Country Code
mncintegerMobile Network Code
rsrqintegerQualité du signal
connectedbooleanTracker actuellement connecté
connectedAtstring|nullDate de dernière connexion

Batterie et alimentation

ChampTypeDescription
batteryintegerNiveau batterie (0-100 %)
temperatureintegerTempérature interne (°C)
chargingbooleanTracker en charge
chargingAtstring|nullDernier changement d'état charge

Veille

ChampTypeDescription
sleepbooleanTracker en mode veille
sleepAtstring|nullDate de passage en veille

Dernière position connue

ChampTypeDescription
latitudestring|nullDernière latitude (null si jamais fixée)
longitudestring|nullDernière longitude (null si jamais fixée)
altitudeintegerDernière altitude (m)
speedintegerDernière vitesse (km/h)
lastPointAtstringDate du dernier point enregistré

Communication

ChampTypeDescription
sentAtstringDate de la dernière transmission
configSentAtstring|nullDate du dernier push de configuration

Suivi de zones

ChampTypeDescription
zoneTrackbooleantrue si la balise est actuellement à l'intérieur d'une zone géofence suivie
Les champs 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).

Usage typique : utilisez 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

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"}
En cas d'absence de réponse ou d'erreur — le webhook peut être rejoué. Assurez-vous que votre traitement est idempotent (traiter deux fois le même message ne doit pas créer de doublons). Utilisez le champ 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.

Filtrez les points avec 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").

Selon la configuration plateforme, ce même appui physique peut apparaître sous 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.

Pairing — un 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

ConditionAction
fix == 0Ignorer — pas de position GPS valide
fix == 2À utiliser avec précaution — position 2D seulement (altitude peu fiable)
fix >= 3Afficher — position fiable
accuracy > 100Marquer "faible précision"
satellites < 4Position 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

Idempotence

Chaque message et élément possède un id unique. Utilisez ces identifiants pour éviter les doublons.

NiveauChampFormatExemple
Messagedata.idmsg_*msg_3AAKX57Y9c0KK5YuMxlAQhANjaS
Élémentelements[].idelm_*elm_3A6em1aqCXEqx7mmrIowhAVaQq2
Trackertracker.idtra_*tra_35pBms5aEyRZnLVAG7u7ZdmcCTC
Clienttracker.customerIdcus_*cus_38wA1qzOeV4Y5CotZNCP15z4J5E
Configurationtracker.configurationIdcfn_*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 tracker
  • timestamp (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 :

  1. É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'eventType seul porte l'information.
  2. Événements télémétriques (shock_detection, battery_charging_start, geofence_in, sleep_scheduled…) : contiennent un objet data avec des champs spécifiques au type d'événement.
  3. Événements de type bouton (button_1/2/3, sos, user_ok) : contiennent un objet pt avec la position GPS au moment de l'appui. Peuvent aussi contenir un data selon le eventType.

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.id comme clé unique pour éviter les doublons
  • Logs : archivez les payloads reçus pour faciliter le support et le diagnostic