Webhooks
Atualizado Aug 2026 · API v3Regista um endpoint HTTPS e o pon chama-te a ti quando algo acontece — sem loop de polling, sem pedidos desperdiçados. Gere os webhooks em my.pon.app → Webhooks ou via API.
Topics
| Topic | Dispara quando |
|---|---|
list.changed |
Algo numa lista mudou (grosseiro, coalescido — o predefinido) |
item.added |
Um item entrou numa lista |
item.removed |
Um item foi apagado |
item.checked |
Um item foi marcado durante as compras (desmarcar só dispara list.changed) |
list.members.changed |
Alguém entrou ou saiu de uma lista |
Subscreve o que realmente precisas. Um filtro opcional listIds (até 50,
apenas as tuas próprias listas — ids desconhecidos respondem 400 com
invalidListIds) restringe as entregas a listas específicas.
Registar
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"] }'
A resposta contém o teu segredo de assinatura (whsec_…) — mostrado uma
vez. Registar de novo o mesmo URL atualiza a subscrição e mantém o
segredo. Até 5 webhooks por conta.
O registo faz ping ao teu URL imediatamente.
O pon envia um eventoping assinado e espera um 2xx — responde-lhe antes de verificares a assinatura (o segredo só chega na resposta). Um URL morto é rejeitado com 422 WEBHOOK_UNREACHABLE.Entregas
Cada entrega é um POST com os headers PON-Event: <topic> e
PON-Signature: sha256=<hmac>:
{ "event": "item.checked", "listId": "6led…", "cursor": 123, "at": "2026-08-09T19:00:00.000Z" }
As entregas são best-effort, sem retries — se o teu endpoint estiver em baixo, o próximo evento (ou um fetch do teu lado) põe-te em dia. Redirecionamentos não são seguidos. Várias alterações correspondentes numa só escrita coalescem numa única entrega por topic subscrito.
Verificar a assinatura
Calcula um HMAC-SHA256 sobre o corpo bruto do pedido com o teu segredo e compara-o — em tempo constante — com o 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
Um 2xx confirma uma entrega. Após 20 falhas consecutivas (qualquer
outra coisa, incluindo timeouts), o webhook pausa-se automaticamente
(status: paused, pausedReason: auto_failures). Corrige o teu endpoint e
reativa-o depois em my.pon.app ou via PATCH
/v3/webhooks/{id} com { "status": "active" } — reativar repõe o
contador a zero. Um ping de teste manual é POST
/v3/webhooks/{id}/pings (nunca conta como falha).
Os webhooks ganham ao polling — sempre.
Um loop de polling de 5 em 5 minutos faz ~8 600 pedidos por mês e conta como uso intensivo no medidor de fair use. Um webhook faz exatamente tantos quantas vezes as tuas listas mudam.