Webhooks API¶
Webhooks let you receive real-time notifications when events happen in your account. You register one or more webhook endpoints (HTTPS URLs), subscribe each to the event types you care about, and InvoicePDFs delivers a signed payload to your server whenever a matching event occurs. Deliveries are recorded so you can inspect their status and retry failures.
Subscribable event types (events):
invoice.createdinvoice.updatedinvoice.finalizedinvoice.sentinvoice.paidinvoice.voidedrender.queuedrender.completedrender.failedbatch.completedbatch.faileddelivery.sentdelivery.failed
Create Webhook Endpoint¶
A signing secret (whsec_...) is generated automatically and used to sign every delivery.
This response is the only one that contains it — store it now. Reading or listing
endpoints never returns the secret, and the only way to obtain another is
Rotate Signing Secret, which stops the current one working.
The endpoint is created active.
Request:
{
"url": "https://example.com/webhooks",
"description": "Production webhook",
"events": ["invoice.created", "invoice.paid"]
}
| Field | Required | Description |
|---|---|---|
url |
Yes | HTTPS URL that will receive event deliveries |
description |
No | Human-readable label for the endpoint |
events |
Yes | List of event types this endpoint subscribes to |
Response 200 OK:
{
"data": {
"id": "we_01XYZ",
"url": "https://example.com/webhooks",
"description": "Production webhook",
"events": ["invoice.created", "invoice.paid"],
"is_active": true,
"secret": "whsec_3pL8vQz1XyR...",
"created_at": "2026-07-20T10:00:00Z",
"updated_at": "2026-07-20T10:00:00Z"
}
}
Try it
List Webhook Endpoints¶
Response:
{
"data": [
{
"id": "we_01XYZ",
"url": "https://example.com/webhooks",
"description": "Production webhook",
"events": ["invoice.created", "invoice.paid"],
"is_active": true,
"created_at": "2026-07-20T10:00:00Z",
"updated_at": "2026-07-20T10:00:00Z"
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}
Try it
Get Webhook Endpoint¶
Response:
{
"data": {
"id": "we_01XYZ",
"url": "https://example.com/webhooks",
"description": "Production webhook",
"events": ["invoice.created", "invoice.paid"],
"is_active": true,
"created_at": "2026-07-20T10:00:00Z",
"updated_at": "2026-07-20T10:00:00Z"
}
}
Try it
Update Webhook Endpoint¶
Only include the fields you want to change:
| Field | Required | Description |
|---|---|---|
url |
No | New delivery URL |
description |
No | New label |
events |
No | Replacement list of subscribed event types |
is_active |
No | Enable or disable deliveries to this endpoint |
Note
events is replaced entirely on update, not merged. Include every event type you want the endpoint to keep receiving.
Response 200 OK:
{
"data": {
"id": "we_01XYZ",
"url": "https://example.com/webhooks",
"description": "Production webhook",
"events": ["invoice.created", "invoice.paid", "invoice.voided"],
"is_active": false,
"created_at": "2026-07-20T10:00:00Z",
"updated_at": "2026-07-20T11:30:00Z"
}
}
Try it
Delete Webhook Endpoint¶
Response:
Try it
Rotate Signing Secret¶
Generates a new signing secret for the endpoint and returns it. The previous secret stops being valid immediately, so update your verification code with the new value.
Response 200 OK:
Try it
Send a Test Event¶
Queues a synthetic test event delivery to the endpoint so you can verify connectivity. Returns the created delivery record.
Response 200 OK:
{
"data": {
"id": "whd_01ABC",
"endpoint_id": "we_01XYZ",
"event_id": "evt_01ABC",
"event_type": "test",
"status": "pending",
"http_status": null,
"attempts": 0,
"error_message": null,
"created_at": "2026-07-20T10:00:00Z",
"delivered_at": null
}
}
Try it
List Webhook Deliveries¶
Returns delivery attempts across all of your endpoints, newest first.
Response:
{
"data": [
{
"id": "whd_01ABC",
"endpoint_id": "we_01XYZ",
"event_id": "evt_01ABC",
"event_type": "invoice.paid",
"status": "delivered",
"http_status": 200,
"attempts": 1,
"error_message": null,
"created_at": "2026-07-20T10:00:00Z",
"delivered_at": "2026-07-20T10:00:01Z"
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}
Try it
Get Webhook Delivery¶
Response:
{
"data": {
"id": "whd_01ABC",
"endpoint_id": "we_01XYZ",
"event_id": "evt_01ABC",
"event_type": "invoice.paid",
"status": "failed",
"http_status": 500,
"attempts": 3,
"error_message": "Upstream returned 500",
"created_at": "2026-07-20T10:00:00Z",
"delivered_at": null
}
}
Try it
Webhook Delivery Statuses¶
| Status | Description |
|---|---|
pending |
Created, not yet attempted |
retrying |
An attempt failed and another is scheduled. attempts says how many have been made; the backoff is 30s, 2m, 10m then 50m |
delivered |
The endpoint answered 2xx |
failed |
Five attempts were made and none succeeded |
Retry Webhook Delivery¶
Re-queues a delivery for another attempt. Only deliveries in failed or pending status can be retried; the attempt counter is reset and re-delivery is triggered in the background.
Response 200 OK:
{
"data": {
"id": "whd_01ABC",
"endpoint_id": "we_01XYZ",
"event_id": "evt_01ABC",
"event_type": "invoice.paid",
"status": "pending",
"http_status": null,
"attempts": 0,
"error_message": null,
"created_at": "2026-07-20T10:00:00Z",
"delivered_at": null
}
}
Retrying a delivery that is already delivered returns 409 Conflict: