Update a webhook
Change a webhook's URL, event scopes, filters, or other settings. Send only the keys you want to change. Omitted keys keep their current value, and an explicit null clears a nullable field.
Path parameters
slug:requiredstringThe workspace slug. It appears in your Plane URLs. In https://app.plane.so/my-team/projects/, the slug is my-team.
pk:requiredstring (uuid)The webhook id.
Body parameters
Every field is optional. Send the subset you're changing.
url:optionalstring (uri)The endpoint Plane posts events to. It must be a publicly reachable http or https URL, and it must be unique within the workspace.
name:optionalstringDisplay name.
Maximum 255 characters. Nullable.
scopes:optionalarray of stringThe complete list of events the webhook receives, such as workitem.created or cycle.updated. The list you send replaces the current one. An unknown scope returns 400.
is_active:optionalbooleanWhether Plane delivers events to the webhook.
content_type:optionalstringContent type of the delivery payloads. One of application/json, application/x-www-form-urlencoded.
version:optionalstringThe payload version, for example v2.
Maximum 10 characters.
rich_filters:optionalobjectA structured filter that replaces the current one, for example {"priority__in": ["urgent", "high"]}. Send {} to remove it. See Rich filters.
A function Plane can't evaluate against an event returns 400.
pql_filters:optionalobjectA PQL filter that replaces the current one, as {"stripped": "<query>"}. Send {"stripped": ""} to remove it. See PQL filters.
The request returns 400 if the value isn't an object with a string stripped, if the query has invalid syntax, or if the query uses a function that needs a signed-in user, such as currentUser().
last_used_filter:optionalstringWhich filter Plane evaluates when it delivers an event: rich_filters or pql_filters. Plane evaluates only this one.
Plane doesn't validate the value. Any value other than pql_filters makes Plane evaluate rich_filters.
If you send exactly one of rich_filters and pql_filters and leave this out, Plane switches it to the filter you sent. For example, a request with only rich_filters moves a webhook that used its PQL filter over to the rich filter.
Response shaping
fields:optionalstringComma-separated list of fields to return. Fields you don't request are left out of the response instead of coming back as null. id is always included. Pass all to get every requestable field. An unknown field name returns 400. See Sparse fields.
Requestable here: content_type, created_at, created_by_id, id, is_active, last_used_filter, name, pql_filters, rich_filters, scopes, updated_at, updated_by_id, url, version.
Scopes
webhooks:write
Errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_request | The URL isn't allowed, a scope is unknown, or a filter is invalid or can't be evaluated. |
401 | unauthorized | Missing or invalid credentials. |
402 | payment_required | The feature this endpoint belongs to isn't enabled on your plan or is switched off. |
403 | forbidden | Your role or token scope doesn't allow this. |
404 | not_found | No such resource, or it's outside your tenant. |
406 | not_acceptable | The Accept header asks for a representation the API can't produce. |
409 | conflict | Another webhook in the workspace already uses this URL. |
413 | payload_too_large | The request body is over the size limit. |
415 | unsupported_media_type | The Content-Type isn't one this endpoint accepts. |
429 | rate_limited | Throttled. Honor the Retry-After header before retrying. |
curl -X PATCH \
"https://api.plane.so/api/v2/workspaces/my-team/webhooks/9c1f0b3d-6d2e-4c9a-8b41-2f7e5a0d6c88/" \
-H "X-Api-Key: $PLANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rich_filters": {"priority__in": ["urgent", "high"]}
}'import requests
response = requests.patch(
"https://api.plane.so/api/v2/workspaces/my-team/webhooks/9c1f0b3d-6d2e-4c9a-8b41-2f7e5a0d6c88/",
headers={"X-Api-Key": "your-api-key"},
json={
"rich_filters": {"priority__in": ["urgent", "high"]},
},
)
print(response.json())const response = await fetch(
"https://api.plane.so/api/v2/workspaces/my-team/webhooks/9c1f0b3d-6d2e-4c9a-8b41-2f7e5a0d6c88/",
{
method: "PATCH",
headers: {
"X-Api-Key": "your-api-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
rich_filters: { priority__in: ["urgent", "high"] },
}),
},
);
const data = await response.json();{
"id": "9c1f0b3d-6d2e-4c9a-8b41-2f7e5a0d6c88",
"name": "Urgent work items to on-call",
"url": "https://hooks.example.com/plane/urgent",
"is_active": true,
"version": "v2",
"content_type": "application/json",
"scopes": ["workitem.created", "workitem.updated"],
"last_used_filter": "rich_filters",
"rich_filters": {
"priority__in": ["urgent", "high"]
},
"pql_filters": {
"stripped": "priority = \"urgent\""
},
"created_at": "2026-01-14T09:22:41.478363Z",
"updated_at": "2026-02-03T16:45:12.904117Z",
"created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
"updated_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
}{
"type": "not_found",
"code": "not_found",
"detail": "The requested resource was not found."
}
