Skip to content

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.created
  • invoice.updated
  • invoice.finalized
  • invoice.sent
  • invoice.paid
  • invoice.voided
  • render.queued
  • render.completed
  • render.failed
  • batch.completed
  • batch.failed
  • delivery.sent
  • delivery.failed

Create Webhook Endpoint

POST /api/v1/webhook-endpoints

A signing secret (whsec_...) is generated automatically and used to sign every delivery. 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,
    "created_at": "2026-07-20T10:00:00Z",
    "updated_at": "2026-07-20T10:00:00Z"
  }
}
Try it

List Webhook Endpoints

GET /api/v1/webhook-endpoints?limit=50

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

GET /api/v1/webhook-endpoints/{endpoint_id}

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

PATCH /api/v1/webhook-endpoints/{endpoint_id}

Only include the fields you want to change:

{
  "events": ["invoice.created", "invoice.paid", "invoice.voided"],
  "is_active": false
}
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

DELETE /api/v1/webhook-endpoints/{endpoint_id}

Response:

{
  "data": {
    "deleted": true
  }
}
Try it

Rotate Signing Secret

POST /api/v1/webhook-endpoints/{endpoint_id}/rotate-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:

{
  "data": {
    "secret": "whsec_9fK2pQx7RzW..."
  }
}
Try it

Send a Test Event

POST /api/v1/webhook-endpoints/{endpoint_id}/test

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

GET /api/v1/webhook-deliveries?limit=50

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

GET /api/v1/webhook-deliveries/{delivery_id}

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

Retry Webhook Delivery

POST /api/v1/webhook-deliveries/{delivery_id}/retry

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:

{
  "error": {
    "code": "conflict",
    "message": "Only failed or pending deliveries can be retried"
  }
}
Try it