curl --request PATCH \
--url https://app.vumasign.com/api/v1/webhooks/{webhookId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"active": false
}
'import requests
url = "https://app.vumasign.com/api/v1/webhooks/{webhookId}"
payload = { "active": False }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({active: false})
};
fetch('https://app.vumasign.com/api/v1/webhooks/{webhookId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.vumasign.com/api/v1/webhooks/{webhookId}"
payload := strings.NewReader("{\n \"active\": false\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"id": "01960000-0000-4000-8000-000000000e5d",
"url": "https://api.example.test/hooks/vumasign",
"subscribed_events": [
"envelope.completed",
"envelope.declined"
],
"brand_id": null,
"active": false,
"consecutive_failures": 0,
"last_success_at": "2026-09-02T09:06:00.000Z",
"last_failure_at": null,
"disabled_at": "2026-09-03T12:00:00.000Z",
"disabled_reason": "deactivated by the organisation",
"created_at": "2026-09-01T08:00:00.000Z"
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}Change the URL, the subscription, the brand filter or the active flag.
A PARTIAL BODY, and one path for every property this resource will ever have. BoldSign minted one endpoint per property — addTags, changeAccessCode, extendExpiry, eight ways to edit a document — and has 87 paths and a casing typo they can never fix.
⚠️ "active": false STOPS DELIVERY AND KEEPS THE QUEUE. This is the operation for a maintenance window: queued deliveries wait, and their retry ladders do not advance while they wait. "active": true resumes them and resets the health window, which is how an auto-disabled endpoint is brought back.
⚠️ OMISSION IS MEANINGFUL HERE AND NOWHERE ELSE IN THIS API. Sending "brand_id": null REMOVES the filter; omitting brand_id leaves it alone. Every other request in this document spells absence as null.
The secret is not settable — see /rotate-secret.
curl --request PATCH \
--url https://app.vumasign.com/api/v1/webhooks/{webhookId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"active": false
}
'import requests
url = "https://app.vumasign.com/api/v1/webhooks/{webhookId}"
payload = { "active": False }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({active: false})
};
fetch('https://app.vumasign.com/api/v1/webhooks/{webhookId}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.vumasign.com/api/v1/webhooks/{webhookId}"
payload := strings.NewReader("{\n \"active\": false\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"id": "01960000-0000-4000-8000-000000000e5d",
"url": "https://api.example.test/hooks/vumasign",
"subscribed_events": [
"envelope.completed",
"envelope.declined"
],
"brand_id": null,
"active": false,
"consecutive_failures": 0,
"last_success_at": "2026-09-02T09:06:00.000Z",
"last_failure_at": null,
"disabled_at": "2026-09-03T12:00:00.000Z",
"disabled_reason": "deactivated by the organisation",
"created_at": "2026-09-01T08:00:00.000Z"
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}{
"error": {
"code": "unauthenticated",
"message": "<string>"
}
}Authorizations
Authorization: Bearer vsk_live_…. Chosen over a bespoke X-API-KEY header because every client, proxy and log-redaction rule already knows this one. What a key may DO is its scopes — see x-scopes at the root of this document and x-required-scope on each operation. The scope list is not written here because OpenAPI reserves a requirement’s scope array for oauth2 and openIdConnect and requires it to be empty for an http scheme.
Path Parameters
The endpoint’s id, as returned when it was registered.
An endpoint id.
"01960000-0000-4000-8000-000000000e5d"
Body
The properties to change. Anything omitted is left as it was.
The change.
A new delivery URL, on the same terms as registration.
"https://api.example.test/hooks/vumasign"
Replaces the whole subscription list. Not merged with it.
One event type.
envelope.sent, envelope.completed, envelope.declined, envelope.voided, envelope.expired, envelope.sealed, envelope.sealing_failed, recipient.completed null removes the filter. Omitting the property leaves it unchanged.
false stops delivery and KEEPS THE QUEUE — this is the operation to use for maintenance, not DELETE. true resumes it AND resets the health window, which is how an auto-disabled endpoint is brought back.
Response
The endpoint as it now stands, after every change was applied.
The endpoint.
The endpoint’s id. A bare uuid.
Where deliveries are POSTed. https:// only, no credentials, and not a private or loopback address — deliveries are made from inside our network.
What this endpoint hears about. Never empty. ⚠️ An unknown name is refused at registration rather than accepted and never delivered.
One event type.
envelope.sent, envelope.completed, envelope.declined, envelope.voided, envelope.expired, envelope.sealed, envelope.sealing_failed, recipient.completed Deliver only envelopes carrying this brand; null for every envelope in the organisation.
⚠️ THIS IS ROUTING, NOT ISOLATION. Any key on this organisation can read every envelope in it whatever brand it carries — there is no brand predicate in any access rule anywhere. Filtering decides which events are POSTed to which URL; it does not, and cannot, stop a consumer learning about another brand by asking. Do not build a permission boundary out of it.
Whether we are delivering. False either because you deactivated it or because it was auto-disabled after failing for the whole health window — disabled_reason says which, in prose.
⚠️ DELIVERIES THAT EXHAUSTED THE WHOLE LADDER SINCE THE LAST SUCCESS, not individual attempts. One unreachable host over one event counts once here, not seven times.
The last 2xx we received. Null if there has never been one.
The last delivery that used up its ladder.
When delivery stopped. Null while active.
Why, in prose for a person. Null while active. ⚠️ This is the field that answers "why did my endpoint stop receiving events" without a support ticket.
ISO 8601, UTC.