Esta página enumera los eventos de IoT a los que puede suscribirse un webhook y los data que transporta cada uno. El envoltorio alrededor de data, las cabeceras y la firma se describen en Webhooks. La lista de eventos disponibles para su organización también está disponible en GET /api/webhooks/events.
Reglas generales:
- Los payloads solo contienen identificadores y campos seguros. Nunca se envía una credencial de dispositivo, token, contraseña, certificado ni enlace de descarga.
- Las horas son texto ISO 8601 en UTC, excepto las horas de alarma, que son milisegundos desde la época.
- Los eventos pueden llegar desordenados y, en raras ocasiones, dos veces. Deduplique por
X-Webhook-Deliveryy ordene por las horas del payload. - Los ejemplos muestran solo el
eventy eldatadel envoltorio; el envoltorio completo también incluyewebhookId,tenantIdycreatedAt.
Dispositivos
| Evento | Se envía cuando |
|---|---|
device.created | Se añadió un dispositivo: manualmente, desde una importación, por aprovisionamiento o reclamación, o como hijo de una pasarela |
device.updated | Cambiaron el nombre, la etiqueta, el tipo, el perfil, la marca de pasarela, la información adicional o el estado |
device.deleted | Se eliminó un dispositivo (manualmente, por una liberación o al deshacer una importación) |
device.credentials_rotated | La credencial fue rotada, reemplazada, renovada (X.509) o revocada |
device.connected | Un dispositivo se conectó y permaneció conectado durante el tiempo de retención |
device.disconnected | Un dispositivo se desconectó y permaneció desconectado durante el tiempo de retención |
{ "event": "device.created", "data": {
"deviceId": "6f1c…", "name": "pump-station-04", "serial": null, "profileId": "a1b2…",
"status": "ACTIVE", "isGateway": false, "createdAt": "2026-11-09T08:00:00.000Z" } }
Un hijo de una pasarela también incluye gatewayDeviceId.
{ "event": "device.updated", "data": {
"deviceId": "6f1c…", "name": "pump-station-04", "serial": null, "profileId": "a1b2…",
"status": "DISABLED", "isGateway": false, "changedFields": ["status"], "previousStatus": "ACTIVE",
"updatedAt": "2026-11-09T08:10:00.000Z" } }
changedFields indica solo los nombres de los campos (ordenados: additionalInfo, isGateway, label, name, profileId, status, type), nunca sus valores. previousStatus está presente solo cuando cambió el estado. Una edición que no cambia ninguno de estos campos no envía nada.
{ "event": "device.deleted", "data": {
"deviceId": "6f1c…", "name": "pump-station-04", "serial": null, "profileId": "a1b2…",
"credentialRevoked": true, "deletedAt": "2026-11-09T08:20:00.000Z" } }
{ "event": "device.credentials_rotated", "data": {
"deviceId": "6f1c…", "name": "pump-station-04", "serial": null, "profileId": "a1b2…",
"change": "rotated", "credentialType": "ACCESS_TOKEN", "previousType": "ACCESS_TOKEN",
"changedAt": "2026-11-09T08:30:00.000Z" } }
change es rotated, replaced, renewed o revoked; tras revoked, credentialType es null.
{ "event": "device.connected", "data": {
"deviceId": "6f1c…", "name": "router-17", "profileId": "a1b2…", "transport": "mqtts",
"connectedAt": "2026-11-03T10:00:00.000Z", "remoteIpPrefix": "203.0.113.0/24" } }
{ "event": "device.disconnected", "data": {
"deviceId": "6f1c…", "name": "router-17", "profileId": "a1b2…", "reason": "timeout",
"disconnectedAt": "2026-11-03T12:00:00.000Z", "lastSeenAt": "2026-11-03T11:59:40.000Z", "onlineSeconds": 7200 } }
remoteIpPrefix es el /24 de una dirección IPv4 o el /48 de una dirección IPv6, nunca la dirección completa. reason es clean (el dispositivo se desconectó), timeout (se agotó su ventana de keep-alive o de uplink), kicked (el servidor lo cerró, por ejemplo tras un cambio de credencial) o quota (alcanzó un límite).
Tiempo de retención y volumen. Un cambio de conexión solo se envía después de mantenerse durante el tiempo de retención: Dispositivos > ajustes > Connection webhooks: hold time (seconds), por defecto 30, de 5 a 3.600. Un dispositivo que se cae y vuelve dentro de ese tiempo no envía nada. Por defecto se envían como máximo 600 eventos de conexión y 600 eventos de cambio de dispositivo por organización y minuto; el resto de ese minuto se descarta y sus propietarios y administradores reciben un aviso. Los dispositivos siguen siendo legibles a través de la API.
Alarmas
| Evento | Se envía cuando |
|---|---|
alarm.created | Se abrió una alarma (una regla de perfil, un bloque de flujo o un operador). No se envía cuando una alarma abierta vuelve a activarse. |
alarm.acknowledged | Un operador o un flujo reconoció una alarma abierta. Permanece abierta. |
alarm.cleared | Una alarma se resolvió: por su regla o flujo, por un operador, o porque se eliminó su dispositivo |
{ "event": "alarm.created", "data": {
"alarmId": "9a7e…", "type": "high_temperature", "severity": "CRITICAL",
"originator": { "type": "DEVICE", "id": "6f1c…", "name": "cold-room-2" },
"deviceId": "6f1c…", "profileId": "a1b2…", "url": "/admin/iot/alarms/9a7e…",
"title": "Temperature too high", "startedAt": 1762678800000, "openedAt": 1762678800000,
"details": { "temperature": 9.4 }, "backfilled": false, "metadata": { "topic": null } } }
{ "event": "alarm.acknowledged", "data": {
"alarmId": "9a7e…", "type": "high_temperature", "severity": "CRITICAL", "originator": { "…": "…" },
"deviceId": "6f1c…", "profileId": "a1b2…", "url": "/admin/iot/alarms/9a7e…",
"ackBy": { "userId": "u-55…" }, "ackAt": 1762679100000 } }
{ "event": "alarm.cleared", "data": {
"alarmId": "9a7e…", "type": "high_temperature", "severity": "CRITICAL", "originator": { "…": "…" },
"deviceId": "6f1c…", "profileId": "a1b2…", "url": "/admin/iot/alarms/9a7e…",
"clearedBy": "rule", "reason": "clear", "clearedAt": 1762680000000, "durationSeconds": 1200,
"metadata": { "topic": null } } }
urles la página de la alarma en la aplicación; anteponga su host y/tenant/<tenantId>.backfilled: truemarca una alarma abierta por lecturas tardías (por ejemplo, tras reproducir el buffer de una pasarela). Para estas no se notifica a nadie.clearedByes"rule"o{ "userId": "…" };reasonesclear,manualooriginator_deleted.metadataesnullcuando una persona la resolvió.- Un cambio de severidad de una alarma abierta no envía webhook. Los webhooks de alarmas no tienen límite de volumen; el límite de tasa de su endpoint sigue aplicando.
Comandos
| Evento | Se envía cuando |
|---|---|
rpc.completed | Un comando terminó SUCCESSFUL (respondido, o un comando unidireccional fue entregado) |
rpc.failed | Un comando terminó FAILED, TIMEOUT (resultado desconocido) o EXPIRED (nunca llegó al dispositivo) |
{ "event": "rpc.failed", "data": {
"rpcId": "c0de…", "deviceId": "6f1c…", "method": "pump.start", "status": "TIMEOUT",
"error": null, "source": "api", "completedAt": "2026-11-09T09:00:15.000Z" } }
La respuesta en sí no está en el payload: léala con GET /api/iot/rpc/{rpcId}. Un comando cancelado no envía nada.
Firmware
| Evento | Se envía cuando |
|---|---|
ota.update.initiated | Se entregó a un dispositivo un paquete de firmware para instalar |
ota.update.succeeded | Un dispositivo ejecuta la versión objetivo |
ota.update.failed | La actualización falló, agotó el tiempo o se revirtió |
ota.rollout.wave_completed | Una oleada superó sus controles |
ota.rollout.paused | Un control falló o una persona pausó el despliegue |
ota.rollout.resumed | Una persona reanudó el despliegue |
ota.rollout.completed | La última oleada superó sus controles |
ota.rollout.aborted | Una persona lo canceló, su asignación fue eliminada o reemplazada, o su paquete fue revocado |
{ "event": "ota.update.failed", "data": {
"deviceId": "6f1c…", "packageId": "f00d…", "title": "router-fw", "version": "2.5.0", "fromVersion": "2.4.1",
"state": "FAILED", "attempts": 1, "at": "2026-11-09T10:00:00.000Z", "stage": "verify", "error": "…" } }
stage es download, verify, update o rollback; error es el código del dispositivo, o un tiempo agotado.
{ "event": "ota.rollout.paused", "data": {
"rolloutId": "r-12…", "assignmentId": "as-3…", "packageId": "f00d…", "status": "PAUSED", "wave": 2, "waves": 3,
"at": "2026-11-09T11:00:00.000Z", "reason": "failure_gate", "failures": 4, "failurePct": 6.7, "successPct": 88.3 } }
Los payloads de despliegue incluyen rolloutId, assignmentId, packageId, status, wave (desde 1), waves y at, además de: updated, failures, successPct (oleada completada); reason y los recuentos (pausado; reason es failure_gate, success_gate, no_result (ningún dispositivo terminó) o manual); pausedReason (reanudado); updated (completado); reason (cancelado).
Aprovisionamiento
| Evento | Se envía cuando |
|---|---|
iot.device.claimed | Un dispositivo licenciado fue reclamado para su organización |
iot.device.released | Un dispositivo volvió al pool de fábrica: kind OWNER (usted lo liberó), FORCED (soporte de la plataforma) o DEVICE (desde la página propia del dispositivo) |
{ "event": "iot.device.claimed", "data": {
"deviceId": "6f1c…", "serial": "RT-0017", "model": "…", "claimedAt": "2026-11-09T07:00:00.000Z", "claimedByUserId": "u-55…" } }
{ "event": "iot.device.released", "data": {
"deviceId": "6f1c…", "serial": "RT-0017", "model": "…", "kind": "OWNER", "releasedAt": "2026-11-09T07:30:00.000Z" } }
Reglas
| Evento | Se envía cuando |
|---|---|
rules.mode_changed | Un lugar pasó a Manual, volvió a Auto, o su Manual terminó por sí solo |
rules.needs_attention | Una regla se desactivó porque un dispositivo o el lugar que menciona ya no existe |
{ "event": "rules.mode_changed", "data": {
"placeType": "asset", "placeId": "77aa…", "placeName": "Greenhouse 2", "mode": "manual", "change": "manual",
"actorId": "u-55…", "until": 1762700000000, "reason": "Harvest" } }
change es manual, auto o expired; actorId es null cuando un Manual terminó por sí solo. Un cambio de vuelta a Auto también incluye applyNow y rearmed.
{ "event": "rules.needs_attention", "data": {
"ruleId": "ru-9…", "name": "Close vents at night", "reason": "…",
"home": { "type": "asset", "id": "77aa…" } } }
Flujos
automation.message solo lo envía el bloque Webhook de un flujo, y únicamente al endpoint que indica el bloque (que debe suscribirse a «Automation message»). Incluye topic, payload, originator, flowId, flowVersion, nodeId, actor y las claves de metadata que lista el bloque, con X-Idempotency-Key. Véase Bloques de acción.
Otros eventos
esim.operation.succeededyesim.operation.failedpertenecen a la gestión de eSIM, que está en desarrollo.- También se ofrecen eventos de claves de API (
api_key.created,api_key.updated,api_key.rotated,api_key.deleted,api_key.expired) y de organización (miembros, invitaciones, suscripción). Sus payloads no se detallan en esta página.

