developers  · docsAccount
Haal je token
Docs · Webhooks

Webhooks

Bijgewerkt Aug 2026 · API v3

Registreer een HTTPS-endpoint en pon roept jou aan wanneer er iets gebeurt — geen polling-loop, geen verspilde requests. Beheer je webhooks op my.pon.app → Webhooks of via de API.

Topics

Topic Vuurt wanneer
list.changed Er iets aan een lijst veranderde (grof, samengevoegd — de standaard)
item.added Een artikel op een lijst belandde
item.removed Een artikel werd verwijderd
item.checked Een artikel tijdens het winkelen werd afgevinkt (het vinkje weghalen vuurt alleen list.changed)
list.members.changed Iemand een lijst joinde of verliet

Abonneer je op wat je echt nodig hebt. Een optioneel listIds-filter (maximaal 50, alleen je eigen lijsten — onbekende ids antwoorden 400 met invalidListIds) beperkt leveringen tot specifieke lijsten.

Registreren

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"] }'

De response bevat je signing-secret (whsec_…) — één keer getoond. Dezelfde URL opnieuw registreren werkt het abonnement bij en behoudt het secret. Maximaal 5 webhooks per account.

Registratie pingt je URL meteen.

pon stuurt een gesigneerd ping-event en verwacht een 2xx — beantwoord die vóór je de signature controleert (het secret komt pas in de response). Een dode URL wordt geweigerd met 422 WEBHOOK_UNREACHABLE.

Leveringen

Elke levering is een POST met de headers PON-Event: <topic> en PON-Signature: sha256=<hmac>:

{ "event": "item.checked", "listId": "6led…", "cursor": 123, "at": "2026-08-09T19:00:00.000Z" }

Leveringen zijn best-effort, zonder retries — als je endpoint plat ligt, brengt het volgende event (of een fetch aan jouw kant) je weer bij. Redirects worden niet gevolgd. Meerdere passende wijzigingen in één schrijfactie worden samengevoegd tot één levering per geabonneerd topic.

De signature verifiëren

Bereken een HMAC-SHA256 over de rauwe request-body met je secret en vergelijk die — constant-time — met de 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

Een 2xx bevestigt een levering. Na 20 opeenvolgende mislukkingen (al het andere, timeouts inbegrepen) pauzeert de webhook zichzelf (status: paused, pausedReason: auto_failures). Repareer je endpoint en activeer hem daarna weer op my.pon.app of via PATCH /v3/webhooks/{id} met { "status": "active" } — heractiveren zet de teller op nul. Een handmatige testping is POST /v3/webhooks/{id}/pings (telt nooit als mislukking).

Webhooks verslaan polling — altijd.

Een polling-loop van 5 minuten doet zo’n 8.600 requests per maand en telt op de fair-use-meter als zwaar gebruik. Een webhook doet er precies zoveel als je lijsten veranderen.