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).
Prerequisites
- 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.
Endpoints
All routes are POST (body is JSON). Paths below are what the SDK uses after the base URL / tunnel:
| Action | Path | Permission (typical) |
|---|---|---|
| Create | /public/webhook/create | Create or Manage on Webhook |
| List | /public/webhook/list | Read or Manage on Webhook |
| Update | /public/webhook/update | Update or Manage on Webhook |
| Delete | /public/webhook/delete | Delete or Manage on Webhook |
Request and response shapes match the session webhook API; see the OpenAPI specification for full schemas.
Limits
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).
TypeScript (SDK)
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 }});Python (SDK)
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})