Nouveau : le pare-feu IA surveille chaque module et explique chaque incident en termes simples. Découvrez comment ça marche

API des appareils et des profils

Routes REST pour les appareils, les identifiants des appareils, les détails de connexion, le journal des appareils et les profils d'appareils, avec paramètres, réponses et erreurs.

Ces routes gèrent les appareils et les profils d’appareils par code. Les chemins se trouvent sous https://<votre hôte>/tenant/<tenantId>. Les conventions (pagination, corps stricts, heures) sont décrites dans REST API basics.

Appareils

MéthodeCheminPermissionAction
GET/api/iot/devicesiot_device.devices.readLister les appareils
POST/api/iot/devicesiot_device.devices.createCréer un appareil et son jeton d’accès
GET/api/iot/devices/{deviceId}iot_device.devices.readLire un appareil
PATCH/api/iot/devices/{deviceId}iot_device.devices.updateModifier le nom, le libellé, le type, le profil, le statut, les informations supplémentaires
DELETE/api/iot/devices/{deviceId}iot_device.devices.deleteSupprimer un appareil
GET/api/iot/devices/{deviceId}/connectioniot_device.devices.readOù l’appareil se connecte
GET/api/iot/devices/{deviceId}/connectionsiot_device.devices.readLe journal des connexions
GET/api/iot/devices/{deviceId}/logiot_device.devices.readJournal de connexion et lignes d’audit, fusionnés

Lister les appareils

GET /api/iot/devices (pages à partir de 1)

ParamètreValeurs
pageà partir de 1 (par défaut 1)
pageSizede 1 à 100 (par défaut 20)
searchjusqu’à 128 caractères : nom, libellé ou numéro de série
deviceProfileIdun identifiant de profil
statusACTIVE, QUARANTINED ou DISABLED
isGatewaytrue ou false
onlinetrue, false ou unknown
sortname, connection, lastSeen, createdAt, avec :asc ou :desc
{
  "devices": [
    {
      "deviceId": "6f1c…",
      "name": "pump-station-04",
      "label": "Pump station 4",
      "type": "pump-controller",
      "serial": null,
      "deviceProfileId": "a1b2…",
      "status": "ACTIVE",
      "isGateway": false,
      "gatewayDeviceId": null,
      "model": null,
      "fwTitle": null,
      "fwVersion": null,
      "online": true,
      "active": true,
      "lastConnectAt": "2026-11-08T06:12:03.000Z",
      "lastDisconnectAt": null,
      "lastActivityAt": "2026-11-09T09:41:10.000Z",
      "lastRemoteIp": "203.0.113.20",
      "lastTransport": "mqtts",
      "additionalInfo": {},
      "createdAt": "2026-10-01T08:00:00.000Z",
      "updatedAt": "2026-11-08T06:12:03.000Z"
    }
  ],
  "total": 1
}

online vaut null sur un profil dont la règle de présence est Dernière activité uniquement. GET /api/iot/devices/{deviceId} répond { "device": {...} } avec les mêmes champs, plus profileName et profileTransport.

Créer un appareil

POST/tenant/{tenantId}/api/iot/devices

Champs : name (obligatoire, 1 à 128 caractères, unique), label (jusqu’à 255), type (jusqu’à 64), deviceProfileId (sinon le profil par défaut), isGateway, additionalInfo (un objet d’au plus 50 clés et 8 Kio). La réponse contient l’appareil et, pour les profils dont les appareils s’authentifient eux-mêmes, un jeton d’accès dans credential.secret.token. Le jeton n’est affiché que dans cette réponse.

Corps de la requête application/json

{
    "name": "pump-station-04",
    "label": "Pump station 4",
    "deviceProfileId": "a1b2…"
}

Exemple curl

curl -X POST 'https://<your-host>/tenant/{tenantId}/api/iot/devices' \
  -H 'Content-Type: application/json' \
  -d '{"name":"pump-station-04","label":"Pump station 4","deviceProfileId":"a1b2…"}'

Réponses

