# Alerts · Reference

> What has happened, and acknowledging or resolving it from the customer’s control room.

Page: https://safeonuba.com/en/developers/reference/alerts · SafeOnuba API v1 (`api_version: "2026-09-24"`), in preview: the contract may change.

## List alerts

`GET /v1/alerts` · scope `alerts:read` · [see it on the web](https://safeonuba.com/en/developers/reference/alerts#listAlerts)

### Query parameters

- `site_id` (string (uuid))
- `type` (AlertType): What has happened. `earthquake` and `tsunami_risk` concern the whole plant: they carry no `worker` or `device`. A nearby vehicle is **not** an alert: it appears inside an incident’s alert (`nearby`, `vehicle_warnings`). Values: `sos`, `fall_detected`, `restricted_zone_entry`, `forbidden_zone_entry`, `permit_expired_inside`, `permit_closed_inside`, `heat_stress`, `evacuation_help`, `worker_call_request`, `device_offline`, `low_battery`, `earthquake`, `tsunami_risk`.
- `status` (AlertStatus): `acknowledged`: an operator has taken charge. It is not the same as `worker_acknowledged_at`, which means the worker has seen the alert on their watch. Values: `unacknowledged`, `acknowledged`, `resolved`.
- `severity` (Severity): Minimum severity. Values: `low`, `medium`, `high`, `critical`.
- `since` (string (date-time))
- `until` (string (date-time))
- `limit` (integer): Items per page (maximum 500). (from 1 to 500, default 100)
- `cursor` (string): The `next_cursor` from the previous page.

### Responses

- `200`: Alerts, from the most recent to the oldest. → `AlertPage` (`application/json`)
- `401`: The token is missing, has expired or has been revoked. → `Problem` (`application/problem+json`)
- `403`: The token lacks the scope the route requires, or the site doesn’t belong to the client. → `Problem` (`application/problem+json`)
- `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-After` says when to retry. → `Problem` (`application/problem+json`)

### Example request (sandbox)

```bash
curl "https://sandbox.api.safeonuba.com/v1/alerts" \
  -H "Authorization: Bearer $SAFEONUBA_TOKEN"
```

### Example response (`200`)

```json
{
  "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` · [see it on the web](https://safeonuba.com/en/developers/reference/alerts#getAlert)

### Path parameters

- `id` (string (uuid), required): Alert id.

### Responses

- `200`: The alert. → `Alert` (`application/json`)
- `401`: The token is missing, has expired or has been revoked. → `Problem` (`application/problem+json`)
- `403`: The token lacks the scope the route requires, or the site doesn’t belong to the client. → `Problem` (`application/problem+json`)
- `404`: It doesn’t exist, or this identity can’t see it (another site, another contractor). → `Problem` (`application/problem+json`)
- `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-After` says when to retry. → `Problem` (`application/problem+json`)

### Example request (sandbox)

```bash
curl "https://sandbox.api.safeonuba.com/v1/alerts/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90" \
  -H "Authorization: Bearer $SAFEONUBA_TOKEN"
```

### Example response (`200`)

```json
{
  "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"
}
```

## Acknowledge or resolve an alert

`PUT /v1/alerts/{id}` · scope `alerts:write` · [see it on the web](https://safeonuba.com/en/developers/reference/alerts#updateAlert)

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

- `id` (string (uuid), required): Alert id.

### Body (`application/json`, schema `AlertUpdate`)

- `status` (string, required) Values: `acknowledged`, `resolved`.
- `resolution_reason` (string): On resolving: why. Free text; it goes in the alert’s timeline next to the note. (up to 200 characters)
- `note` (string) (up to 500 characters)
- `actor` (Actor, required)
  - `name` (string, required) (up to 120 characters)
  - `external_id` (string) (up to 64 characters)

### Responses

- `200`: The alert, now updated. → `Alert` (`application/json`)
- `401`: The token is missing, has expired or has been revoked. → `Problem` (`application/problem+json`)
- `403`: The token lacks the scope the route requires, or the site doesn’t belong to the client. → `Problem` (`application/problem+json`)
- `404`: It doesn’t exist, or this identity can’t see it. → `Problem` (`application/problem+json`)
- `409`: The transition isn’t possible (for example, acknowledging an alert that is already resolved). → `Problem` (`application/problem+json`)
- `422`: The body is not valid. → `Problem` (`application/problem+json`)
- `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-After` says when to retry. → `Problem` (`application/problem+json`)

### Example request (sandbox)

```bash
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"
  }
}'
```

### Example response (`200`)

```json
{
  "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"
}
```
