Webhooks
Endpoints, the event log, delivery inspection and manual retry.
Base: https://api.facturia.cl/v1. Every endpoint in this chapter authenticates with Authorization: Bearer unless stated otherwise, and the error envelope is the one in Errors.
| Method | Path | What it does |
|---|---|---|
GET | /webhook_endpoints | List webhook endpoints |
POST | /webhook_endpoints | Register a webhook endpoint |
GET | /webhook_endpoints/{webhook_endpoint_id} | Retrieve a webhook endpoint |
PATCH | /webhook_endpoints/{webhook_endpoint_id} | Update a webhook endpoint |
DELETE | /webhook_endpoints/{webhook_endpoint_id} | Delete a webhook endpoint |
POST | /webhook_endpoints/{webhook_endpoint_id}/ping | Send a synthetic event to verify plumbing |
POST | /webhook_endpoints/{webhook_endpoint_id}/rotate_secret | Rotate the signing secret |
GET | /webhook_endpoints/{webhook_endpoint_id}/deliveries | Inspect delivery attempts |
POST | /webhook_endpoints/{webhook_endpoint_id}/deliveries/{delivery_id}/retry | Redeliver an event |
GET | /events | Query the event ledger (retained 12 months) |
GET | /events/{event_id} | Retrieve an event |
GET /webhook_endpoints
List webhook endpoints
Webhook endpoints configured for the account, with their enabled_events and delivery health, secrets never included.
curl -sS https://api.facturia.cl/v1/webhook_endpoints \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
limit | query | — | integer | |
cursor | query | — | string | Opaque cursor from a previous response's next_cursor. |
Responses
| Code | Meaning | Body |
|---|---|---|
200 | A list of endpoints. | lista de WebhookEndpoint |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
POST /webhook_endpoints
Register a webhook endpoint
The secret is returned once, on creation, and never again.
curl -sS -X POST https://api.facturia.cl/v1/webhook_endpoints \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"url":"https://api.miempresa.cl/hooks/facturia"}'Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
Idempotency-Key | header | — | string | Client-generated key, unique per logical operation, retained 24h and scoped to (account, empresa, endpoint). Replays return the original response with Facturia-Idempotent-Replay: true. Same key + different body → 409. |
Body
| Field | Type | Required | Notes |
|---|---|---|---|
url | string | yes | |
description | string | — | |
enabled_events | string[] | — | Event types, or ["*"] for everything including future types. Default: ["*"]. |
empresas | Rut[] | — | Restrict deliveries to these empresas. Defaults to all the key can see. |
| Responses |
| Code | Meaning | Body |
|---|---|---|
201 | The created endpoint, including its signing secret. | WebhookEndpointWithSecret |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
GET /webhook_endpoints/{webhook_endpoint_id}
Retrieve a webhook endpoint
One webhook endpoint's configuration and delivery health, without its signing secret.
curl -sS https://api.facturia.cl/v1/webhook_endpoints/whe_01K2RF5N8Q2W \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
webhook_endpoint_id | path | yes | string |
Responses
| Code | Meaning | Body |
|---|---|---|
200 | The endpoint. | WebhookEndpoint |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
PATCH /webhook_endpoints/{webhook_endpoint_id}
Update a webhook endpoint
Update url, enabled_events or description. The signing secret is unaffected — use rotate_secret to change it.
curl -sS -X PATCH https://api.facturia.cl/v1/webhook_endpoints/whe_01K2RF5N8Q2W \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://api.miempresa.cl/hooks/facturia","description":"…"}'Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
webhook_endpoint_id | path | yes | string |
Body
| Field | Type | Required | Notes |
|---|---|---|---|
url | string | — | |
description | string | — | |
enabled_events | string[] | — | |
empresas | Rut[] | — | |
status | enabled · disabled | — | |
| Responses |
| Code | Meaning | Body |
|---|---|---|
200 | The updated endpoint. | WebhookEndpoint |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
DELETE /webhook_endpoints/{webhook_endpoint_id}
Delete a webhook endpoint
Delete the endpoint and destroy its signing secret (current and previous) in the vault; both are removed together so no orphaned secret survives the row.
curl -sS -X DELETE https://api.facturia.cl/v1/webhook_endpoints/whe_01K2RF5N8Q2W \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
webhook_endpoint_id | path | yes | string |
Responses
| Code | Meaning | Body |
|---|---|---|
204 | Deleted. | — |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
POST /webhook_endpoints/{webhook_endpoint_id}/ping
Send a synthetic event to verify plumbing
Send a synthetic ping event to the endpoint's current URL, so an integrator can verify signature verification before relying on a real event.
curl -sS -X POST https://api.facturia.cl/v1/webhook_endpoints/whe_01K2RF5N8Q2W/ping \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
webhook_endpoint_id | path | yes | string |
Responses
| Code | Meaning | Body |
|---|---|---|
202 | The delivery attempt. | WebhookDelivery |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
POST /webhook_endpoints/{webhook_endpoint_id}/rotate_secret
Rotate the signing secret
The previous secret keeps signing for 24 hours so you can deploy without downtime.
curl -sS -X POST https://api.facturia.cl/v1/webhook_endpoints/whe_01K2RF5N8Q2W/rotate_secret \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
webhook_endpoint_id | path | yes | string |
Responses
| Code | Meaning | Body |
|---|---|---|
200 | The endpoint with its new secret. | WebhookEndpointWithSecret |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
GET /webhook_endpoints/{webhook_endpoint_id}/deliveries
Inspect delivery attempts
Delivery attempts for this endpoint, newest first, with each attempt's response status and whether it will be retried.
curl -sS https://api.facturia.cl/v1/webhook_endpoints/whe_01K2RF5N8Q2W/deliveries \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
webhook_endpoint_id | path | yes | string | |
limit | query | — | integer | |
cursor | query | — | string | Opaque cursor from a previous response's next_cursor. |
status | query | — | pending · succeeded · failed | |
event_id | query | — | string |
Responses
| Code | Meaning | Body |
|---|---|---|
200 | A list of deliveries. | lista de WebhookDelivery |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
POST /webhook_endpoints/{webhook_endpoint_id}/deliveries/{delivery_id}/retry
Redeliver an event
Rate-limited at 20/min per account, not per credential (ticket #152) — a leaked key
would otherwise turn this into a free outbound-request amplifier from Facturia's own IPs.
There is also a hard ceiling of 20 total delivery attempts per (endpoint, event) pair,
answered as 409 too_many_replays.
curl -sS -X POST https://api.facturia.cl/v1/webhook_endpoints/whe_01K2RF5N8Q2W/deliveries/whd_01K2RG1P4M7X01/retry \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
webhook_endpoint_id | path | yes | string | |
delivery_id | path | yes | string |
Responses
| Code | Meaning | Body |
|---|---|---|
202 | The new delivery attempt. | WebhookDelivery |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
404 | No such object under this key. | ErrorResponse |
409 | State conflict — idempotency reuse, duplicate external_id, artifact not ready. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
GET /events
Query the event ledger (retained 12 months)
Retention is 12 months — deliberately longer than a typical webhook ledger, so a whole F29
tax cycle stays replayable. Webhook delivery is at-least-once and unordered; deduplicate
on id.
Polling instead of webhooks. If you cannot expose an HTTPS endpoint — a personal agent,
a laptop, anything behind NAT — this endpoint is the supported substitute, and ?after=
is the parameter that makes it work:
GET /v1/events?after=evt_01K2RG1P4M7X&limit=100
after pages FORWARDS: oldest first, strictly newer than the id you name, next_cursor
advancing away from it. The loop is after = next_cursor ?? after, processing data in
order; it never re-reads a row and needs no set of seen ids. after accepts both an
evt_… id (the last event you processed) and a cur_… value from next_cursor, so your
stored checkpoint and the token you are handed are interchangeable. When has_more is
false, next_cursor is null — keep the id of the last event you processed and send
that next time.
cursor is the opposite direction and the default: newest first, "older than this", which
is what a dashboard reading a ledger wants. Sending both is 400 rather than a silent
precedence — they name positions in opposite orders, and honouring either would skip rows
for half the callers with nothing to tell them so.
curl -sS https://api.facturia.cl/v1/events \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
limit | query | — | integer | |
cursor | query | — | string | Opaque cursor from a previous response's next_cursor. |
after | query | — | string | Forward checkpoint: return events strictly NEWER than this one, oldest first. An evt_… id or a cur_… value from a previous forward page. Mutually exclusive with cursor. |
type | query | — | string | |
empresa_rut | query | — | Rut | |
created_at[gte] | query | — | string | |
created_at[lte] | query | — | string | Upper bound, inclusive. Honoured since the endpoint shipped and undeclared until now, which made "give me one closed month of the ledger" look impossible from the contract. |
Responses
| Code | Meaning | Body |
|---|---|---|
200 | A list of events. | lista de Event |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |
GET /events/{event_id}
Retrieve an event
One event from the account's own ledger — the same object a webhook delivery carries — for a caller reconciling by id rather than by subscription.
curl -sS https://api.facturia.cl/v1/events/evt_01K2RG1P4M7X \
-H "Authorization: Bearer $FACTURIA_KEY"Parameters
| Parameter | In | Required | Type | Notes |
|---|---|---|---|---|
event_id | path | yes | string |
Responses
| Code | Meaning | Body |
|---|---|---|
200 | The event. | Event |
401 | Missing, malformed or revoked key. | ErrorResponse |
403 | Valid key, not permitted — scope, empresa allowlist, or mode. | ErrorResponse |
429 | Too many requests. | ErrorResponse |
default | An error not otherwise enumerated for this operation, in the same §5.5 envelope as every other refusal. Branch on error.code, never on the HTTP status alone or on error.message — a code this operation has not been seen to throw yet is still safer to route on than a string meant for a human. | ErrorResponse |