v1 · preview

Try webhook signature, alert.created, location_withheld or 429.

↑ ↓ moveEnter openEsc close

Reference

Webhooks

Destinations and the format of what is sent to them.

List destinations

GET/v1/webhooks

Scope webhooks:manage

Responses

  • 200

    Destinations.

    application/json WebhookEndpointList

  • 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-After says when to retry.

    application/problem+json Problem

Request · sandbox

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

Response 200

JSON
{
  "data": [
    {
      "id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
      "url": "string",
      "event_types": [
        "alert.created"
      ],
      "filters": {
        "site_ids": [
          "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90"
        ],
        "min_severity": "low",
        "contractors": [
          "string"
        ]
      },
      "is_active": false,
      "failing_since": "2026-09-24T11:04:12Z",
      "created_at": "2026-09-24T11:04:12Z"
    }
  ]
}

Create a destination

POST/v1/webhooks

Scope webhooks:manage

Body application/json WebhookEndpointCreate

  • urlstringrequired
  • event_typesarray<EventType | "alert.*" | "muster.*">required
  • filtersobject
    Fields3
    • site_idsarray<string (uuid)>
    • min_severitySeverity

      Possible values: lowmediumhighcritical

    • contractorsarray<string>

Responses

  • 201

    Destination created, with its signing secret (this once only).

    application/json WebhookEndpointCreated

  • 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

  • 422

    The body is not valid (the URL must be https).

    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-After says when to retry.

    application/problem+json Problem

Request · sandbox

curl -X POST "https://sandbox.api.safeonuba.com/v1/webhooks" \
  -H "Authorization: Bearer $SAFEONUBA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://sala.cliente.example/safeonuba",
  "event_types": [
    "alert.*",
    "muster.*"
  ]
}'

Response 201

JSON
{
  "id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
  "url": "string",
  "event_types": [
    "alert.created"
  ],
  "filters": {
    "site_ids": [
      "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90"
    ],
    "min_severity": "low",
    "contractors": [
      "string"
    ]
  },
  "is_active": false,
  "failing_since": "2026-09-24T11:04:12Z",
  "created_at": "2026-09-24T11:04:12Z",
  "secret": "whsec_6f1c0d9e2b7a4c3f8e5d1a0b9c8e7f6a"
}

Delete a destination

DEL/v1/webhooks/{id}

Scope webhooks:manage

Path parameters

  • idstring (uuid)required

    Destination id.

Responses

  • 204

    Deleted.

  • 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.

    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-After says when to retry.

    application/problem+json Problem

Request · sandbox

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

Response 204

JSON
HTTP 204

Rotate the signing secret

POST/v1/webhooks/{id}/rotate-secret

Scope webhooks:manage

Issues a new secret. The previous one keeps signing for 24 h: during that time every delivery carries both signatures in X-SafeOnuba-Signature, separated by a comma, so the receiver can change secret without interruption. A second rotation retires the first: there are never more than two.

Path parameters

  • idstring (uuid)required

    Destination id.

Responses

  • 200

    The new secret (this once only) and until when the previous one signs.

    application/json WebhookSecretRotated

  • 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.

    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-After says when to retry.

    application/problem+json Problem

Request · sandbox

curl -X POST "https://sandbox.api.safeonuba.com/v1/webhooks/0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90/rotate-secret" \
  -H "Authorization: Bearer $SAFEONUBA_TOKEN"

Response 200

JSON
{
  "secret": "whsec_6f1c0d9e2b7a4c3f8e5d1a0b9c8e7f6a",
  "previous_valid_until": "2026-09-24T11:04:12Z"
}

Send a test event

POST/v1/webhooks/{id}/test

Scope webhooks:manage

Sends an alert.created marked simulated: true, signed like a real one.

Path parameters

  • idstring (uuid)required

    Destination id.

Responses

  • 202

    Queued: the result shows on the destination (failing_since).

  • 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.

    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-After says when to retry.

    application/problem+json Problem

Request · sandbox

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

Response 202

JSON
HTTP 202

What your destination receives

Each event reaches your URL as a POST with this body. Both groups share the format: what changes is what goes inside data.

Changes to an alert

POSTYour destination · alert.*

Your destination receives it; it’s signed and carries no token.

One POST per event to each subscribed destination, with the complete object.

Headers: X-SafeOnuba-Event-Id, X-SafeOnuba-Timestamp (Unix seconds) and X-SafeOnuba-Signature: v1=<hex(HMAC_SHA256(secret, timestamp + "." + body))>. Reject anything more than 5 min out of sync. During a rotation two signatures arrive, separated by a comma.

