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…). Deliveries retry with exponential backoff until your endpoint returns a 2xx.

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). 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 with exponential backoff on its own schedule.

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.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