201Créé
{
    "device": {
        "deviceId": "6f1c…",
        "name": "pump-station-04",
        "status": "ACTIVE",
        "…": "…"
    },
    "credential": {
        "credential": {
            "credentialId": "…",
            "type": "ACCESS_TOKEN",
            "…": "…"
        },
        "secret": {
            "token": "Xq3…"
        }
    }
}
403Interdit
{
    "message": "The device limit of this account is reached.",
    "code": "FORBIDDEN",
    "details": {
        "key": "max_devices",
        "limit": 43,
        "current": 43,
        "adding": 1
    }
}
409Conflit
{
    "message": "A device with this name already exists.",
    "code": "CONFLICT",
    "details": {
        "reason": "name_taken"
    }
}

Modifier un appareil

PATCH /api/iot/devices/{deviceId} accepte l’un quelconque de name, label, type, deviceProfileId, isGateway, additionalInfo, status (ACTIVE ou DISABLED). N’envoyez que ce qui change. Un appareil en quarantaine s’approuve via le provisioning, pas ici : « Un appareil en quarantaine s’active via le provisioning, et non en le modifiant ici. » Un nouveau nom, un nouveau profil ou une désactivation met fin à la session active de l’appareil ; il se reconnecte avec les nouveaux paramètres.

Supprimer un appareil

DELETE répond { "message": "Device deleted." }. Les relevés de l’appareil sont supprimés en arrière-plan. Un appareil encore utilisé est refusé avec 409, par exemple « The device is still in use by 1 asset placement or relation (iot_asset). » Retirez-le de son actif et supprimez d’abord ses relations : voir Placing devices et Relations.

Détails de connexion

GET /api/iot/devices/{deviceId}/connection ne renvoie aucun secret :

{
  "connection": {
    "mqtt": { "host": "mqtt.example.com", "port": 8883, "tls": true },
    "httpBase": "https://acme.example.com",
    "topics": { "telemetry": "v1/telemetry", "attributes": "v1/attributes", "rpcRequest": "v1/rpc/req/+", "rpcResponse": "v1/rpc/res/{id}" },
    "telemetryKeys": [{ "key": "temperature", "type": "number" }]
  }
}

mqtt vaut null lorsque le profil refuse MQTT sur cet écouteur ; rpcRequest et rpcResponse valent null avec le schéma Legacy compatible.

Journaux

  • GET .../connections?page=1&pageSize=50 : connexions et déconnexions, les plus récentes d’abord (pages à partir de 1, pageSize jusqu’à 100).
  • GET .../log?page=1&pageSize=50&source=connection|audit : le journal de connexion et les lignes d’audit de l’appareil, fusionnés, les plus récents d’abord. page × pageSize ne doit pas dépasser 1 000.

Identifiants de l’appareil

MéthodeCheminAction
GET/api/iot/devices/{deviceId}/credentialsL’identifiant actif, sans son secret
PUT/api/iot/devices/{deviceId}/credentialsPasser à un autre identifiant
POST/api/iot/devices/{deviceId}/credentials/rotateUn nouveau secret du même type (201)
DELETE/api/iot/devices/{deviceId}/credentialsRévoquer l’identifiant

Toutes requièrent iot_device.credentials.manage. Le passage, la rotation et la révocation mettent fin immédiatement à l’ancien identifiant (sans période de tolérance) et déconnectent l’appareil.

Corps des PUT :

{ "type": "ACCESS_TOKEN" }
{ "type": "MQTT_BASIC", "username": "pump04", "clientId": "pump04", "password": null }
{ "type": "X509_CERTIFICATE", "certificateId": "…" }

Pour MQTT_BASIC, omettez password (ou mettez null) pour obtenir un mot de passe généré. Un mot de passe choisi doit comporter au moins 16 caractères, variés, et ne pas contenir le nom d’utilisateur ni l’identifiant client. Le nom d’utilisateur provision est réservé. La réponse est { "credential": {...}, "secret": { "token": "…" } } ou { ..., "secret": { "password": "…" } }, affichée une seule fois ; un identifiant X.509 n’a pas de secret. Un identifiant X.509 se renouvelle en associant un nouveau certificat : « Un identifiant X.509 se renouvelle en associant un nouveau certificat. » Voir Device credentials.