Acknowledgement: any 2xx in under 5 s. Retries at 10 s, 30 s, 2 min, 10 min, 30 min, 1 h and then every hour up to 24 h. “At least once” delivery (deduplicate by id) and no guaranteed order (use date_last_modified). SOS, falls, “I can’t evacuate” and evacuations go out before the rest.

Body application/json Event

  • idstring (uuid)required

    For deduplication: delivery is “at least once”.

  • typeEventTyperequired

    Possible values: alert.createdalert.acknowledgedalert.resolvedalert.reopenedalert.worker_acknowledgedmuster.startedmuster.kind_changedmuster.phase_changedmuster.targets_changedmuster.updatedmuster.worker_missingmuster.ended

  • api_versionstringrequired

    Possible values: 2026-09-24

  • created_atstring (date-time)required
  • organization_idstring (uuid) | nullrequired

    The site’s company. null in test events.

  • site_idstring (uuid)required
  • data{ alert } | { muster }required

    The complete object exactly as the GET would return it at that moment.

    One of 2 shapes
    • variant 1
      • alertAlertrequired
        Fields of Alert22
        • idstring (uuid)required
        • typeAlertTyperequired

          Possible values: sosfall_detectedrestricted_zone_entryforbidden_zone_entrypermit_expired_insidepermit_closed_insideheat_stressevacuation_helpworker_call_requestdevice_offlinelow_batteryearthquaketsunami_risk

        • severitySeverityrequired

          Possible values: lowmediumhighcritical

        • statusAlertStatusrequired

          Possible values: unacknowledgedacknowledgedresolved

        • titlestringrequired

          With include_worker_names, the title the control room reads (it carries the person’s name). Without it, one composed of the type, the zone and the external_id, with no name.

        • date_createdstring (date-time)required
        • date_last_modifiedstring (date-time)required

          For ordering: webhooks don’t guarantee order, and anything older than what you already have is discarded.

        • siteSiteRefrequired
          Fields of SiteRef2
          • idstring (uuid)required
          • namestringrequired
        • zoneZoneRefrequired
          Fields of ZoneRef2
          • idstring (uuid)required
          • namestringrequired
        • workerWorkerRefrequired
          Fields of WorkerRef4
          • idstring (uuid)required
          • external_idstring | nullrequired

            The worker’s code at the company (the one in its personnel system). null if not given.

          • namestring

            Full name. Only if the contract includes it; otherwise the property doesn’t appear.

          • contractorstring | nullrequired
        • deviceDeviceRefrequired
          Fields of DeviceRef4
          • idstring (uuid)required
          • serialstringrequired
          • batteryinteger | nullrequired

            from 0 to 100

          • date_last_seenstring (date-time) | nullrequired
        • locationLocationrequired
          Fields of Location7
          • latitudenumberrequired

            from -90 to 90

          • longitudenumberrequired

            from -180 to 180

          • uncertainty_mnumber | nullrequired

            Uncertainty radius in metres. null if unknown: not knowing it is not the same as it being perfect.

            minimum 0

          • sourcestringrequired

            zone: the person was in a privacy zone and the point is the zone’s, not theirs.

            Possible values: gpsnetworkzone

          • maskedbooleanrequired

            The point is the representative one for a privacy zone.

          • position_date_utcstring (date-time)required
          • heightobject | nullrequired

            Height above ground by barometer, when it can be stated; null if not.

        • location_withheldbooleanrequired

          The position exists but is not delivered: in “emergencies only”, an alert below the severity that lifts the veil doesn’t show it, and neither does the dashboard.

        • detailsAlertDetailsrequired
          One of 9 shapes
            • triggerstringrequired

              How it was requested: on the watch screen, with the physical button, after an unanswered fall, or from the control room.

              Possible values: watch_buttonwatch_hardware_buttonafter_fallcontrol_room

            • escalated_to_sosbooleanrequired

              Did not answer the watch’s “Are you OK?” and it escalated to SOS.

            • zone_typestringrequired

              Possible values: restrictedforbidden

            • permit_referencestring | nullrequired

              The permit to work (job safety analysis, JSA) in force, if there was one.

          • Nothing derived from heart rate: vital signs don’t leave through the API, not even aggregated.

            • actionstringrequired

              What the watch has told them: stop, drink and find shade. There are no levels.

              Possible values: stop_and_rest

            • heat_index_cnumber | nullrequired

              The plant’s heat index (°C).

            • sun_exposure_minutesinteger | nullrequired
            • reasonstring | nullrequired

              What they said on the watch: trapped, injured or helping someone else.

              Possible values: trappedinjuredhelping

            • muster_idstring (uuid)required
            • voice_notebooleanrequired

              With no coverage, the watch recorded a voice message (it can be heard in the dashboard).

            • minutes_silentintegerrequired
            • battery_pctintegerrequired

              from 0 to 100

            • magnitudenumber | nullrequired
            • distance_kmnumber | nullrequired
            • officialbooleanrequired

              false: a SafeOnuba estimate with no official warning. true: an official bulletin confirmed by a person.

            • felt_at_sitebooleanrequired
            • etastring (date-time) | nullrequired

              Estimated arrival of the wave (tsunami).

        • nearbyarray<Nearby>required
          Fields of Nearby5
          • kindstringrequired

            Possible values: personvehicle

          • workerobjectrequired
          • vehicle_typestring | nullrequired
          • distance_mintegerrequired
          • reported_atstring (date-time)required
        • vehicle_warningsarray<VehicleWarning>required
          Fields of VehicleWarning4
          • atstring (date-time)required
          • vehicle_typestring | nullrequired
          • distance_mintegerrequired
          • worker_acknowledged_atstring (date-time) | nullrequired
        • worker_acknowledged_atstring (date-time) | nullrequired

          The worker pressed “Got it” on their watch (watch time).

        • acknowledgedActionByrequired
          Fields of ActionBy2
          • atstring (date-time)required
          • bystringrequired

            Who: a person from the dashboard, or “Client · Operator (via integration)”.

        • resolvedobject | nullrequired

          Resolved: by whom, when and with what note.

          Fields3
          • atstring (date-time)required
          • bystringrequired

            Who: a person from the dashboard, or “Client · Operator (via integration)”.

          • notestring | nullrequired
        • assigned_tostring | nullrequired
        • simulatedbooleanrequired

          Raised in a drill or with simulated watches.

        • panel_urlstring (uri)required
    • variant 2
      • musterMusterrequired
        Fields of Muster13
        • idstring (uuid)required
        • siteSiteRefrequired
          Fields of SiteRef2
          • idstring (uuid)required
          • namestringrequired
        • statusstringrequired

          Possible values: activecompletedcancelled

        • phasestringrequired

          inspecting: headcount complete and the control room is checking the plant; watches say “do not go back until further notice”.

          Possible values: evacuatinginspecting

        • kindMusterKindrequired

          Possible values: generaltsunamiearthquake

        • reasonstring | nullrequired
        • started_atstring (date-time)required
        • ended_atstring (date-time) | nullrequired
        • deadlineobject | nullrequired
          Fields2
          • atstring (date-time)required
          • sourcestringrequired

            Tsunami: the time of an official warning, or the ceiling in the zone’s plan. Never a physical calculation.

            Possible values: officialplan_estimate

        • originobject | nullrequired

          Where the emergency comes from. null in an evacuation with no origin (a general drill).

          Fields5
          • latitudenumberrequired
          • longitudenumberrequired
          • radius_mintegerrequired
          • labelstring | nullrequired
          • zoneZoneRefrequired
        • targets_revisionintegerrequired

          Goes up every time the targets change (ruling out, restoring, change of type).

        • totalsobjectrequired

          The same figures as the dashboard banner and the closing summary: the server counts them. In an ended evacuation, what remains is what was recorded on ending —arrived and total— and the rest comes out as null.

          Fields7
          • expectedintegerrequired
          • safeintegerrequired
          • helpinteger | nullrequired
          • wrong_pointinteger | nullrequired
          • pendinginteger | nullrequired
          • no_signalinteger | nullrequired
          • not_worninteger | nullrequired
        • assembly_pointsarray<AssemblyPoint>required

          The targets for the type, ruled-out ones included.

          Fields of AssemblyPoint5
          • idstring (uuid)required
          • namestringrequired
          • statusstringrequired

            Possible values: availableexcluded

          • countinteger | nullrequired

            People safe at this point. null in an ended evacuation: on ending, only the total is kept.

          • excludedobject | nullrequired

