Reference
Alerts
What has happened, and acknowledging or resolving it from the customer’s control room.
List alerts
GET/v1/alerts
Scope alerts:read
Query parameters
site_idstring (uuid)typeAlertTypeWhat has happened.
earthquakeandtsunami_riskconcern the whole plant: they carry noworkerordevice. A nearby vehicle is not an alert: it appears inside an incident’s alert (nearby,vehicle_warnings).Possible values:
sosfall_detectedrestricted_zone_entryforbidden_zone_entrypermit_expired_insidepermit_closed_insideheat_stressevacuation_helpworker_call_requestdevice_offlinelow_batteryearthquaketsunami_riskstatusAlertStatusacknowledged: an operator has taken charge. It is not the same asworker_acknowledged_at, which means the worker has seen the alert on their watch.Possible values:
unacknowledgedacknowledgedresolvedseveritySeverityMinimum severity.
Possible values:
lowmediumhighcriticalsincestring (date-time)untilstring (date-time)limitintegerItems per page (maximum 500).
from 1 to 500 · default 100
cursorstringThe
next_cursorfrom the previous page.
Responses
- 200
Alerts, from the most recent to the oldest.
application/json
AlertPage - 401
The token is missing, has expired or has been revoked.
application/problem+json
Problem - 403
The token lacks the scope the route requires, or the site doesn’t belong to the client.
application/problem+json
Problem - 429
Too many requests, or too much query time: each client has a number of requests per minute (600 by default) and a query time per minute (30 s by default), and each request spends however long it takes, so a long list counts for more than a single alert.
Retry-Aftersays when to retry.application/problem+json
Problem
Request · 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();Response 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"
}Alert detail
GET/v1/alerts/{id}
Scope alerts:read
Path parameters
idstring (uuid)requiredAlert id.
Responses
- 200
The alert.
application/json
Alert - 401
The token is missing, has expired or has been revoked.
application/problem+json
Problem - 403
The token lacks the scope the route requires, or the site doesn’t belong to the client.
application/problem+json
Problem - 404
It doesn’t exist, or this identity can’t see it (another site, another contractor).
application/problem+json
Problem - 429
Too many requests, or too much query time: each client has a number of requests per minute (600 by default) and a query time per minute (30 s by default), and each request spends however long it takes, so a long list counts for more than a single alert.
Retry-Aftersays when to retry.application/problem+json
Problem
Request · 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();Response 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"
}Acknowledge or resolve an alert
PUT/v1/alerts/{id}
Scope alerts:write
The alert’s timeline reads “Client · Operator (via integration)”. Acknowledging is not resolving: an acknowledged alert keeps marking the person on the map until it is resolved.
Path parameters
idstring (uuid)requiredAlert id.
Body application/json AlertUpdate
statusstringrequiredPossible values:
acknowledgedresolvedresolution_reasonstringOn resolving: why. Free text; it goes in the alert’s timeline next to the note.
up to 200 characters
notestringup to 500 characters
Fields of Actor2
namestringrequiredup to 120 characters
external_idstringup to 64 characters
Responses
- 200
The alert, now updated.
application/json
Alert - 401
The token is missing, has expired or has been revoked.
application/problem+json
Problem - 403
The token lacks the scope the route requires, or the site doesn’t belong to the client.
application/problem+json
Problem - 404
It doesn’t exist, or this identity can’t see it.
application/problem+json
Problem - 409
The transition isn’t possible (for example, acknowledging an alert that is already resolved).
application/problem+json
Problem - 422
The body is not valid.
application/problem+json
Problem - 429
Too many requests, or too much query time: each client has a number of requests per minute (600 by default) and a query time per minute (30 s by default), and each request spends however long it takes, so a long list counts for more than a single alert.
Retry-Aftersays when to retry.application/problem+json
Problem
Request · 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();Response 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"
}