From 29020bcbedcbefb428e8f7d04804436e44a5c6fa Mon Sep 17 00:00:00 2001 From: Ephraim Duncan Date: Mon, 3 Aug 2026 02:16:39 +0000 Subject: [PATCH] docs(webhooks): correct retry policy, timeout and payload reference (#3132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Corrects the webhooks documentation, which described delivery behavior that does not exist in the implementation. ## Changes Made - Replaced the fabricated retry schedule (5 attempts / immediate-to-2h backoff) with the real provider-dependent behavior: retries belong to the job provider (`NEXT_PRIVATE_JOBS_PROVIDER`) — local (default) 4 total attempts back-to-back, BullMQ 3 attempts with exponential backoff from 1s, Inngest 5 attempts with platform backoff. - Fixed the webhook timeout from 30 seconds to 10 seconds (`WEBHOOK_TIMEOUT_MS = 10_000`, hard abort). - Clarified failure semantics: non-2xx fails, 3xx redirects are not followed (`redirect: 'manual'`), network/SSRF-blocked calls record response code 0; failed deliveries mark only the `WebhookCall` record — the webhook itself is never auto-disabled. - Corrected URL requirements: `http://` is accepted; documented the SSRF guard (private/loopback blocked, `NEXT_PRIVATE_WEBHOOK_SSRF_BYPASS_HOSTS` bypass for self-hosters). - Added `envelopeId` to both field tables and all payload/recipient JSON examples; framed numeric `id` as the legacy v1 identifier. - Removed a documented `documentMeta` field that exists in neither the Zod schema nor Prisma; fixed timezone/dateFormat examples to the hardcoded `Etc/UTC` / `yyyy-MM-dd hh:mm a` values. - Added missing `REJECTED`/`CANCELLED` statuses and `TEMPLATE_DIRECT_LINK` source; fixed `templateId` to `null` on TEMPLATE_* examples; documented the previously missing `RECIPIENT_EXPIRED` event across setup, events, and verification pages. ## Testing Performed Docs-only change. Every claim verified against the implementation (`execute-webhook-call.ts`, job clients, `webhook-payload.ts`, `assert-webhook-url.ts`, webhook-router schema). --- .../docs/developers/webhooks/events.mdx | 115 ++++++++++++++---- .../docs/developers/webhooks/index.mdx | 6 +- .../docs/developers/webhooks/setup.mdx | 39 +++--- .../docs/developers/webhooks/verification.mdx | 1 + 4 files changed, 122 insertions(+), 39 deletions(-) diff --git a/apps/docs/content/docs/developers/webhooks/events.mdx b/apps/docs/content/docs/developers/webhooks/events.mdx index 9f63f78ac..5bfaa7a42 100644 --- a/apps/docs/content/docs/developers/webhooks/events.mdx +++ b/apps/docs/content/docs/developers/webhooks/events.mdx @@ -33,13 +33,14 @@ All webhook events share a common structure: | Field | Type | Description | | ---------------- | --------- | ------------------------------------------------------ | -| `id` | number | Document or template ID | +| `id` | number | Legacy numeric v1 document or template ID | +| `envelopeId` | string | Canonical v2 identifier (`envelope_` + 16 characters) | | `externalId` | string? | External identifier for integration | | `userId` | number | Owner's user ID | | `authOptions` | object? | Document-level authentication options | | `formValues` | object? | PDF form values associated with the document | | `title` | string | Document or template title | -| `status` | string | Current status: `DRAFT`, `PENDING`, `COMPLETED` | +| `status` | string | Current status: `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED`, `CANCELLED` | | `visibility` | string | Document visibility setting | | `createdAt` | datetime | Document creation timestamp | | `updatedAt` | datetime | Last modification timestamp | @@ -47,8 +48,8 @@ All webhook events share a common structure: | `deletedAt` | datetime? | Deletion timestamp | | `teamId` | number? | Team ID if document belongs to a team | | `templateId` | number? | Template ID if created from a template | -| `source` | string | Source: `DOCUMENT` or `TEMPLATE` | -| `documentMeta` | object | Document metadata (subject, message, signing options) | +| `source` | string | Source: `DOCUMENT`, `TEMPLATE`, or `TEMPLATE_DIRECT_LINK` | +| `documentMeta` | object? | Nullable document metadata (subject, message, signing options) | | `recipients` | array | List of recipient objects | | `Recipient` | array | List of recipient objects (legacy, same as recipients) | @@ -60,7 +61,6 @@ All webhook events share a common structure: | `subject` | string? | Email subject line | | `message` | string? | Email message body | | `timezone` | string | Timezone for date display | -| `password` | string? | Document access password (if set) | | `dateFormat` | string | Date format string | | `redirectUrl` | string? | URL to redirect after signing | | `signingOrder` | string | `PARALLEL` or `SEQUENTIAL` | @@ -77,8 +77,9 @@ All webhook events share a common structure: | Field | Type | Description | | ---------------------- | --------- | ------------------------------------------ | | `id` | number | Recipient ID | -| `documentId` | number? | Parent document ID | -| `templateId` | number? | Template ID if created from a template | +| `envelopeId` | string | Canonical parent envelope ID | +| `documentId` | number? | Legacy parent document ID; null for templates | +| `templateId` | number? | Legacy parent template ID; null for documents | | `email` | string | Recipient email address | | `name` | string | Recipient name | | `token` | string | Unique signing token | @@ -94,6 +95,8 @@ All webhook events share a common structure: | `sendStatus` | string | `NOT_SENT` or `SENT` | | `rejectionReason` | string? | Reason if recipient rejected | +Use `recipient.envelopeId` as the reliable parent link. The legacy `documentId` and `templateId` fields depend on the parent envelope type, so one of them is always null. + --- ## Document Lifecycle Events @@ -111,6 +114,7 @@ Triggered when a new document is created. "event": "DOCUMENT_CREATED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "externalId": null, "userId": 1, "authOptions": null, @@ -129,9 +133,8 @@ Triggered when a new document is created. "id": "doc_meta_123", "subject": "Please sign this document", "message": "Hello, please review and sign this document.", - "timezone": "UTC", - "password": null, - "dateFormat": "MM/DD/YYYY", + "timezone": "Etc/UTC", + "dateFormat": "yyyy-MM-dd hh:mm a", "redirectUrl": null, "signingOrder": "PARALLEL", "allowDictateNextSigner": false, @@ -145,6 +148,7 @@ Triggered when a new document is created. "recipients": [ { "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 10, "templateId": null, "email": "signer@example.com", @@ -166,6 +170,7 @@ Triggered when a new document is created. "Recipient": [ { "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 10, "templateId": null, "email": "signer@example.com", @@ -203,6 +208,7 @@ The document status changes to `PENDING` and recipients have `sendStatus: "SENT" "event": "DOCUMENT_SENT", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "externalId": null, "userId": 1, "authOptions": null, @@ -221,9 +227,8 @@ The document status changes to `PENDING` and recipients have `sendStatus: "SENT" "id": "doc_meta_123", "subject": "Please sign this document", "message": "Hello, please review and sign this document.", - "timezone": "UTC", - "password": null, - "dateFormat": "MM/DD/YYYY", + "timezone": "Etc/UTC", + "dateFormat": "yyyy-MM-dd hh:mm a", "redirectUrl": null, "signingOrder": "PARALLEL", "allowDictateNextSigner": false, @@ -237,6 +242,7 @@ The document status changes to `PENDING` and recipients have `sendStatus: "SENT" "recipients": [ { "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 10, "templateId": null, "email": "signer@example.com", @@ -258,6 +264,7 @@ The document status changes to `PENDING` and recipients have `sendStatus: "SENT" "Recipient": [ { "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 10, "templateId": null, "email": "signer@example.com", @@ -295,12 +302,14 @@ The recipient's `readStatus` changes to `OPENED`. "event": "DOCUMENT_OPENED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "status": "PENDING", "title": "contract.pdf", "source": "DOCUMENT", "recipients": [ { "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", "email": "signer@example.com", "name": "John Doe", "role": "SIGNER", @@ -328,6 +337,7 @@ The recipient's `signingStatus` changes to `SIGNED` and `signedAt` is populated. "event": "DOCUMENT_SIGNED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "status": "COMPLETED", "title": "contract.pdf", "source": "DOCUMENT", @@ -335,6 +345,7 @@ The recipient's `signingStatus` changes to `SIGNED` and `signedAt` is populated. "recipients": [ { "id": 51, + "envelopeId": "envelope_abcdefhiklmnorst", "email": "signer@example.com", "name": "John Doe", "role": "SIGNER", @@ -361,12 +372,14 @@ Triggered when an individual recipient completes their required action (signing, "event": "DOCUMENT_RECIPIENT_COMPLETED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "status": "PENDING", "title": "contract.pdf", "source": "DOCUMENT", "recipients": [ { "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", "email": "signer@example.com", "name": "John Doe", "role": "SIGNER", @@ -395,6 +408,7 @@ The document status changes to `COMPLETED` and `completedAt` is set. "event": "DOCUMENT_COMPLETED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "externalId": null, "userId": 1, "authOptions": null, @@ -413,9 +427,8 @@ The document status changes to `COMPLETED` and `completedAt` is set. "id": "doc_meta_123", "subject": "Please sign this document", "message": "Hello, please review and sign this document.", - "timezone": "UTC", - "password": null, - "dateFormat": "MM/DD/YYYY", + "timezone": "Etc/UTC", + "dateFormat": "yyyy-MM-dd hh:mm a", "redirectUrl": null, "signingOrder": "PARALLEL", "allowDictateNextSigner": false, @@ -429,6 +442,7 @@ The document status changes to `COMPLETED` and `completedAt` is set. "recipients": [ { "id": 50, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 10, "templateId": null, "email": "reviewer@example.com", @@ -451,6 +465,7 @@ The document status changes to `COMPLETED` and `completedAt` is set. }, { "id": 51, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 10, "templateId": null, "email": "signer@example.com", @@ -475,6 +490,7 @@ The document status changes to `COMPLETED` and `completedAt` is set. "Recipient": [ { "id": 50, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 10, "templateId": null, "email": "reviewer@example.com", @@ -497,6 +513,7 @@ The document status changes to `COMPLETED` and `completedAt` is set. }, { "id": 51, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 10, "templateId": null, "email": "signer@example.com", @@ -537,12 +554,14 @@ The recipient's `signingStatus` changes to `REJECTED` and `rejectionReason` cont "event": "DOCUMENT_REJECTED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "status": "PENDING", "title": "contract.pdf", "source": "DOCUMENT", "recipients": [ { "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", "email": "signer@example.com", "name": "John Doe", "role": "SIGNER", @@ -561,7 +580,7 @@ The recipient's `signingStatus` changes to `REJECTED` and `rejectionReason` cont ### `document.cancelled` -Triggered when the document owner or a team member deletes a document. Draft and pending documents are hard-deleted, while completed documents are soft-deleted. +Triggered when a pending document is explicitly cancelled with `POST /envelope/cancel`, or when a document owner or team member deletes a document. Deleting a draft or pending document hard-deletes it, while deleting a completed document soft-deletes it. This event is **not** triggered when a recipient hides a document from their inbox. @@ -572,6 +591,7 @@ This event is **not** triggered when a recipient hides a document from their inb "event": "DOCUMENT_CANCELLED", "payload": { "id": 7, + "envelopeId": "envelope_abcdefhiklmnorst", "externalId": null, "userId": 3, "authOptions": null, @@ -591,7 +611,6 @@ This event is **not** triggered when a recipient hides a document from their inb "subject": "", "message": "", "timezone": "Etc/UTC", - "password": null, "dateFormat": "yyyy-MM-dd hh:mm a", "redirectUrl": "", "signingOrder": "PARALLEL", @@ -606,6 +625,7 @@ This event is **not** triggered when a recipient hides a document from their inb "recipients": [ { "id": 7, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 7, "templateId": null, "email": "signer@example.com", @@ -627,6 +647,7 @@ This event is **not** triggered when a recipient hides a document from their inb "Recipient": [ { "id": 7, + "envelopeId": "envelope_abcdefhiklmnorst", "documentId": 7, "templateId": null, "email": "signer@example.com", @@ -651,6 +672,45 @@ This event is **not** triggered when a recipient hides a document from their inb } ``` +### `recipient.expired` + +Triggered when a recipient's signing deadline passes on a pending document before they sign or reject it. + +**Event name:** `RECIPIENT_EXPIRED` + +The recipient's `expiresAt` contains the signing deadline, and `expirationNotifiedAt` is set when the expiration is processed. + +```json +{ + "event": "RECIPIENT_EXPIRED", + "payload": { + "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", + "status": "PENDING", + "title": "contract.pdf", + "source": "DOCUMENT", + "recipients": [ + { + "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", + "documentId": 10, + "templateId": null, + "email": "signer@example.com", + "name": "John Doe", + "role": "SIGNER", + "expiresAt": "2024-04-22T11:51:00.000Z", + "expirationNotifiedAt": "2024-04-22T11:52:00.000Z", + "readStatus": "OPENED", + "signingStatus": "NOT_SIGNED", + "sendStatus": "SENT" + } + ] + }, + "createdAt": "2024-04-22T11:52:00.000Z", + "webhookEndpoint": "https://your-endpoint.com/webhook" +} +``` + ### `document.reminder.sent` Triggered when a reminder email is sent to a recipient who has not yet completed their action. @@ -662,12 +722,14 @@ Triggered when a reminder email is sent to a recipient who has not yet completed "event": "DOCUMENT_REMINDER_SENT", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "status": "PENDING", "title": "contract.pdf", "source": "DOCUMENT", "recipients": [ { "id": 52, + "envelopeId": "envelope_abcdefhiklmnorst", "email": "signer@example.com", "name": "John Doe", "role": "SIGNER", @@ -686,7 +748,7 @@ Triggered when a reminder email is sent to a recipient who has not yet completed ## Template Events -Template events track changes to reusable document templates. Template payloads use the same structure as document payloads, with `source` set to `TEMPLATE` and `templateId` populated. +Template events track changes to reusable document templates. Template payloads use the same structure as document payloads. For `TEMPLATE_CREATED`, `TEMPLATE_UPDATED`, and `TEMPLATE_DELETED` the template's own legacy numeric ID is in `id` and `templateId` is `null`. Only `TEMPLATE_USED` — whose payload describes the new document envelope created from the template — carries the originating template's legacy ID in `templateId`, with `source` set to `TEMPLATE`. ### `template.created` @@ -699,9 +761,10 @@ Triggered when a new template is created. "event": "TEMPLATE_CREATED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "title": "My Template", "status": "DRAFT", - "templateId": 10, + "templateId": null, "source": "TEMPLATE", "recipients": [] }, @@ -721,9 +784,10 @@ Triggered when a template's settings, recipients, or fields are modified. "event": "TEMPLATE_UPDATED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "title": "My Updated Template", "status": "DRAFT", - "templateId": 10, + "templateId": null, "source": "TEMPLATE", "recipients": [] }, @@ -743,9 +807,10 @@ Triggered when a template is deleted. "event": "TEMPLATE_DELETED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "title": "Deleted Template", "status": "DRAFT", - "templateId": 10, + "templateId": null, "source": "TEMPLATE", "recipients": [] }, @@ -765,6 +830,7 @@ Triggered when a document is created from a template. This event fires alongside "event": "TEMPLATE_USED", "payload": { "id": 10, + "envelopeId": "envelope_abcdefhiklmnorst", "title": "Document from Template", "status": "DRAFT", "templateId": 10, @@ -791,7 +857,8 @@ Triggered when a document is created from a template. This event fires alongside | `DOCUMENT_RECIPIENT_COMPLETED` | Recipient completes their action | Recipient `signingStatus: "SIGNED"`, `signedAt` set | | `DOCUMENT_COMPLETED` | All recipients complete actions | `status: "COMPLETED"`, `completedAt` set | | `DOCUMENT_REJECTED` | Recipient rejects document | Recipient `signingStatus: "REJECTED"`, `rejectionReason` set | -| `DOCUMENT_CANCELLED` | Owner or team member deletes document | Document cancelled or deleted | +| `DOCUMENT_CANCELLED` | Pending document explicitly cancelled, or document deleted | `status: "CANCELLED"` after explicit cancellation; deletion may remove or soft-delete the document | +| `RECIPIENT_EXPIRED` | Recipient signing deadline passes | Recipient `expiresAt` passed, `expirationNotifiedAt` set | | `DOCUMENT_REMINDER_SENT` | Reminder email sent to recipient | No status changes | ### Template Events @@ -821,7 +888,7 @@ When processing webhook events: **Process idempotently** — Webhooks may be retried, so handle duplicate events - **Respond quickly** — Return a 200 status code within 30 seconds + **Respond quickly** — Return a `2xx` status code within 10 seconds diff --git a/apps/docs/content/docs/developers/webhooks/index.mdx b/apps/docs/content/docs/developers/webhooks/index.mdx index 14bb89123..8c27eccbd 100644 --- a/apps/docs/content/docs/developers/webhooks/index.mdx +++ b/apps/docs/content/docs/developers/webhooks/index.mdx @@ -9,7 +9,7 @@ description: Receive real-time notifications for document and template events. 2. When an event occurs, Documenso sends an HTTP POST to your URL 3. Your application processes the event and responds with 200 OK -Documenso supports webhook events for the full document lifecycle (created, sent, opened, signed, completed, rejected, cancelled) as well as template events (created, updated, deleted, used). +Documenso supports webhook events for the full document lifecycle (created, sent, opened, signed, completed, rejected, cancelled), recipient-level events (recipient completed, reminder sent, recipient expired), and template events (created, updated, deleted, used). --- @@ -42,12 +42,14 @@ Documenso supports webhook events for the full document lifecycle (created, sent "event": "DOCUMENT_COMPLETED", "payload": { "id": 123, + "envelopeId": "envelope_abcdefhiklmnorst", "title": "Contract", "status": "COMPLETED", "completedAt": "2024-01-15T10:30:00.000Z", "recipients": [ { "id": 1, + "envelopeId": "envelope_abcdefhiklmnorst", "email": "signer@example.com", "signingStatus": "SIGNED" } @@ -58,6 +60,8 @@ Documenso supports webhook events for the full document lifecycle (created, sent } ``` +`payload.id` is the legacy numeric v1 ID. Use `payload.envelopeId` as the canonical v2 identifier. Each recipient repeats `envelopeId` as the reliable parent link because the legacy `documentId` and `templateId` fields depend on the parent envelope type, leaving one of them null. + --- ## See Also diff --git a/apps/docs/content/docs/developers/webhooks/setup.mdx b/apps/docs/content/docs/developers/webhooks/setup.mdx index 1725bec05..88fda57ea 100644 --- a/apps/docs/content/docs/developers/webhooks/setup.mdx +++ b/apps/docs/content/docs/developers/webhooks/setup.mdx @@ -148,7 +148,7 @@ func main() { - Always respond with a `200 OK` status within 30 seconds. Documenso will retry failed deliveries. + Always respond with a `2xx` status within 10 seconds. Documenso will retry failed deliveries according to the configured background-job provider. ## Configuring Webhooks in Documenso via the Dashboard @@ -184,7 +184,7 @@ Fill in the following fields: | Field | Description | | ----- | ----------- | -| **Webhook URL** | The HTTPS endpoint that will receive webhook events | +| **Webhook URL** | The HTTP or HTTPS endpoint that will receive webhook events | | **Events** | Select which events should trigger this webhook | | **Secret** (optional) | A secret key used to sign the payload for verification | @@ -202,12 +202,21 @@ Your webhook endpoint must meet these requirements: | Requirement | Details | | ----------- | ------- | -| **Protocol** | HTTPS required (HTTP not allowed in production) | -| **Response** | Must return `2xx` status code within 30 seconds | +| **Protocol** | HTTP and HTTPS are accepted; use HTTPS in production | +| **Response** | Must return a `2xx` status code within 10 seconds | | **Method** | Must accept HTTP POST requests | | **Content-Type** | Must accept `application/json` payloads | | **Availability** | Must be publicly accessible from the internet | + + Documenso performs a best-effort check that rejects webhook URLs which use or resolve to private + or loopback addresses. This is not a complete SSRF mitigation — it does not cover DNS rebinding + and fails open on DNS lookup errors or timeouts — so self-hosted deployments should still enforce + network-level egress rules. Self-hosters that need to deliver to a hostname resolving to a + private address can add that hostname to the comma-separated + `NEXT_PRIVATE_WEBHOOK_SSRF_BYPASS_HOSTS` environment variable. + + For local development, use a tunneling service like [ngrok](https://ngrok.com) or [localtunnel](https://localtunnel.me) to expose your local server. @@ -225,7 +234,8 @@ When creating a webhook, you can subscribe to one or more events: | `DOCUMENT_RECIPIENT_COMPLETED` | A recipient completes their required action | | `DOCUMENT_COMPLETED` | All recipients have completed their actions | | `DOCUMENT_REJECTED` | A recipient rejects the document | -| `DOCUMENT_CANCELLED` | The document owner deletes the document | +| `DOCUMENT_CANCELLED` | A pending document is explicitly cancelled or a document owner deletes it | +| `RECIPIENT_EXPIRED` | A recipient's signing deadline passes before they sign or reject | | `DOCUMENT_REMINDER_SENT` | A reminder email is sent to a recipient | | `TEMPLATE_CREATED` | A new template is created | | `TEMPLATE_UPDATED` | A template is modified | @@ -294,6 +304,7 @@ Each webhook call shows the following details: - Timestamp - Response code - Request and response bodies +- Response headers Click any call to see full details including headers and response data. @@ -318,17 +329,17 @@ Documenso will attempt to deliver the same payload again ## Retry Policy -When a webhook delivery fails (non-2xx response or timeout), Documenso automatically retries with exponential backoff: +A delivery fails when the endpoint returns a non-`2xx` response, the 10-second timeout expires, or the request fails. Redirects are not followed, so `3xx` responses also fail. Network and SSRF-blocked requests are recorded with response code `0`. -| Attempt | Delay | -| ------- | ----- | -| 1 | Immediate | -| 2 | 1 minute | -| 3 | 5 minutes | -| 4 | 30 minutes | -| 5 | 2 hours | +For self-hosted deployments, retries are handled by the background-job provider selected with `NEXT_PRIVATE_JOBS_PROVIDER`: -After 5 failed attempts, the webhook is marked as failed and no further automatic retries occur. You can manually resend failed webhooks from the dashboard. +| Provider | Total attempts | Retry timing | +| -------- | -------------- | ------------ | +| Local (default) | 4 | Back-to-back, with no backoff | +| BullMQ | 3 | Exponential backoff starting at 1 second | +| Inngest | 5 | Inngest platform backoff | + +Only the individual delivery (`WebhookCall`) record is marked as failed. Documenso does not automatically disable the webhook or apply a circuit breaker, so future matching events continue to be delivered. After automatic attempts are exhausted, you can manually resend a failed delivery from the dashboard. If your endpoint consistently fails, consider reviewing your server logs and ensuring your endpoint meets all [URL requirements](#webhook-url-requirements). diff --git a/apps/docs/content/docs/developers/webhooks/verification.mdx b/apps/docs/content/docs/developers/webhooks/verification.mdx index a6cac916d..751d30d89 100644 --- a/apps/docs/content/docs/developers/webhooks/verification.mdx +++ b/apps/docs/content/docs/developers/webhooks/verification.mdx @@ -255,6 +255,7 @@ const validEvents = [ 'DOCUMENT_REJECTED', 'DOCUMENT_CANCELLED', 'DOCUMENT_REMINDER_SENT', + 'RECIPIENT_EXPIRED', 'TEMPLATE_CREATED', 'TEMPLATE_UPDATED', 'TEMPLATE_DELETED',