{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Webhooks"},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"webhooks","__idx":0},"children":["Webhooks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Signing session webhooks keep your application up to date without polling. Webhooks are session-specific: add up to two endpoints when you ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/embed-api/openapi/signing/createsigningsession"},"children":["create a signing session"]},", and each endpoint receives every event for that session."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"webhooks\": [\n    {\n      \"url\": \"https://example.com/webhooks/signing\",\n      \"secret\": \"your-shared-secret\"\n    }\n  ]\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["We recommend configuring a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["secret"]}," and validating every delivery."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"delivery-behavior","__idx":1},"children":["Delivery behavior"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Docue sends each event as an HTTP ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST"]}," with:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Content-Type: application/json"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Id"]},": identifies this endpoint delivery and remains the same across retries"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Sent-At"]},": UTC time (ISO 8601, e.g. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2026-02-12T10:31:00.000Z"]},") when this delivery attempt was sent. It is refreshed on every retry, while the request body stays identical"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Signature"]},": included when a secret is configured"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Return any ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2xx"]}," response within five seconds to acknowledge the delivery. Acknowledge quickly and do any heavy processing asynchronously on your side. Timeouts, network errors, and non-",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2xx"]}," responses are treated as failures and retried. Deliveries can therefore arrive more than once or out of order. Make processing idempotent using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["event.meta.id"]},", which identifies the business event independently of its endpoint delivery."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"retries","__idx":2},"children":["Retries"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Failed deliveries are retried with an increasing backoff, up to ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["8 attempts"]}," in total (the initial delivery plus 7 retries). The wait before each retry is:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"After failed attempt"},"children":["After failed attempt"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Wait before next attempt"},"children":["Wait before next attempt"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["1"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["5 seconds"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["2"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["5 minutes"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["30 minutes"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["4"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["2 hours"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["5"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["5 hours"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["6"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["10 hours"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["7"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["10 hours"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If the 8th attempt also fails, the delivery is marked ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["exhausted"]}," and no further retries are made."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/embed-api/openapi/signing/listsigningsessionwebhookcalls"},"children":["List recent webhook delivery attempts"]}," to inspect delivery status (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["pending"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivered"]},", or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["exhausted"]},"), attempt count, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["retry_after"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["last_error"]}," for a session."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"event-format","__idx":3},"children":["Event format"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The body contains the event and resource snapshots as they were when the event occurred:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:00.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"signed\",\n        \"status_changed_at\": \"2026-02-12T10:31:00.000Z\",\n        \"decline_reason\": null\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.participant.signed\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88411\",\n      \"timestamp\": \"2026-02-12T10:31:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["event.meta.type"]}," to route the event. Every payload contains ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["workspace"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["session"]},"; the other fields depend on the event type. Session snapshots contain ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status_changed_at"]},". Participant snapshots contain ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["session_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status_changed_at"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["decline_reason"]},". Invitation snapshots contain ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["participant_id"]},", and a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["timeline"]}," with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["created_at"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sent_at"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["opened_at"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["revoked_at"]},". ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_id"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["decline_reason"]}," are ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["null"]}," when unset."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"event-types","__idx":4},"children":["Event types"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Expand an event type to see a full webhook request body. Status values below are representative of when each event is typically delivered; always read the live ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status_changed_at"]}," fields from the payload."]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.session.created"]}," — The session is created."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:00.000Z\"\n      },\n      \"participants\": [\n        {\n          \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n          \"external_id\": \"user-123\",\n          \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n          \"status\": \"pending\",\n          \"status_changed_at\": \"2026-02-12T10:30:00.000Z\",\n          \"decline_reason\": null\n        }\n      ],\n      \"invitations\": [\n        {\n          \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88311\",\n          \"participant_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n          \"timeline\": {\n            \"created_at\": \"2026-02-12T10:30:00.000Z\",\n            \"sent_at\": null,\n            \"opened_at\": null,\n            \"revoked_at\": null\n          }\n        }\n      ]\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.session.created\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88411\",\n      \"timestamp\": \"2026-02-12T10:30:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.session.started"]}," — The session is started."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:05.000Z\"\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.session.started\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88412\",\n      \"timestamp\": \"2026-02-12T10:30:05.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.session.cancelled"]}," — The session is cancelled."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"cancelled\",\n        \"status_changed_at\": \"2026-02-12T11:00:00.000Z\"\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.session.cancelled\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88415\",\n      \"timestamp\": \"2026-02-12T11:00:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.session.discarded"]}," — The session is discarded."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"discarded\",\n        \"status_changed_at\": \"2026-02-12T11:00:00.000Z\"\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.session.discarded\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88413\",\n      \"timestamp\": \"2026-02-12T11:00:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.session.completed"]}," — Every participant has signed."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"completed\",\n        \"status_changed_at\": \"2026-02-12T10:45:00.000Z\"\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.session.completed\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88414\",\n      \"timestamp\": \"2026-02-12T10:45:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.session.expired"]}," — The session expired before it was completed."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"expired\",\n        \"status_changed_at\": \"2026-02-13T08:00:00.000Z\"\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.session.expired\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88415\",\n      \"timestamp\": \"2026-02-13T08:00:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.session.renewed"]}," — An expired session is renewed with a new due date."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-13T09:00:00.000Z\"\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.session.renewed\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88416\",\n      \"timestamp\": \"2026-02-13T09:00:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.participant.added"]}," — A participant is added."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:00.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88212\",\n        \"external_id\": \"user-124\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:10.000Z\",\n        \"decline_reason\": null\n      },\n      \"invitations\": [\n        {\n          \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88321\",\n          \"participant_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88212\",\n          \"timeline\": {\n            \"created_at\": \"2026-02-12T10:30:10.000Z\",\n            \"sent_at\": null,\n            \"opened_at\": null,\n            \"revoked_at\": null\n          }\n        }\n      ]\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.participant.added\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88415\",\n      \"timestamp\": \"2026-02-12T10:30:10.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.participant.removed"]}," — A participant is removed."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:00.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88212\",\n        \"external_id\": \"user-124\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:10.000Z\",\n        \"decline_reason\": null\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.participant.removed\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88416\",\n      \"timestamp\": \"2026-02-12T10:30:20.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.participant.signed"]}," — A participant signs."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:05.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"signed\",\n        \"status_changed_at\": \"2026-02-12T10:36:00.000Z\",\n        \"decline_reason\": null\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.participant.signed\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88418\",\n      \"timestamp\": \"2026-02-12T10:36:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.participant.declined"]}," — A participant declines to sign."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:05.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"declined\",\n        \"status_changed_at\": \"2026-02-12T10:38:00.000Z\",\n        \"decline_reason\": \"I do not agree with the terms.\"\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.participant.declined\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88417\",\n      \"timestamp\": \"2026-02-12T10:38:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.participant.excused"]}," — A participant is excused from signing."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:40:00.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"excused\",\n        \"status_changed_at\": \"2026-02-12T10:42:00.000Z\",\n        \"decline_reason\": null\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.participant.excused\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88422\",\n      \"timestamp\": \"2026-02-12T10:42:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.participant.reinstated"]}," — A declined participant is brought back to pending."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:40:00.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:45:00.000Z\",\n        \"decline_reason\": null\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.participant.reinstated\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88421\",\n      \"timestamp\": \"2026-02-12T10:45:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.invitation.created"]}," — An invitation is created."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:05.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:00.000Z\",\n        \"decline_reason\": null\n      },\n      \"invitation\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88311\",\n        \"participant_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"timeline\": {\n          \"created_at\": \"2026-02-12T10:30:05.000Z\",\n          \"sent_at\": null,\n          \"opened_at\": null,\n          \"revoked_at\": null\n        }\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.invitation.created\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88419\",\n      \"timestamp\": \"2026-02-12T10:30:05.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.invitation.sent"]}," — An invitation is sent by email or SMS. Resends fire ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["invitation.resent"]}," instead."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:05.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:00.000Z\",\n        \"decline_reason\": null\n      },\n      \"invitation\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88311\",\n        \"participant_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"timeline\": {\n          \"created_at\": \"2026-02-12T10:30:05.000Z\",\n          \"sent_at\": \"2026-02-12T10:30:06.000Z\",\n          \"opened_at\": null,\n          \"revoked_at\": null\n        }\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.invitation.sent\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f8841c\",\n      \"timestamp\": \"2026-02-12T10:30:06.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.invitation.resent"]}," — An invitation is sent again on request. The signing link stays the same."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:05.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:00.000Z\",\n        \"decline_reason\": null\n      },\n      \"invitation\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88311\",\n        \"participant_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"timeline\": {\n          \"created_at\": \"2026-02-12T10:30:05.000Z\",\n          \"sent_at\": \"2026-02-12T10:30:06.000Z\",\n          \"opened_at\": null,\n          \"revoked_at\": null\n        }\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.invitation.resent\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f8841d\",\n      \"timestamp\": \"2026-02-12T10:45:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.invitation.opened"]}," — An invitation is opened."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:05.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"viewing\",\n        \"status_changed_at\": \"2026-02-12T10:32:00.000Z\",\n        \"decline_reason\": null\n      },\n      \"invitation\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88311\",\n        \"participant_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"timeline\": {\n          \"created_at\": \"2026-02-12T10:30:05.000Z\",\n          \"sent_at\": \"2026-02-12T10:30:06.000Z\",\n          \"opened_at\": \"2026-02-12T10:32:00.000Z\",\n          \"revoked_at\": null\n        }\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.invitation.opened\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f8841a\",\n      \"timestamp\": \"2026-02-12T10:32:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"details","attributes":{},"children":[{"$$mdtype":"Tag","name":"summary","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.docue.sign.v1.invitation.revoked"]}," — An invitation is revoked."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"event\": {\n    \"payload\": {\n      \"workspace\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88001\"\n      },\n      \"session\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"external_id\": \"deal-42\",\n        \"status\": \"started\",\n        \"status_changed_at\": \"2026-02-12T10:30:05.000Z\"\n      },\n      \"participant\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"external_id\": \"user-123\",\n        \"session_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f881fd\",\n        \"status\": \"pending\",\n        \"status_changed_at\": \"2026-02-12T10:30:00.000Z\",\n        \"decline_reason\": null\n      },\n      \"invitation\": {\n        \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88311\",\n        \"participant_id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f88211\",\n        \"timeline\": {\n          \"created_at\": \"2026-02-12T10:30:05.000Z\",\n          \"sent_at\": \"2026-02-12T10:30:06.000Z\",\n          \"opened_at\": null,\n          \"revoked_at\": \"2026-02-12T10:40:00.000Z\"\n        }\n      }\n    },\n    \"meta\": {\n      \"type\": \"com.docue.sign.v1.invitation.revoked\",\n      \"id\": \"0196ae5b-2e9d-729f-aba5-fa4db6f8841b\",\n      \"timestamp\": \"2026-02-12T10:40:00.000Z\"\n    }\n  }\n}\n","lang":"json"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"verify-webhook-signatures","__idx":5},"children":["Verify webhook signatures"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a secret is configured, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Signature"]}," is the lowercase hexadecimal HMAC-SHA256 digest of the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Sent-At"]}," value, a dot, and the exact raw request body:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"X-Webhook-Signature = hex(HMAC-SHA256(secret, X-Webhook-Sent-At + \".\" + raw_request_body))\n"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Validate the signature before parsing JSON. Do not compute it from a parsed and re-serialized body, because changes to whitespace, property order, or escaping change the digest. Compare signatures in constant time."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Because the send time is covered by the signature, you can use it to reject replayed requests. After the signature is valid, reject the request if ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Sent-At"]}," is more than five minutes away from your current time. Each retry is sent with a fresh ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Sent-At"]}," and signature, so legitimate retries pass this check. It does not replace idempotency: still ignore events whose ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["event.meta.id"]}," you have already processed."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This Express example receives the raw body, validates it, and only then processes the event:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"js","header":{"controls":{"copy":{}}},"source":"import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport express from \"express\";\n\nconst app = express();\nconst secret = process.env.DOCUE_WEBHOOK_SECRET;\n\nif (!secret) throw new Error(\"DOCUE_WEBHOOK_SECRET is required\");\n\napp.post(\n  \"/webhooks/signing\",\n  express.raw({ type: \"application/json\" }),\n  (request, response) => {\n    const signature = request.get(\"X-Webhook-Signature\") ?? \"\";\n    const sentAt = request.get(\"X-Webhook-Sent-At\") ?? \"\";\n    const expected = createHmac(\"sha256\", secret)\n      .update(`${sentAt}.`)\n      .update(request.body)\n      .digest(\"hex\");\n\n    const valid = /^[a-f0-9]{64}$/.test(signature)\n      && timingSafeEqual(Buffer.from(signature, \"hex\"), Buffer.from(expected, \"hex\"));\n\n    if (!valid) return response.sendStatus(401);\n\n    // Reject replays: the send time is signed, so it can be trusted here.\n    const ageMs = Math.abs(Date.now() - Date.parse(sentAt));\n    if (!(ageMs <= 5 * 60 * 1000)) return response.sendStatus(401);\n\n    const { event } = JSON.parse(request.body.toString(\"utf8\"));\n\n    // Ignore the event if event.meta.id has already been processed.\n    console.log(event.meta.type, event.payload);\n\n    return response.sendStatus(204);\n  },\n);\n","lang":"js"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Mount this route before any JSON body parser so that ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["request.body"]}," contains the original bytes."]}]},"headings":[{"value":"Webhooks","id":"webhooks","depth":1},{"value":"Delivery behavior","id":"delivery-behavior","depth":2},{"value":"Retries","id":"retries","depth":3},{"value":"Event format","id":"event-format","depth":2},{"value":"Event types","id":"event-types","depth":2},{"value":"Verify webhook signatures","id":"verify-webhook-signatures","depth":2}],"frontmatter":{"seo":{"title":"Webhooks"}},"lastModified":"2026-09-30T08:45:33.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/embed-api/signing/webhooks","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}