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

API des commandes

Envoyez des commandes aux appareils, attendez ou interrogez leurs résultats, annulez-les et gérez le catalogue de commandes d'un profil via REST : champs, états, limites et erreurs.

Une commande (un RPC) demande à un appareil d’effectuer une action et, sauf si elle est à sens unique, attend la réponse de l’appareil. Chaque commande est enregistrée comme une requête avec un état, afin que vous puissiez l’envoyer maintenant et lire le résultat plus tard. Le fonctionnement des commandes pour les utilisateurs de l’application est décrit dans Envoyer des commandes aux appareils. Les chemins sont sous https://<your host>/tenant/<tenantId>.

En cours de développement : les commandes vers les appareils derrière une passerelle (les appareils enfants d’une passerelle) sont en cours de développement. Envoyez des commandes aux appareils qui se connectent d’eux-mêmes.

Routes

MéthodeCheminPermissionAction
POST/api/iot/devices/{deviceId}/rpciot_rpc.read plus le niveau de la commandeEnvoyer une commande
GET/api/iot/devices/{deviceId}/rpciot_rpc.readHistorique des commandes de l’appareil
GET/api/iot/rpc/{rpcId}iot_rpc.readUne commande avec sa réponse
POST/api/iot/rpc/{rpcId}/canceliot_rpc.read plus le niveau de la commandeAnnuler une commande en file d’attente ou envoyée
GET/api/iot/devices/{deviceId}/rpc-commandsiot_rpc.send.basicLes commandes qu’un contrôle de tableau de bord peut envoyer à cet appareil
GET/api/iot/rpc-commands/{profileId}iot_rpc.readCatalogue de commandes d’un profil (?format=export pour le format d’import)
POST/api/iot/rpc-commands/{profileId}iot_rpc.commands.manageAjouter une commande au catalogue
PUT/api/iot/rpc-commands/{profileId}iot_rpc.commands.manageRemplacer tout le catalogue
PATCH, DELETE/api/iot/rpc-commands/{profileId}/{commandId}iot_rpc.commands.manageModifier ou supprimer une commande

Qui peut envoyer quoi

Chaque commande du catalogue d’un profil a un niveau. Le niveau détermine la permission :

NiveauPermissionRôle par défautUne clé d’API peut-elle la détenir ?
basiciot_rpc.send.basicUtilisateurOui
privilegediot_rpc.send.privilegedAdministrateurOui
criticaliot_rpc.send.criticalAdministrateurOui
brut (une méthode absente du catalogue)iot_rpc.send.rawPropriétaireNon

Ainsi, une clé d’API ne peut envoyer que les méthodes présentes dans le catalogue du profil d’appareil.

Envoyer une commande

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

Champs : method (obligatoire, namespace.verb, jusqu’à 64 caractères), params (JSON quelconque, 16 KiB au maximum), oneway, persistent, timeoutMs (1 000 à 600 000 ; par défaut celui du catalogue ou du profil, sinon 10 000), expiresInS (1 à 604 800, pour une commande persistante ; par défaut 86 400), wait, confirm, confirmText, source (api, console ou dashboard_control). Une commande à deux sens, non persistante, avec un délai d’au plus 30 secondes attend sa fin et répond 200 ; sinon elle répond 202 et s’exécute en arrière-plan.

Corps de la requête application/json

{
    "method": "pump.start",
    "params": {
        "speed": 80
    },
    "timeoutMs": 15000
}

Exemple curl

curl -X POST 'https://<your-host>/tenant/{tenantId}/api/iot/devices/{deviceId}/rpc' \
  -H 'Content-Type: application/json' \
  -d '{"method":"pump.start","params":{"speed":80},"timeoutMs":15000}'

Réponses

200OK
{
    "rpc": {
        "rpcId": "c0de…",
        "deviceId": "6f1c…",
        "method": "pump.start",
        "status": "SUCCESSFUL",
        "outcome": null,
        "response": {
            "ok": true
        },
        "error": null,
        "tier": "privileged",
        "highImpact": false,
        "source": "api",
        "createdAt": "2026-11-09T09:00:00.000Z",
        "completedAt": "2026-11-09T09:00:01.200Z",
        "…": "…"
    }
}
202Acceptée
{
    "rpc": {
        "rpcId": "c0de…",
        "status": "QUEUED",
        "…": "…"
    }
}
403Interdit
{
    "message": "You are not permitted to perform this action",
    "code": "FORBIDDEN"
}
409Conflit
{
    "message": "The device is disabled or quarantined; it takes no commands.",
    "code": "CONFLICT",
    "details": {
        "reason": "device_not_active"
    }
}
429Trop de requêtes
{
    "message": "Too many commands to this device; try again in a minute.",
    "code": "RATE_LIMIT_EXCEEDED",
    "details": {
        "reason": "device_rate_limited"
    }
}
  • Sens unique (oneway: true) : la commande réussit lorsqu’elle est livrée ; aucune réponse n’est attendue.
  • Persistante (persistent: true) : si l’appareil est hors ligne, la commande l’attend jusqu’à expiresInS, puis se termine en EXPIRED.
  • wait : true impose l’attente (refusé avec « A synchronous call waits at most 30 s; use wait: false for a longer timeout. » lorsque la commande ne peut pas se terminer en 30 s) ; false répond toujours 202 immédiatement.
  • Commandes à fort impact nécessitent "confirm": true, et la phrase saisie dans confirmText lorsque la commande du catalogue en comporte une. Sans cela : « This command needs confirm: true. » Elles sont inscrites dans le journal d’audit à l’envoi et à leur fin, et sont envoyées au plus une fois.

