Skip to content

Manage webhooks via API

You can manage webhooks programmatically with the same Public API used for envelopes and workspaces: signed POST requests over the Oak tunnel (or via the TypeScript / Python SDK).

  • Team API key in Settings → API Keys with Webhook permissions (e.g. Manage for full CRUD, or granular Create / Read / Update / Delete).
  • Plan must include webhooks (same as creating webhooks in the app).
  • Use the Encryption Proxy or an SDK so traffic is encrypted end-to-end.

All routes are POST (body is JSON). Paths below are what the SDK uses after the base URL / tunnel:

ActionPathPermission (typical)
Create/public/webhook/createCreate or Manage on Webhook
List/public/webhook/listRead or Manage on Webhook
Update/public/webhook/updateUpdate or Manage on Webhook
Delete/public/webhook/deleteDelete or Manage on Webhook

Request and response shapes match the session webhook API; see the OpenAPI specification for full schemas.

Each team can have at most 20 webhooks. If you call create when the team already has 20, the API returns WEBHOOK_LIMIT_REACHED (HTTP 400).

import { SubnotoClient } from "@subnoto/api-client";
const client = new SubnotoClient({
accessKey: process.env.API_ACCESS_KEY!,
secretKey: process.env.API_SECRET_KEY!
});
const { data: created } = await client.POST("/public/webhook/create", {
body: {
url: "https://api.example.com/subnoto-webhook",
contentType: "application/json",
sslVerify: true,
active: true,
events: ["ENVELOPE_COMPLETED"],
title: "Production hook"
}
});
const { data: listed } = await client.POST("/public/webhook/list", {
body: { page: 1, limit: 50 }
});
await client.POST("/public/webhook/update", {
body: {
uuid: created!.webhook.uuid,
active: false,
title: "Paused hook"
}
});
await client.POST("/public/webhook/delete", {
body: { uuid: created!.webhook.uuid }
});
from subnoto_api_client import SubnotoSyncClient, SubnotoConfig
with SubnotoSyncClient(SubnotoConfig()) as client:
r = client.post(
"/public/webhook/create",
json={
"url": "https://api.example.com/subnoto-webhook",
"contentType": "application/json",
"sslVerify": True,
"active": True,
"events": ["ENVELOPE_COMPLETED"],
"title": "Production hook",
},
)
uuid = r.json()["webhook"]["uuid"]
client.post("/public/webhook/list", json={"page": 1, "limit": 50})
client.post(
"/public/webhook/update",
json={"uuid": uuid, "active": False, "title": "Paused hook"},
)
client.post("/public/webhook/delete", json={"uuid": uuid})