curl --request GET \
--url https://app.vumasign.com/api/v1/webhooks/{webhookId} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.vumasign.com/api/v1/webhooks/{webhookId}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
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"
"net/http"
"io"
)
func main() {
url := "https://app.vumasign.com/api/v1/webhooks/{webhookId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
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": true,
"consecutive_failures": 0,
"last_success_at": "2026-09-02T09:06:00.000Z",
"last_failure_at": null,
"disabled_at": null,
"disabled_reason": null,
"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>"
}
}One endpoint, with its health.
⚠️ THREE SITUATIONS ANSWER WITH THE SAME 404: no such endpoint; one belonging to another organisation; an id that is not a uuid. “This exists but is not yours” is itself the secret, and the handler could not distinguish them if it wanted to — the read runs inside a transaction already scoped to the key’s tenant.
curl --request GET \
--url https://app.vumasign.com/api/v1/webhooks/{webhookId} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.vumasign.com/api/v1/webhooks/{webhookId}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
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"
"net/http"
"io"
)
func main() {
url := "https://app.vumasign.com/api/v1/webhooks/{webhookId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
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": true,
"consecutive_failures": 0,
"last_success_at": "2026-09-02T09:06:00.000Z",
"last_failure_at": null,
"disabled_at": null,
"disabled_reason": null,
"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>"
}
}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 by the list.
An endpoint id.
"01960000-0000-4000-8000-000000000e5d"
Response
The endpoint and its delivery health, without its secret.
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.