developers  · docsCuenta
Consigue tu token
Docs · Webhooks

Webhooks

Actualizado Aug 2026 · API v3

Registra un endpoint HTTPS y pon te llama cuando pasa algo — sin bucle de polling, sin peticiones desperdiciadas. Gestiona tus webhooks en my.pon.app → Webhooks o vía API.

Topics

Topic Se dispara cuando
list.changed Cualquier cosa de una lista cambió (grueso, agrupado — el predeterminado)
item.added Un artículo aterrizó en una lista
item.removed Un artículo fue eliminado
item.checked Un artículo fue marcado durante la compra (desmarcarlo solo dispara list.changed)
list.members.changed Alguien se unió a una lista o la abandonó

Suscríbete a lo que de verdad necesites. Un filtro opcional listIds (hasta 50, solo tus propias listas — los ids desconocidos responden 400 con invalidListIds) restringe las entregas a listas concretas.

Registro

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 respuesta contiene tu secreto de firma (whsec_…) — se muestra una sola vez. Volver a registrar la misma URL actualiza la suscripción y conserva el secreto. Hasta 5 webhooks por cuenta.

El registro hace ping a tu URL de inmediato.

pon envía un evento ping firmado y espera un 2xx — respóndelo antes de comprobar la firma (el secreto solo llega en la respuesta). Una URL muerta se rechaza con 422 WEBHOOK_UNREACHABLE.

Entregas

Cada entrega es un POST con los headers PON-Event: <topic> y PON-Signature: sha256=<hmac>:

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

Las entregas son best-effort, sin reintentos — si tu endpoint está caído, el siguiente evento (o un fetch por tu parte) te pone al día. No se siguen redirecciones. Varios cambios coincidentes en una misma escritura se agrupan en una entrega por topic suscrito.

Verifica la firma

Calcula un HMAC-SHA256 sobre el cuerpo crudo de la petición con tu secreto y compáralo — en tiempo constante — con el 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 confirma una entrega. Tras 20 fallos consecutivos (cualquier otra cosa, incluidos los timeouts) el webhook se pausa solo (status: paused, pausedReason: auto_failures). Arregla tu endpoint y reactívalo en my.pon.app o vía PATCH /v3/webhooks/{id} con { "status": "active" } — reactivar pone el contador a cero. Un ping de prueba manual es POST /v3/webhooks/{id}/pings (nunca cuenta como fallo).

Los webhooks ganan al polling — siempre.

Un bucle de polling cada 5 minutos hace ~8.600 peticiones al mes y cuenta como uso intensivo en el indicador de fair use. Un webhook hace exactamente tantas como cambien tus listas.