Cette route n’a pas de clé d’idempotence : chaque POST crée une nouvelle commande. Si votre appel expire sur le réseau, lisez l’historique de l’appareil avant de renvoyer une commande.

États

QUEUED → SENT → DELIVERED → SUCCESSFUL, ou l’un de FAILED, TIMEOUT, EXPIRED, CANCELLED.

ÉtatSignification
SUCCESSFULLa réponse est arrivée, ou une commande à sens unique a été livrée
FAILEDL’appareil l’a refusée, ou elle n’a pas pu être envoyée
TIMEOUTPas de réponse à temps. Le résultat est inconnu : l’appareil a peut-être exécuté la commande. outcome vaut unknown.
EXPIREDElle n’a jamais atteint l’appareil avant son expiration
CANCELLEDAnnulée en file d’attente ou envoyée

outcome apporte un détail : running (l’appareil a accepté une commande de longue durée), unknown (un délai dépassé) ou late (une réponse est arrivée après la fin). Les résultats sont conservés 90 jours par défaut.

Lire les résultats

Interrogez GET /api/iot/rpc/{rpcId} jusqu’à ce que l’état soit final, ou abonnez-vous aux événements webhook rpc.completed et rpc.failed et lisez la réponse à leur réception. Voir la Référence des événements webhook.

Historique d’un appareil, du plus récent au plus ancien :

GET /api/iot/devices/{deviceId}/rpc?status=FAILED&limit=50

Sans page, l’historique se lit avec un curseur : status, method, from, to (dates), limit (1 à 100, par défaut 25) et cursor. La réponse est { "requests": [...], "nextCursor": "…" } ; renvoyez nextCursor comme cursor jusqu’à ce qu’il soit null. Avec page (à partir de 0), la liste suit les règles habituelles des listes : pageSize, search, sort (method, status, source, createdAt, completedAt), status et source sous forme de listes séparées par des virgules, createdFrom, createdTo ; la réponse est { "requests": [...], "total": n }. Les paramètres secrets sont masqués dans toutes les réponses.

Annuler

POST /api/iot/rpc/{rpcId}/cancel fait passer une commande QUEUED ou SENT à CANCELLED et répond { "rpc": {...} }. Autres états : 409 « Only a queued or sent request can be cancelled. » L’annulation exige la même permission de niveau que l’envoi. Une annulation n’envoie aucun webhook.

Limites

LimiteValeur par défaut
Commandes par appareil10 par minute (429, Retry-After: 60)
Commandes par organisation600 par minute (429 « Too many requests for your plan. Please upgrade or try again later. »)
Paramètres16 KiB de JSON
Réponse conservée64 KiB
Commandes par catalogue de profil200

Refus

Statutdetails.reasonMessage
400bad_paramsLes paramètres ne correspondent pas à la commande.
400wait_too_longUn appel synchrone attend 30 s au maximum ; utilisez wait: false pour un délai plus long.
400confirm_required, confirm_text_mismatchCette commande nécessite confirm: true. / La confirmation saisie ne correspond pas.
400method_refusedLa réinitialisation d’usine, l’appairage, l’oubli du Wi-Fi et l’oubli du cloud ne sont jamais envoyés depuis le cloud.
400payload_too_largeLa requête est plus grande que ce que l’appareil accepte.
403rpc_method_reservedLa méthode appartient à un module dédié (par exemple l’accès à distance) et n’est envoyée que par lui ; details.owner nomme le module.
404Appareil introuvable.
409rpc_not_supported_by_profileLe profil d’appareil ne parle que les topics Legacy, qui ne transportent pas de RPC.
409device_not_activeL’appareil est désactivé ou mis en quarantaine.
409not_cancellableSeule une demande en file d’attente ou envoyée peut être annulée.
429device_rate_limitedTrop de commandes adressées à cet appareil ; réessayez dans une minute.

Le catalogue de commandes

Une commande du catalogue comporte : method, label (jusqu’à 120), description, paramsSchema (jusqu’à 50 champs, chacun avec label, type valant text, textarea, number, boolean, select, multi-select ou json, et les options required, min, max, step, options), maskedParams (champs secrets jamais réaffichés), tier (basic, privileged, critical), highImpact, oneway, long, defaultTimeoutMs, persistentDefault, confirmText (impact élevé uniquement).

{
  "method": "valve.set",
  "label": "Set valve position",
  "tier": "privileged",
  "paramsSchema": { "position": { "label": "Position (%)", "type": "number", "min": 0, "max": 100, "required": true } }
}

GET ...?format=export renvoie { "commands": [...] } sans identifiants, que PUT accepte en retour pour copier un catalogue vers un autre profil.