Webhooks
Mis à jour Aug 2026 · API v3Enregistre un endpoint HTTPS et pon t’appelle toi quand quelque chose se passe — pas de boucle de polling, pas de requêtes gaspillées. Gère tes webhooks sur my.pon.app → Webhooks ou via l’API.
Topics
| Topic | Se déclenche quand |
|---|---|
list.changed |
Quelque chose a changé sur une liste (grossier, regroupé — le défaut) |
item.added |
Un article a atterri sur une liste |
item.removed |
Un article a été supprimé |
item.checked |
Un article a été coché pendant les courses (décocher ne déclenche que list.changed) |
list.members.changed |
Quelqu’un a rejoint ou quitté une liste |
Abonne-toi à ce dont tu as vraiment besoin. Un filtre listIds optionnel
(jusqu’à 50, tes propres listes uniquement — des ids inconnus répondent
400 avec invalidListIds) restreint les livraisons à des listes précises.
Enregistrer
POST /v3/webhooks
curl -X POST https://api.pon.app/v3/webhooks \
-H "Authorization: Bearer pon_pat_XXXX" \
-H "Content-Type: application/json" \
-d '{ "url": "https://hooks.example.com/pon",
"events": ["item.checked"],
"listIds": ["LIST_ID"] }'
La réponse contient ton secret de signature (whsec_…) — affiché une
seule fois. Réenregistrer la même URL met à jour l’abonnement et conserve
le secret. Jusqu’à 5 webhooks par compte.
L’enregistrement pinge ton URL immédiatement.
pon envoie un événementping signé et attend un 2xx — réponds-y avant de vérifier la signature (le secret n’arrive que dans la réponse). Une URL morte est rejetée avec 422 WEBHOOK_UNREACHABLE.Livraisons
Chaque livraison est un POST avec les headers PON-Event: <topic> et
PON-Signature: sha256=<hmac> :
{ "event": "item.checked", "listId": "6led…", "cursor": 123, "at": "2026-08-09T19:00:00.000Z" }
Les livraisons sont best-effort, sans retries — si ton endpoint est hors service, l’événement suivant (ou un fetch de ton côté) te remet à jour. Les redirections ne sont pas suivies. Plusieurs changements correspondants dans une même écriture se regroupent en une seule livraison par topic abonné.
Vérifier la signature
Calcule un HMAC-SHA256 sur le corps brut de la requête avec ton secret et compare-le — en temps constant — au header :
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, header, secret) {
const expected = "sha256=" +
createHmac("sha256", secret).update(rawBody).digest("hex");
return (
header.length === expected.length &&
timingSafeEqual(Buffer.from(header), Buffer.from(expected))
);
}import hashlib, hmac
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(header, expected)Circuit breaker
Un 2xx acquitte une livraison. Après 20 échecs consécutifs (tout le
reste, timeouts inclus) le webhook se met en pause automatiquement
(status: paused, pausedReason: auto_failures). Répare ton endpoint, puis
réactive-le sur my.pon.app ou via PATCH /v3/webhooks/{id}
avec { "status": "active" } — la réactivation remet le compteur à zéro. Un
ping de test manuel se fait via POST /v3/webhooks/{id}/pings
(il ne compte jamais comme un échec).
Les webhooks battent le polling — toujours.
Une boucle de polling de 5 minutes fait environ 8 600 requêtes par mois et compte comme usage intensif sur la jauge fair-use. Un webhook en fait exactement autant que tes listes changent.