developers  · docsConta
Obtém o teu token
Docs · Webhooks

Webhooks

Atualizado Aug 2026 · API v3

Regista 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 evento ping 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.