Notice d'intégration
SelyPass envoie chaque événement au centre SelyGuard par une requête HTTPS signée (JSON + HMAC-SHA256). Il n'y a ni récepteur à héberger, ni trame à coder : l'alarme arrive en moins d'une seconde avec le nom du travailleur, son téléphone et sa position GPS.
Dans SelyPass : Gardiennage › Alertes › Télésurveillance › Télésurveillance SelyGuard › Activer. L'organisation remplit sa fiche (nom, adresse, consignes, contacts à appeler après l'agent). SelyPass crée alors le client et le site dans SelyGuard par l'API partenaire ci-dessous, reçoit la clé et le secret de ses alarmes, et les utilise sans aucune saisie. « Modifier » renvoie la fiche ; « Résilier » révoque la clé et garde l'historique.
PUT https://selyguard-telesurveillance-web.vercel.app/api/partner/v1/accounts/{id organisation SelyPass}
X-SelyGuard-Partner: selypass
X-SelyGuard-Timestamp: 1793548800
X-SelyGuard-Signature: hex( HMAC-SHA256( secret partenaire, timestamp + "." + "PUT /api/partner/v1/accounts/{id}" + "." + corps ) )
{ "organization": { "name": "Atlas Sécurité", "email": "contact@atlas.fr" },
"site": { "name": "Atlas — agents PTI", "address": "…", "city": "Lyon" },
"instructions": "Appeler l'agent puis le chef de poste…",
"contacts": [ { "name": "Chef de poste", "phone": "+33611111111", "sms": true } ],
"supervisionMinutes": 130 }
→ 201 / 200 { "siteId", "accountNumber": "SP-482913", "alarmEndpoint", "key", "secret", "created" }
GET …/accounts/{id} état : dernier signal, alarmes en cours
DELETE …/accounts/{id} résiliationUne organisation SelyPass correspond à un client et un site SelyGuard. Les contacts envoyés remplacent la liste précédente. Le secret partenaire est la variable SELYPASS_PARTNER_SECRET de SelyGuard et SELYGUARD_PARTNER_SECRET de SelyPass.
POST https://selyguard-telesurveillance-web.vercel.app/api/ingest/selypass Content-Type: application/json X-Selypass-Key: sp_live_xxxxxxxxxxxxxxxxxxxxxxxx X-Selypass-Timestamp: 1793548800 (secondes Unix, tolérance ±5 min) X-Selypass-Signature: hex( HMAC-SHA256( secret, timestamp + "." + corps_brut ) )
La signature se calcule sur le corps exact envoyé (mêmes octets, sans reformatage).
| Événement | type | Priorité |
|---|---|---|
| Alerte travailleur isolé | lone_worker_alert | P1 |
| Homme à terre | man_down | P1 |
| Travailleur isolé : pas de réponse | lone_worker_no_response | P1 |
| Ronde en retard | patrol_late | P2 |
| Fin de poste oubliée | shift_end_missed | P2 |
| Poste non pris | shift_not_started | P3 |
| Test manuel | test_manual | info (archivé) |
| Test cyclique | test_periodic | info (archivé) |
{
"eventId": "a7c1e0f2-…", // obligatoire, unique par envoi (UUID) : anti-doublon
"type": "man_down", // voir le tableau § 3
"worker": {
"id": "W42", // identifiant stable du travailleur
"name": "Jean Dupont",
"phone": "+33611223344" // appelé en premier par le centre
},
"location": {
"lat": 48.85661, "lng": 2.35222,
"accuracy": 12, // mètres
"address": "12 rue de Rivoli, Paris",// optionnel
"at": "2026-11-02T08:14:05+01:00" // heure du point GPS
},
"occurredAt": "2026-11-02T08:14:07+01:00",
"message": "Chute détectée, pas de mouvement depuis 30 s",
"device": { "id": "SP-APP-9F3A", "name": "Android – Jean" },
"restore": false // true = fin d'alarme
}Fin d'alarme
{ "eventId": "b81d…", "type": "man_down", "restore": true, "worker": { "id": "W42" } }La fin d'alarme est rattachée à l'alerte ouverte du même travailleur (worker.id) et du même type. Elle est inscrite dans l'historique, mais l'opérateur clôture lui-même la fiche.
Test cyclique
{ "eventId": "c02e…", "type": "test_periodic", "device": { "id": "SP-GW-01" } }| 202 | Alarme créée : { alarmId, escalated } | terminé |
| 200 | Doublon (eventId déjà reçu) | terminé |
| 401 | Clé, signature ou horloge invalide | corriger la configuration ; ne pas réessayer en boucle |
| 422 | JSON invalide (détail dans « issues ») | corriger le message |
| 5xx / délai dépassé | Incident réseau ou serveur | réessayer avec le même eventId : 5 s, 15 s, 30 s, puis toutes les minutes |
Réutiliser le même eventId lors d'un nouvel essai est sans risque : SelyGuard ne crée jamais deux fois la même alarme. Si le centre reste injoignable, SelyPass doit garder ses alertes et appliquer son mode dégradé (appel direct des secours).
Node.js
import { createHmac, randomUUID } from "node:crypto";
export async function sendToSelyGuard(event) {
const body = JSON.stringify({ eventId: randomUUID(), ...event });
const ts = Math.floor(Date.now() / 1000).toString();
const sig = createHmac("sha256", process.env.SELYGUARD_SECRET).update(`${ts}.${body}`).digest("hex");
const res = await fetch("https://selyguard-telesurveillance-web.vercel.app/api/ingest/selypass", {
method: "POST",
headers: { "content-type": "application/json", "x-selypass-key": process.env.SELYGUARD_KEY,
"x-selypass-timestamp": ts, "x-selypass-signature": sig },
body,
signal: AbortSignal.timeout(10_000),
});
if (res.status >= 500) throw new Error("SelyGuard indisponible, réessayer");
return res.json();
}
await sendToSelyGuard({ type: "lone_worker_alert",
worker: { id: "W42", name: "Jean Dupont", phone: "+33611223344" },
location: { lat: 48.85661, lng: 2.35222, accuracy: 12 } });Ligne de commande (test)
BODY='{"eventId":"test-001","type":"test_manual"}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SELYGUARD_SECRET" -hex | sed 's/^.* //')
curl -X POST https://selyguard-telesurveillance-web.vercel.app/api/ingest/selypass \
-H "Content-Type: application/json" -H "X-Selypass-Key: $SELYGUARD_KEY" \
-H "X-Selypass-Timestamp: $TS" -H "X-Selypass-Signature: $SIG" -d "$BODY"Pour les équipements SelypassId de contrôle d'accès, de détection et de vidéo :
Champs optionnels supplémentaires : severity (critical | high | medium | low | info, qui remplace la priorité), zone, label, metadata, et media (jusqu'à 5 images, en URL https ou en base64).
Une solution Selykai Solutions