Profils d’appareils

MéthodeCheminPermissionAction
GET/api/iot/device-profilesiot_device_profile.profiles.readListe (page à partir de 1, pageSize, search, transportType, onlineRule, sort)
POST/api/iot/device-profilesiot_device_profile.profiles.writeCréer
GET/api/iot/device-profiles/{profileId}.profiles.readLire
PATCH/api/iot/device-profiles/{profileId}.profiles.writeModifier ; envoyer expectedVersion
DELETE/api/iot/device-profiles/{profileId}.profiles.writeSupprimer
POST/api/iot/device-profiles/{profileId}/default.profiles.writeEn faire le profil par défaut
POST/api/iot/device-profiles/{profileId}/duplicate.profiles.writeLe copier sous le nom «  (copie) »
GET/api/iot/device-profiles/{profileId}/key-usage?keys=a,b.profiles.readQui lit ces clés (règles, cartes, flux)
GET, PUT, POST/api/iot/device-profiles/{profileId}/provisioningiot_device_profile.provisioning.manageParamètres de provisioning ; POST fait tourner ou révoque une clé de provisioning

Champs de tri : name, transport, online, updated. Une liste répond { "profiles": [...], "total": n } ; un profil, { "profile": {...} }.

Créer un profil

Un nouveau profil requiert un name (jusqu’à 128 caractères) et une onlineRule : LIVE_SOCKET (Connexion en direct), UPLINK_WINDOW (Message récent, nécessite aussi expectedIntervalS, de 60 à 604 800), ou LAST_SEEN_ONLY (Dernière activité uniquement). Chaque autre champ prend sa valeur par défaut.

{
  "name": "Cold room sensor",
  "onlineRule": "UPLINK_WINDOW",
  "expectedIntervalS": 300,
  "transportType": "MQTT",
  "telemetrySchema": [
    { "key": "temperature", "type": "number", "unit": "°C", "label": "Temperature", "min": -30, "max": 10, "decimals": 1 }
  ]
}

Champs retenus et leurs plages :

ChampPlage
transportTypeMQTT, HTTP, ANY, ou un protocole enregistré
allowedAuthModes1 à 3 parmi ACCESS_TOKEN, MQTT_BASIC, X509_CERTIFICATE
mqttTransportTLS_REQUIRED (par défaut) ou PLAINTEXT_ALLOWED
allowedNetworksjusqu’à 64 réseaux ou adresses
payloadMaxBytes1 024 à 65 536
downlinkMaxBytes1 024 à 65 536
inactivityTimeoutSec10 à 604 800
maxGatewayChildren0 à 10 000
rpcTimeoutDefaultSec1 à 300
onlineWindowFactor1,5 à 10, une décimale
telemetrySchema, cfgSchemajusqu’à 500 clés chacun
rateLimitscount:seconds[,count:seconds] par famille, par exemple "telemetry_msgs": "10:1,300:60"

Lisez d’abord un profil existant pour voir chaque champ avec sa valeur actuelle ; l’éditeur de profils couvre les mêmes champs avec des explications, voir Profils d’appareils.

Refus

Un corps qui enfreint une règle de champ renvoie une 400 avec les problèmes dans issues, chacun avec son path et son message, par exemple online_rule_required (un nouveau profil nécessite une règle de connexion), expected_interval_required (Message récent nécessite expectedIntervalS) ou online_rule_not_allowed (la règle de connexion ne convient pas au transport).

Les autres refus portent details.reason, par exemple :

MotifSignification
stale_profileQuelqu’un a enregistré le profil depuis votre lecture (409)
name_takenUn autre profil porte déjà ce nom
default_profileLe profil par défaut ne peut pas être supprimé
builtin_profileUn profil intégré ne peut pas être modifié de cette façon
still_referencedDes appareils ou d’autres enregistrements utilisent encore le profil
reference_unverifiableUn module susceptible d’utiliser le profil n’a pas pu être interrogé ; réessayez