Aller au contenu

Types d'événements

Lisoloo émet cinq types d’événements, un par transition de statut. Tous partagent la même enveloppe extérieure ; le bloc data varie par événement.

{
"event_id": "f8a3b7c1-2e4d-4a9b-9d8f-7c6e5b4a3d2c",
"event_type": "<type>",
"timestamp": "2026-05-27T10:15:08Z",
"message_id": "507f1f77bcf86cd799439011",
"data": { ... }
}
ChampTypeNotes
event_idUUIDUnique par événement. À utiliser pour l’idempotence.
event_typestringUn de sms.queued, sms.processing, sms.sent, sms.delivered, sms.failed.
timestampISO 8601Quand la passerelle a émis l’événement.
message_idstringLe message_id de POST /send.
dataobjectCharge utile spécifique à l’événement.

Déclenché immédiatement après que POST /send retourne 201.

{
"event_id": "...",
"event_type": "sms.queued",
"timestamp": "2026-05-27T10:15:00Z",
"message_id": "507f1f77bcf86cd799439011",
"data": {
"total_recipients": 3,
"total_messages": 3,
"total_cost": 0.06,
"currency": "USD",
"scheduled_at": null
}
}

Pour les envois planifiés, scheduled_at est la première paire (date, time) de scheduled_dates (ou la première occurrence calculée pour récurrent). Sinon nullsms.processing suivra en quelques secondes.

Déclenché quand le connecteur opérateur récupère le job.

{
"event_type": "sms.processing",
"data": {
"recipient_phone": "+243998857000",
"carrier": "vodacom_drc"
}
}

Un événement par destinataire. carrier est le slug interne du connecteur — informationnel seulement, pas partie de l’API stable.

Déclenché quand le SMSC accepte le message pour livraison (côté opérateur).

{
"event_type": "sms.sent",
"data": {
"recipient_phone": "+243998857000",
"carrier": "vodacom_drc",
"sent_at": "2026-05-27T10:15:03Z"
}
}

Le destinataire n’a pas encore reçu le SMS à ce point — il est dans la file sortante de l’opérateur.

Déclenché quand le combiné ACK la livraison (ou que l’opérateur rapporte « delivered » dans son accusé asynchrone).

{
"event_type": "sms.delivered",
"data": {
"recipient_phone": "+243998857000",
"carrier": "vodacom_drc",
"delivered_at": "2026-05-27T10:15:08Z",
"segments": 1
}
}

Terminal pour ce destinataire.

Déclenché sur tout chemin vers failed.

{
"event_type": "sms.failed",
"data": {
"recipient_phone": "+243998857000",
"carrier": "vodacom_drc",
"failed_at": "2026-05-27T10:15:05Z",
"error_code": "1502",
"error_message": "Numéro inaccessible",
"retryable": false
}
}

Terminal. Le error_code correspond au catalogue d’erreurs pour la cause au niveau opérateur. La passerelle ne retry pas les SMS échoués d’elle-même — l’opérateur a déjà tenté ses propres retries avant de rapporter failed.

Les événements se déclenchent dans l’ordre où la passerelle observe les transitions de la machine d’états, mais l’ordre de livraison HTTP n’est pas garanti. Une réponse lente de votre endpoint sur sms.processing suivie d’une réponse rapide sur sms.delivered peut résulter en delivered arrivant en premier.

Si l’ordre strict compte, ignorez event_type du fil et à la place chargez GET /status/{message_id} à la réception de tout événement — traitez le webhook comme un signal « quelque chose a changé ».

Votre handler doit être idempotent sur event_id. La passerelle re-tentera sur 5xx ou timeout ; le retry porte le même event_id. Une implémentation typique :

def handle_event(event: dict, db) -> None:
event_id = event["event_id"]
if db.events.find_one({"event_id": event_id}):
return # déjà traité
process_event(event, db)
db.events.insert_one({"event_id": event_id, "received_at": now()})