Skip to main content
The API POSTs a signed JSON event to your endpoint whenever something happens (an invoice is stamped, a cancellation resolves, a download is ready…). A delivery that fails is retried with capped exponential backoff for about 24 hours (see Retries).

Register an endpoint

The response includes the signing secret exactly once:
Store whsec_... securely — it is never shown again (rotate by creating a new endpoint). The one exception is an Idempotency-Key retry of this same request within 24h, which replays the original response, secret included (the stored copy is encrypted). In live mode the URL must be https. enabled_events entries may be "*", an exact type, or a namespace wildcard like "invoice.*".

The delivery

Headers: Body (the same object as GET /v1/events/:id):

Verifying the signature

The signature is HMAC-SHA256 over the string `${id}.${timestamp}.${rawBody}` using your raw whsec_... secret, hex-encoded. Verify over the exact raw request body bytes — do not re-serialize the parsed JSON. Reject deliveries whose timestamp is outside a tolerance window (default 300s; see WEBHOOK_TOLERANCE_SECS) to blunt replays.

Node.js

Python

Return 2xx fast (do the real work async). Any non-2xx or a timeout (10s) is treated as a failure and the delivery is retried on the schedule below.

Retries

Each delivery gets up to 35 attempts over about 24 hours, retried independently per endpoint. The first attempt is immediate. The waits after each failure double from 2 seconds to about 34 minutes (2s, 4s, 8s, … 2048s), then retries run once an hour. After the last attempt the delivery stays failed with next_attempt_at: null and no more retries are scheduled. If your endpoint was down longer than that, replay the event with POST /v1/events/:id/resend (the event log keeps it), which starts a fresh 35-attempt schedule. Timing is approximate, and a large backlog can stretch it: to protect other customers, at most 2 deliveries to the same endpoint run per worker poll. GET /v1/webhook_endpoints/:id/deliveries shows the next scheduled attempt in next_attempt_at.

Events

This list is the complete set of event types, generated from and verified against EVENT_TYPES in src/core/events.ts — subscribe to any of them exactly, by namespace wildcard (invoice.*), or with *. fiscal_profile.manifest_signed fires when you sign a manifiesto de cuentas (POST /v1/fiscal_profiles/:id/manifest); download.created fires when a descarga masiva job is accepted; download.partial fires when some invoices were delivered and some were not; download.no_data fires when the SAT confirms a request found zero CFDIs in range. Each event is also readable at GET /v1/events/:id and listable at GET /v1/events — the event log is the source of truth deliveries replay from, so a missed webhook can always be reconciled by polling events. Endpoints only receive events emitted after they were created.

Managing endpoints