Empezar
Primeros pasos
Del acceso a tu primer webhook en cinco minutos: pide un token, haz la primera llamada, crea un destino y lanza una alerta de prueba en el sandbox.
En esta página
Esta guía va del acceso a tu primera alerta recibida, todo en el sandbox. Necesitas un terminal con curl y, para el paso 5, una URL pública en https donde recibir webhooks.
Los ejemplos leen las credenciales de variables de entorno. No las escribas en el código.
export SAFEONUBA_CLIENT_ID="cliente-ejemplo"
export SAFEONUBA_CLIENT_SECRET="cs_…"1. Pide acceso
El acceso lo damos de alta nosotros, cliente a cliente, y el motivo queda registrado. La planta ve en su panel (Ajustes → Integraciones) quién tiene acceso, a qué y por qué.
Al darte de alta recibes un client_id y un client_secret, que empieza por cs_. El secreto se enseña una sola vez: guárdalo en tu gestor de secretos en ese momento.
Para pedirlo, escríbenos a info@safeonuba.com con tu empresa, la planta y qué quieres integrar.
2. Pide un token
El token se pide con OAuth2 client_credentials y dura una hora.
curl -X POST https://sandbox.api.safeonuba.com/v1/oauth/token \
-d grant_type=client_credentials \
-d client_id="$SAFEONUBA_CLIENT_ID" \
-d client_secret="$SAFEONUBA_CLIENT_SECRET"const res = await fetch('https://sandbox.api.safeonuba.com/v1/oauth/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.SAFEONUBA_CLIENT_ID,
client_secret: process.env.SAFEONUBA_CLIENT_SECRET,
}),
});
const { access_token } = await res.json();import os
import requests
res = requests.post(
"https://sandbox.api.safeonuba.com/v1/oauth/token",
data={
"grant_type": "client_credentials",
"client_id": os.environ["SAFEONUBA_CLIENT_ID"],
"client_secret": os.environ["SAFEONUBA_CLIENT_SECRET"],
},
timeout=10,
)
res.raise_for_status()
access_token = res.json()["access_token"]using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient();
var res = await http.PostAsync("https://sandbox.api.safeonuba.com/v1/oauth/token",
new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = Environment.GetEnvironmentVariable("SAFEONUBA_CLIENT_ID")!,
["client_secret"] = Environment.GetEnvironmentVariable("SAFEONUBA_CLIENT_SECRET")!,
}));
res.EnsureSuccessStatusCode();
var token = (await res.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("access_token").GetString();La respuesta:
{
"access_token": "at_9c1e…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "alerts:read alerts:write musters:read"
}Guarda el access_token para los pasos siguientes:
export SAFEONUBA_TOKEN="…"3. Haz la primera llamada
GET /v1/sites devuelve los centros a los que tienes acceso. Vale con cualquier scope, así que es la mejor forma de comprobar que el token funciona.
curl https://sandbox.api.safeonuba.com/v1/sites \
-H "Authorization: Bearer $SAFEONUBA_TOKEN"Anota el id de tu centro de sandbox: lo usarás al lanzar un escenario.
4. Crea un destino de webhook
Un destino es la URL de tu receptor y los eventos que quieres que le lleguen. Hace falta el scope webhooks:manage.
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.*"]
}'La respuesta trae el secret de firma, que empieza por whsec_.
5. Recibe y verifica
Tu receptor tiene que hacer tres cosas con cada envío:
- Comprobar la firma de
X-SafeOnuba-Signaturesobre el cuerpo en bruto. - Responder
2xxen menos de 5 segundos. - Procesar el evento después, fuera de esa petición.
Verificar la firma tiene el receptor completo en Node, Python y C#. Cuando lo tengas desplegado, comprueba que le llega algo:
curl -X POST https://sandbox.api.safeonuba.com/v1/webhooks/ID_DEL_DESTINO/test \
-H "Authorization: Bearer $SAFEONUBA_TOKEN"Llega un alert.created marcado simulated: true y firmado como uno real.
6. Lanza un SOS de prueba
En el sandbox, un escenario pone a un reloj simulado a pulsar el SOS. Lo que recibes es lo mismo que recibirías de un reloj de verdad.
curl -X POST https://sandbox.api.safeonuba.com/v1/sandbox/scenarios \
-H "Authorization: Bearer $SAFEONUBA_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "scenario": "sos" }'A tu receptor le llega un alert.created con la alerta completa en data.alert. Si nadie la cierra, se cierra sola a los 10 minutos.
7. Reconócela desde tu sala
Con el scope alerts:write, tu sala puede hacerse cargo de la alerta. Siempre en nombre de una persona: el actor es el operador que la ha reconocido, y queda en la cronología de la alerta.
curl -X PUT https://sandbox.api.safeonuba.com/v1/alerts/ID_DE_LA_ALERTA \
-H "Authorization: Bearer $SAFEONUBA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "acknowledged",
"actor": { "name": "E. Ejemplo", "external_id": "OP-117" }
}'A tu receptor le llega alert.acknowledged, y en el panel de SafeOnuba la alerta aparece reconocida «vía integración».
Siguientes pasos
- Autenticación y scopes: cachear el token y rotar el secreto sin cortes.
- Webhooks: reintentos, duplicados, orden y filtros.
- Sandbox: el escenario de evacuación completa, de principio a fin.