Webhooks
Aggiornato Aug 2026 · API v3Registra un endpoint HTTPS e pon chiama te quando succede qualcosa — niente loop di polling, niente richieste sprecate. Gestisci i webhook su my.pon.app → Webhooks o via API.
Topic
| Topic | Scatta quando |
|---|---|
list.changed |
Qualcosa in una lista è cambiato (grossolano, accorpato — il default) |
item.added |
Un articolo è finito su una lista |
item.removed |
Un articolo è stato eliminato |
item.checked |
Un articolo è stato spuntato durante la spesa (togliere la spunta fa scattare solo list.changed) |
list.members.changed |
Qualcuno è entrato o uscito da una lista |
Iscriviti a ciò che ti serve davvero. Un filtro listIds opzionale (fino a
50, solo le tue liste — id sconosciuti rispondono 400 con
invalidListIds) restringe le consegne a liste specifiche.
Registrazione
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 risposta contiene il tuo segreto di firma (whsec_…) — mostrato una
sola volta. Registrare di nuovo lo stesso URL aggiorna la sottoscrizione e
mantiene il segreto. Fino a 5 webhook per account.
La registrazione pinga subito il tuo URL.
pon invia un eventoping firmato e si aspetta un 2xx — rispondi prima di controllare la firma (il segreto arriva solo nella risposta). Un URL morto viene rifiutato con 422 WEBHOOK_UNREACHABLE.Consegne
Ogni consegna è una POST con gli header PON-Event: <topic> e
PON-Signature: sha256=<hmac>:
{ "event": "item.checked", "listId": "6led…", "cursor": 123, "at": "2026-08-09T19:00:00.000Z" }
Le consegne sono best-effort, senza retry — se il tuo endpoint è giù, l’evento successivo (o un fetch dalla tua parte) ti rimette in pari. I redirect non vengono seguiti. Più cambiamenti corrispondenti in una stessa scrittura si accorpano in una sola consegna per topic sottoscritto.
Verificare la firma
Calcola un HMAC-SHA256 sul body grezzo della richiesta con il tuo segreto e confrontalo — in tempo costante — con l’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 conferma una consegna. Dopo 20 fallimenti consecutivi
(qualsiasi altra cosa, timeout inclusi) il webhook si mette in pausa da solo
(status: paused, pausedReason: auto_failures). Sistema il tuo endpoint,
poi riattivalo su my.pon.app o via PATCH /v3/webhooks/{id}
con { "status": "active" } — la riattivazione azzera il contatore. Un ping
di test manuale è POST /v3/webhooks/{id}/pings (non
conta mai come fallimento).
I webhook battono il polling — sempre.
Un loop di polling da 5 minuti fa circa 8.600 richieste al mese e conta come uso intensivo sull’indicatore fair-use. Un webhook ne fa esattamente quante volte cambiano le tue liste.