Skip to content

Update a webhook ​

PATCH/api/v2/workspaces/{slug}/webhooks/{pk}/

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:requiredstring

The 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:optionalstring

Display name.

Maximum 255 characters. Nullable.

scopes:optionalarray of string

The 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:optionalboolean

Whether Plane delivers events to the webhook.

content_type:optionalstring

Content type of the delivery payloads. One of application/json, application/x-www-form-urlencoded.

version:optionalstring

The payload version, for example v2.

Maximum 10 characters.

rich_filters:optionalobject

A 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:optionalobject

A 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:optionalstring

Which 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:optionalstring

Comma-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 ​

StatusCodeCause
400invalid_requestThe URL isn't allowed, a scope is unknown, or a filter is invalid or can't be evaluated.
401unauthorizedMissing or invalid credentials.
402payment_requiredThe feature this endpoint belongs to isn't enabled on your plan or is switched off.
403forbiddenYour role or token scope doesn't allow this.
404not_foundNo such resource, or it's outside your tenant.
406not_acceptableThe Accept header asks for a representation the API can't produce.
409conflictAnother webhook in the workspace already uses this URL.
413payload_too_largeThe request body is over the size limit.
415unsupported_media_typeThe Content-Type isn't one this endpoint accepts.
429rate_limitedThrottled. Honor the Retry-After header before retrying.
Update a webhook
bash
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"]}
}'
Response200
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"
}
Response404
json
{
  "type": "not_found",
  "code": "not_found",
  "detail": "The requested resource was not found."
}