Referencia
Alertas
Lo que ha pasado, y reconocerlo o cerrarlo desde la sala del cliente.
Listar alertas
GET/v1/alerts
Scope alerts:read
Parámetros de consulta
site_idstring (uuid)typeAlertTypeQué ha pasado.
earthquakeytsunami_riskson de la planta entera: no llevanworkernidevice. Un vehículo cerca no es una alerta: sale dentro de la alerta de un incidente (nearby,vehicle_warnings).Valores posibles:
sosfall_detectedrestricted_zone_entryforbidden_zone_entrypermit_expired_insidepermit_closed_insideheat_stressevacuation_helpworker_call_requestdevice_offlinelow_batteryearthquaketsunami_riskstatusAlertStatusacknowledged: un operador se ha hecho cargo. No es lo mismo queworker_acknowledged_at, que es que el trabajador ha visto el aviso en su reloj.Valores posibles:
unacknowledgedacknowledgedresolvedseveritySeverityGravedad mínima.
Valores posibles:
lowmediumhighcriticalsincestring (date-time)untilstring (date-time)limitintegerElementos por página (máximo 500).
de 1 a 500 · por defecto 100
cursorstringEl
next_cursorde la página anterior.
Respuestas
- 200
Alertas, de la más reciente a la más antigua.
application/json
AlertPage - 401
Falta el token, ha caducado o se ha revocado.
application/problem+json
Problem - 403
Al token le falta el scope que pide la ruta, o el centro no es del cliente.
application/problem+json
Problem - 429
Demasiadas peticiones, o demasiado tiempo de consulta: cada cliente tiene un número de peticiones por minuto (600 de serie) y un tiempo de consulta por minuto (30 s de serie), y cada petición gasta lo que tarda, así que una lista larga cuenta más que una alerta suelta.
Retry-Afterdice cuándo volver.application/problem+json
Problem
Petición · sandbox
curl "https://sandbox.api.safeonuba.com/v1/alerts" \
-H "Authorization: Bearer $SAFEONUBA_TOKEN"const res = await fetch('https://sandbox.api.safeonuba.com/v1/alerts', {
headers: {
Authorization: `Bearer ${process.env.SAFEONUBA_TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const data = await res.json();import os
import requests
res = requests.get(
"https://sandbox.api.safeonuba.com/v1/alerts",
headers={"Authorization": f"Bearer {os.environ['SAFEONUBA_TOKEN']}"},
timeout=10,
)
res.raise_for_status()
data = res.json()using System.Net.Http.Headers;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("SAFEONUBA_TOKEN"));
var res = await http.GetAsync("https://sandbox.api.safeonuba.com/v1/alerts");
res.EnsureSuccessStatusCode();
var json = await res.Content.ReadAsStringAsync();Respuesta 200
{
"data": [
{
"id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
"type": "sos",
"severity": "critical",
"status": "unacknowledged",
"title": "SOS activado — Ana Ejemplo",
"date_created": "2026-09-24T11:04:12Z",
"date_last_modified": "2026-09-24T11:04:12Z",
"site": {
"id": "11111111-1111-1111-1111-111111111111",
"name": "Planta Ejemplo — simulación"
},
"zone": null,
"worker": {
"id": "33333333-3333-3333-3333-333333333305",
"external_id": "EMP-004512",
"name": "Ana Ejemplo",
"contractor": "Contrata Ejemplo A"
},
"device": {
"id": "44444444-4444-4444-4444-444444444405",
"serial": "OS-W-0005",
"battery": 64,
"date_last_seen": "2026-09-24T11:04:10Z"
},
"location": {
"latitude": 40.00121,
"longitude": -3.00214,
"uncertainty_m": 8,
"source": "gps",
"masked": false,
"position_date_utc": "2026-09-24T11:04:08Z",
"height": null
},
"location_withheld": false,
"details": {
"trigger": "watch_button"
},
"nearby": [
{
"kind": "vehicle",
"worker": {
"id": "33333333-3333-3333-3333-333333333309",
"external_id": "EMP-002210",
"name": "Carlos Ejemplo",
"contractor": "Contrata Ejemplo B"
},
"vehicle_type": "Grúa móvil",
"distance_m": 18,
"reported_at": "2026-09-24T11:04:02Z"
},
{
"kind": "person",
"worker": {
"id": "33333333-3333-3333-3333-333333333301",
"external_id": "EMP-000981",
"name": "Diego Ejemplo",
"contractor": null
},
"vehicle_type": null,
"distance_m": 26,
"reported_at": "2026-09-24T11:03:58Z"
}
],
"vehicle_warnings": [],
"worker_acknowledged_at": null,
"acknowledged": null,
"resolved": null,
"assigned_to": null,
"simulated": false,
"panel_url": "https://app.safeonuba.com/alertas/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90"
}
],
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yNFQxMTowNDoxMloifQ"
}Detalle de una alerta
GET/v1/alerts/{id}
Scope alerts:read
Parámetros de ruta
idstring (uuid)obligatorioId de la alerta.
Respuestas
- 200
La alerta.
application/json
Alert - 401
Falta el token, ha caducado o se ha revocado.
application/problem+json
Problem - 403
Al token le falta el scope que pide la ruta, o el centro no es del cliente.
application/problem+json
Problem - 404
No existe, o esta identidad no la ve (otro centro, otra contrata).
application/problem+json
Problem - 429
Demasiadas peticiones, o demasiado tiempo de consulta: cada cliente tiene un número de peticiones por minuto (600 de serie) y un tiempo de consulta por minuto (30 s de serie), y cada petición gasta lo que tarda, así que una lista larga cuenta más que una alerta suelta.
Retry-Afterdice cuándo volver.application/problem+json
Problem
Petición · sandbox
curl "https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90" \
-H "Authorization: Bearer $SAFEONUBA_TOKEN"const res = await fetch('https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90', {
headers: {
Authorization: `Bearer ${process.env.SAFEONUBA_TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const data = await res.json();import os
import requests
res = requests.get(
"https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
headers={"Authorization": f"Bearer {os.environ['SAFEONUBA_TOKEN']}"},
timeout=10,
)
res.raise_for_status()
data = res.json()using System.Net.Http.Headers;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("SAFEONUBA_TOKEN"));
var res = await http.GetAsync("https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90");
res.EnsureSuccessStatusCode();
var json = await res.Content.ReadAsStringAsync();Respuesta 200
{
"id": "7a1e9c40-52d8-4b0f-a3c6-2e9d81f0b7a4",
"type": "forbidden_zone_entry",
"severity": "high",
"status": "unacknowledged",
"title": "Entrada en zona prohibida — Almacenamiento H₂ (ATEX) — EMP-003318",
"date_created": "2026-09-24T10:12:40Z",
"date_last_modified": "2026-09-24T10:12:40Z",
"site": {
"id": "11111111-1111-1111-1111-111111111111",
"name": "Planta Ejemplo — simulación"
},
"zone": {
"id": "22222222-2222-2222-2222-222222222202",
"name": "Almacenamiento H₂ (ATEX)"
},
"worker": {
"id": "33333333-3333-3333-3333-333333333303",
"external_id": "EMP-003318",
"contractor": "Contrata Ejemplo C"
},
"device": {
"id": "44444444-4444-4444-4444-444444444403",
"serial": "OS-W-0003",
"battery": 81,
"date_last_seen": "2026-09-24T10:12:38Z"
},
"location": {
"latitude": 40.00344,
"longitude": -3.00561,
"uncertainty_m": 5,
"source": "gps",
"masked": false,
"position_date_utc": "2026-09-24T10:12:36Z",
"height": {
"height_m": 7.6,
"uncertainty_m": 1,
"building": "Nave de proceso",
"floor": "Planta 1"
}
},
"location_withheld": false,
"details": {
"zone_type": "forbidden",
"permit_reference": null
},
"nearby": [],
"vehicle_warnings": [],
"worker_acknowledged_at": "2026-09-24T10:12:51Z",
"acknowledged": null,
"resolved": null,
"assigned_to": null,
"simulated": true,
"panel_url": "https://app.safeonuba.com/alertas/7a1e9c40-52d8-4b0f-a3c6-2e9d81f0b7a4"
}{
"id": "c3b58f21-0e7a-4d19-8f6b-5a2c9e417d03",
"type": "heat_stress",
"severity": "high",
"status": "acknowledged",
"title": "Estrés térmico — parar y descansar",
"date_created": "2026-09-24T13:41:05Z",
"date_last_modified": "2026-09-24T13:43:30Z",
"site": {
"id": "11111111-1111-1111-1111-111111111111",
"name": "Planta Ejemplo — simulación"
},
"zone": null,
"worker": {
"id": "33333333-3333-3333-3333-333333333305",
"external_id": "EMP-004512",
"contractor": "Contrata Ejemplo A"
},
"device": {
"id": "44444444-4444-4444-4444-444444444405",
"serial": "OS-W-0005",
"battery": 58,
"date_last_seen": "2026-09-24T13:41:02Z"
},
"location": {
"latitude": 39.99954,
"longitude": -3.00377,
"uncertainty_m": 6,
"source": "gps",
"masked": false,
"position_date_utc": "2026-09-24T13:41:00Z",
"height": null
},
"location_withheld": false,
"details": {
"action": "stop_and_rest",
"heat_index_c": 33,
"sun_exposure_minutes": 91
},
"nearby": [],
"vehicle_warnings": [],
"worker_acknowledged_at": "2026-09-24T13:41:20Z",
"acknowledged": {
"at": "2026-09-24T13:43:30Z",
"by": "Cliente Ejemplo · E. Ejemplo (vía integración)"
},
"resolved": null,
"assigned_to": "Berta Ejemplo",
"simulated": true,
"panel_url": "https://app.safeonuba.com/alertas/c3b58f21-0e7a-4d19-8f6b-5a2c9e417d03"
}{
"id": "5d02c7a9-1b3e-4f80-9c24-6e8a0d1f3b57",
"type": "evacuation_help",
"severity": "critical",
"status": "unacknowledged",
"title": "No puede evacuar: atrapada — EMP-004512",
"date_created": "2026-09-24T11:12:30Z",
"date_last_modified": "2026-09-24T11:12:30Z",
"site": {
"id": "11111111-1111-1111-1111-111111111111",
"name": "Planta Ejemplo — simulación"
},
"zone": null,
"worker": {
"id": "33333333-3333-3333-3333-333333333305",
"external_id": "EMP-004512",
"contractor": "Contrata Ejemplo A"
},
"device": {
"id": "44444444-4444-4444-4444-444444444405",
"serial": "OS-W-0005",
"battery": 61,
"date_last_seen": "2026-09-24T11:12:28Z"
},
"location": {
"latitude": 39.99871,
"longitude": -2.99905,
"uncertainty_m": 12,
"source": "network",
"masked": false,
"position_date_utc": "2026-09-24T11:12:25Z",
"height": null
},
"location_withheld": false,
"details": {
"reason": "trapped",
"muster_id": "14df4773-88a3-4df5-811e-81cdc8ef12bb"
},
"nearby": [],
"vehicle_warnings": [],
"worker_acknowledged_at": null,
"acknowledged": null,
"resolved": null,
"assigned_to": null,
"simulated": false,
"panel_url": "https://app.safeonuba.com/alertas/5d02c7a9-1b3e-4f80-9c24-6e8a0d1f3b57"
}{
"id": "9e4f1a6b-2c3d-4e5f-8a9b-0c1d2e3f4a5b",
"type": "low_battery",
"severity": "medium",
"status": "unacknowledged",
"title": "Batería baja — EMP-002210",
"date_created": "2026-09-24T15:20:00Z",
"date_last_modified": "2026-09-24T15:20:00Z",
"site": {
"id": "11111111-1111-1111-1111-111111111111",
"name": "Planta Ejemplo — simulación"
},
"zone": null,
"worker": {
"id": "33333333-3333-3333-3333-333333333309",
"external_id": "EMP-002210",
"contractor": "Contrata Ejemplo B"
},
"device": {
"id": "44444444-4444-4444-4444-444444444409",
"serial": "OS-W-0009",
"battery": 12,
"date_last_seen": "2026-09-24T15:19:55Z"
},
"location": null,
"location_withheld": true,
"details": {
"battery_pct": 12
},
"nearby": [],
"vehicle_warnings": [],
"worker_acknowledged_at": null,
"acknowledged": null,
"resolved": null,
"assigned_to": null,
"simulated": true,
"panel_url": "https://app.safeonuba.com/alertas/9e4f1a6b-2c3d-4e5f-8a9b-0c1d2e3f4a5b"
}Reconocer o cerrar una alerta
PUT/v1/alerts/{id}
Scope alerts:write
La cronología de la alerta escribe «Cliente · Operador (vía integración)». Reconocer no es cerrar: una alerta reconocida sigue marcando a la persona en el mapa hasta que se cierra.
Parámetros de ruta
idstring (uuid)obligatorioId de la alerta.
Cuerpo application/json AlertUpdate
statusstringobligatorioValores posibles:
acknowledgedresolvedresolution_reasonstringAl cerrar: por qué. Texto libre; va a la cronología de la alerta junto a la nota.
hasta 200 caracteres
notestringhasta 500 caracteres
Campos de Actor2
namestringobligatoriohasta 120 caracteres
external_idstringhasta 64 caracteres
Respuestas
- 200
La alerta, ya actualizada.
application/json
Alert - 401
Falta el token, ha caducado o se ha revocado.
application/problem+json
Problem - 403
Al token le falta el scope que pide la ruta, o el centro no es del cliente.
application/problem+json
Problem - 404
No existe, o esta identidad no la ve.
application/problem+json
Problem - 409
La transición no es posible (por ejemplo, reconocer una alerta ya cerrada).
application/problem+json
Problem - 422
El cuerpo no es válido.
application/problem+json
Problem - 429
Demasiadas peticiones, o demasiado tiempo de consulta: cada cliente tiene un número de peticiones por minuto (600 de serie) y un tiempo de consulta por minuto (30 s de serie), y cada petición gasta lo que tarda, así que una lista larga cuenta más que una alerta suelta.
Retry-Afterdice cuándo volver.application/problem+json
Problem
Petición · sandbox
curl -X PUT "https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90" \
-H "Authorization: Bearer $SAFEONUBA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "acknowledged",
"actor": {
"name": "E. Ejemplo"
}
}'const res = await fetch('https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.SAFEONUBA_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"status": "acknowledged",
"actor": {
"name": "E. Ejemplo"
}
}),
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const data = await res.json();import os
import requests
res = requests.put(
"https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
headers={"Authorization": f"Bearer {os.environ['SAFEONUBA_TOKEN']}"},
json={
"status": "acknowledged",
"actor": {
"name": "E. Ejemplo",
},
},
timeout=10,
)
res.raise_for_status()
data = res.json()using System.Net.Http.Headers;
using System.Text;
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("SAFEONUBA_TOKEN"));
var contenido = new StringContent("""
{
"status": "acknowledged",
"actor": {
"name": "E. Ejemplo"
}
}
""", Encoding.UTF8, "application/json");
var res = await http.PutAsync("https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90", contenido);
res.EnsureSuccessStatusCode();
var json = await res.Content.ReadAsStringAsync();Respuesta 200
{
"id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
"type": "sos",
"severity": "critical",
"status": "unacknowledged",
"title": "SOS activado — Ana Ejemplo",
"date_created": "2026-09-24T11:04:12Z",
"date_last_modified": "2026-09-24T11:04:12Z",
"site": {
"id": "11111111-1111-1111-1111-111111111111",
"name": "Planta Ejemplo — simulación"
},
"zone": null,
"worker": {
"id": "33333333-3333-3333-3333-333333333305",
"external_id": "EMP-004512",
"name": "Ana Ejemplo",
"contractor": "Contrata Ejemplo A"
},
"device": {
"id": "44444444-4444-4444-4444-444444444405",
"serial": "OS-W-0005",
"battery": 64,
"date_last_seen": "2026-09-24T11:04:10Z"
},
"location": {
"latitude": 40.00121,
"longitude": -3.00214,
"uncertainty_m": 8,
"source": "gps",
"masked": false,
"position_date_utc": "2026-09-24T11:04:08Z",
"height": null
},
"location_withheld": false,
"details": {
"trigger": "watch_button"
},
"nearby": [
{
"kind": "vehicle",
"worker": {
"id": "33333333-3333-3333-3333-333333333309",
"external_id": "EMP-002210",
"name": "Carlos Ejemplo",
"contractor": "Contrata Ejemplo B"
},
"vehicle_type": "Grúa móvil",
"distance_m": 18,
"reported_at": "2026-09-24T11:04:02Z"
},
{
"kind": "person",
"worker": {
"id": "33333333-3333-3333-3333-333333333301",
"external_id": "EMP-000981",
"name": "Diego Ejemplo",
"contractor": null
},
"vehicle_type": null,
"distance_m": 26,
"reported_at": "2026-09-24T11:03:58Z"
}
],
"vehicle_warnings": [],
"worker_acknowledged_at": null,
"acknowledged": null,
"resolved": null,
"assigned_to": null,
"simulated": false,
"panel_url": "https://app.safeonuba.com/alertas/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90"
}