Responses

  • 200

    Received. Any 2xx will do.

Body your destination receives

Event
{
  "id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
  "type": "alert.created",
  "api_version": "2026-09-24",
  "created_at": "2026-09-24T11:04:12Z",
  "organization_id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
  "site_id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
  "data": {
    "alert": {
      "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"
    }
  }
}

How to check it comes from SafeOnuba: verify the signature.

Changes to an evacuation

POSTYour destination · muster.*

Your destination receives it; it’s signed and carries no token.

One POST per event to each subscribed destination, with the complete object.

Headers: X-SafeOnuba-Event-Id, X-SafeOnuba-Timestamp (Unix seconds) and X-SafeOnuba-Signature: v1=<hex(HMAC_SHA256(secret, timestamp + "." + body))>. Reject anything more than 5 min out of sync. During a rotation two signatures arrive, separated by a comma.

Acknowledgement: any 2xx in under 5 s. Retries at 10 s, 30 s, 2 min, 10 min, 30 min, 1 h and then every hour up to 24 h. “At least once” delivery (deduplicate by id) and no guaranteed order (use date_last_modified). SOS, falls, “I can’t evacuate” and evacuations go out before the rest.

Body application/json Event

  • idstring (uuid)required

    For deduplication: delivery is “at least once”.

  • typeEventTyperequired

    Possible values: alert.createdalert.acknowledgedalert.resolvedalert.reopenedalert.worker_acknowledgedmuster.startedmuster.kind_changedmuster.phase_changedmuster.targets_changedmuster.updatedmuster.worker_missingmuster.ended

  • api_versionstringrequired

    Possible values: 2026-09-24

  • created_atstring (date-time)required
  • organization_idstring (uuid) | nullrequired

    The site’s company. null in test events.

  • site_idstring (uuid)required
  • data{ alert } | { muster }required

    The complete object exactly as the GET would return it at that moment.

    One of 2 shapes
    • variant 1
      • alertAlertrequired
        Fields of Alert22
        • idstring (uuid)required
        • typeAlertTyperequired

          Possible values: sosfall_detectedrestricted_zone_entryforbidden_zone_entrypermit_expired_insidepermit_closed_insideheat_stressevacuation_helpworker_call_requestdevice_offlinelow_batteryearthquaketsunami_risk

        • severitySeverityrequired

          Possible values: lowmediumhighcritical

        • statusAlertStatusrequired

          Possible values: unacknowledgedacknowledgedresolved

        • titlestringrequired

          With include_worker_names, the title the control room reads (it carries the person’s name). Without it, one composed of the type, the zone and the external_id, with no name.

        • date_createdstring (date-time)required
        • date_last_modifiedstring (date-time)required

          For ordering: webhooks don’t guarantee order, and anything older than what you already have is discarded.

        • siteSiteRefrequired
          Fields of SiteRef2
          • idstring (uuid)required
          • namestringrequired
        • zoneZoneRefrequired
          Fields of ZoneRef2
          • idstring (uuid)required
          • namestringrequired
        • workerWorkerRefrequired
          Fields of WorkerRef4
          • idstring (uuid)required
          • external_idstring | nullrequired

            The worker’s code at the company (the one in its personnel system). null if not given.

          • namestring

            Full name. Only if the contract includes it; otherwise the property doesn’t appear.

          • contractorstring | nullrequired
        • deviceDeviceRefrequired
          Fields of DeviceRef4
          • idstring (uuid)required
          • serialstringrequired
          • batteryinteger | nullrequired

            from 0 to 100

          • date_last_seenstring (date-time) | nullrequired
        • locationLocationrequired
          Fields of Location7
          • latitudenumberrequired

            from -90 to 90

          • longitudenumberrequired

            from -180 to 180

          • uncertainty_mnumber | nullrequired

            Uncertainty radius in metres. null if unknown: not knowing it is not the same as it being perfect.

            minimum 0

          • sourcestringrequired

            zone: the person was in a privacy zone and the point is the zone’s, not theirs.

            Possible values: gpsnetworkzone

          • maskedbooleanrequired

            The point is the representative one for a privacy zone.

          • position_date_utcstring (date-time)required
          • heightobject | nullrequired

            Height above ground by barometer, when it can be stated; null if not.

        • location_withheldbooleanrequired

          The position exists but is not delivered: in “emergencies only”, an alert below the severity that lifts the veil doesn’t show it, and neither does the dashboard.

        • detailsAlertDetailsrequired
          One of 9 shapes
            • triggerstringrequired

              How it was requested: on the watch screen, with the physical button, after an unanswered fall, or from the control room.

              Possible values: watch_buttonwatch_hardware_buttonafter_fallcontrol_room

            • escalated_to_sosbooleanrequired

              Did not answer the watch’s “Are you OK?” and it escalated to SOS.

            • zone_typestringrequired

              Possible values: restrictedforbidden

            • permit_referencestring | nullrequired

              The permit to work (job safety analysis, JSA) in force, if there was one.

          • Nothing derived from heart rate: vital signs don’t leave through the API, not even aggregated.

            • actionstringrequired

              What the watch has told them: stop, drink and find shade. There are no levels.

              Possible values: stop_and_rest

            • heat_index_cnumber | nullrequired

              The plant’s heat index (°C).

            • sun_exposure_minutesinteger | nullrequired
            • reasonstring | nullrequired

              What they said on the watch: trapped, injured or helping someone else.

              Possible values: trappedinjuredhelping

            • muster_idstring (uuid)required
            • voice_notebooleanrequired

              With no coverage, the watch recorded a voice message (it can be heard in the dashboard).

            • minutes_silentintegerrequired
            • battery_pctintegerrequired

              from 0 to 100

            • magnitudenumber | nullrequired
            • distance_kmnumber | nullrequired
            • officialbooleanrequired

              false: a SafeOnuba estimate with no official warning. true: an official bulletin confirmed by a person.

            • felt_at_sitebooleanrequired
            • etastring (date-time) | nullrequired

              Estimated arrival of the wave (tsunami).

        • nearbyarray<Nearby>required
          Fields of Nearby5
          • kindstringrequired

            Possible values: personvehicle

          • workerobjectrequired
          • vehicle_typestring | nullrequired
          • distance_mintegerrequired
          • reported_atstring (date-time)required
        • vehicle_warningsarray<VehicleWarning>required
          Fields of VehicleWarning4
          • atstring (date-time)required
          • vehicle_typestring | nullrequired
          • distance_mintegerrequired
          • worker_acknowledged_atstring (date-time) | nullrequired
        • worker_acknowledged_atstring (date-time) | nullrequired

          The worker pressed “Got it” on their watch (watch time).

        • acknowledgedActionByrequired
          Fields of ActionBy2
          • atstring (date-time)required
          • bystringrequired

            Who: a person from the dashboard, or “Client · Operator (via integration)”.

        • resolvedobject | nullrequired

          Resolved: by whom, when and with what note.

          Fields3
          • atstring (date-time)required
          • bystringrequired

            Who: a person from the dashboard, or “Client · Operator (via integration)”.

          • notestring | nullrequired
        • assigned_tostring | nullrequired
        • simulatedbooleanrequired

          Raised in a drill or with simulated watches.

        • panel_urlstring (uri)required
    • variant 2
      • musterMusterrequired
        Fields of Muster13
        • idstring (uuid)required
        • siteSiteRefrequired
          Fields of SiteRef2
          • idstring (uuid)required
          • namestringrequired
        • statusstringrequired

          Possible values: activecompletedcancelled

        • phasestringrequired

          inspecting: headcount complete and the control room is checking the plant; watches say “do not go back until further notice”.

          Possible values: evacuatinginspecting

        • kindMusterKindrequired

          Possible values: generaltsunamiearthquake

        • reasonstring | nullrequired
        • started_atstring (date-time)required
        • ended_atstring (date-time) | nullrequired
        • deadlineobject | nullrequired
          Fields2
          • atstring (date-time)required
          • sourcestringrequired

            Tsunami: the time of an official warning, or the ceiling in the zone’s plan. Never a physical calculation.

            Possible values: officialplan_estimate

        • originobject | nullrequired

          Where the emergency comes from. null in an evacuation with no origin (a general drill).

          Fields5
          • latitudenumberrequired
          • longitudenumberrequired
          • radius_mintegerrequired
          • labelstring | nullrequired
          • zoneZoneRefrequired
        • targets_revisionintegerrequired

          Goes up every time the targets change (ruling out, restoring, change of type).

        • totalsobjectrequired

          The same figures as the dashboard banner and the closing summary: the server counts them. In an ended evacuation, what remains is what was recorded on ending —arrived and total— and the rest comes out as null.

          Fields7
          • expectedintegerrequired
          • safeintegerrequired
          • helpinteger | nullrequired
          • wrong_pointinteger | nullrequired
          • pendinginteger | nullrequired
          • no_signalinteger | nullrequired
          • not_worninteger | nullrequired
        • assembly_pointsarray<AssemblyPoint>required

          The targets for the type, ruled-out ones included.

          Fields of AssemblyPoint5
          • idstring (uuid)required
          • namestringrequired
          • statusstringrequired

            Possible values: availableexcluded

          • countinteger | nullrequired

            People safe at this point. null in an ended evacuation: on ending, only the total is kept.

          • excludedobject | nullrequired

Responses

  • 200

    Received. Any 2xx will do.

Body your destination receives

Event
{
  "id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
  "type": "alert.created",
  "api_version": "2026-09-24",
  "created_at": "2026-09-24T11:04:12Z",
  "organization_id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
  "site_id": "0f6c2b7e-3a1d-4c55-9b0e-7d2f4a8c1e90",
  "data": {
    "alert": {
      "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"
    }
  }
}

How to check it comes from SafeOnuba: verify the signature.