Webhooks overview
Webhooks push Plane events to a URL you control. A webhook subscribes to event scopes, such as workitem.created, and can carry a filter that narrows which of those events it receives.
For payloads, signatures, retries, and delivery logs, see Webhooks.
The webhook object
Attributes
idstring (uuid)Unique identifier for the webhook.
namestring or nullDisplay name. Maximum 255 characters.
urlstring (uri)The endpoint Plane posts events to. Unique within the workspace.
is_activebooleanWhether Plane delivers events to the webhook.
versionstringThe payload version. Defaults to
v2.content_typestringapplication/jsonorapplication/x-www-form-urlencoded.scopesarray of stringThe events the webhook receives, such as
workitem.created,workitem.comment.created, orcycle.updated.last_used_filterstringWhich filter Plane evaluates when it delivers an event:
rich_filtersorpql_filters. Defaults torich_filters. Plane doesn't validate the value, and any value other thanpql_filtersacts asrich_filters.rich_filtersobjectA structured filter, for example
{"priority__in": ["urgent", "high"]}.{}means no filter.pql_filtersobjectA filter written in PQL, stored as
{"stripped": "<query>", ...}, for example{"stripped": "priority = \"urgent\""}. Onlystrippedis evaluated. An emptystrippedmeans no filter.created_atstring (date-time)When the webhook was created.
updated_atstring (date-time)When the webhook was last updated.
created_by_idstring (uuid)The user who created the webhook.
updated_by_idstring (uuid) or nullThe user who last updated the webhook.
nulluntil someone updates it.secret_keystringThe signing secret. Returned only by Create a webhook and Regenerate a webhook secret.
{
"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": "pql_filters",
"rich_filters": {},
"pql_filters": {
"stripped": "priority = \"urgent\""
},
"created_at": "2026-01-14T09:22:41.478363Z",
"updated_at": "2026-01-14T09:22:41.478363Z",
"created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
"updated_by_id": null
}Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v2/workspaces/{slug}/webhooks/ | List webhooks |
GET | /api/v2/workspaces/{slug}/webhooks/{pk}/ | Get a webhook |
POST | /api/v2/workspaces/{slug}/webhooks/ | Create a webhook |
PATCH | /api/v2/workspaces/{slug}/webhooks/{pk}/ | Update a webhook |
DELETE | /api/v2/workspaces/{slug}/webhooks/{pk}/ | Delete a webhook |
POST | /api/v2/workspaces/{slug}/webhooks/{pk}/regenerate/ | Regenerate a webhook secret |
How filters affect delivery
When an event happens, Plane checks each active webhook in the workspace in this order:
- The event must match one of the webhook's
scopes. If it doesn't, the webhook doesn't receive it. - The filter named by
last_used_filtermust match the event. Plane evaluates only that filter and ignores the other one. An empty filter matches every event. - If the filter can't be evaluated, Plane skips the delivery. It doesn't fall back to delivering the event unfiltered.
A webhook holds both filter fields, but only one is in use at a time. When a create or update request sends exactly one of rich_filters and pql_filters and leaves out last_used_filter, Plane sets last_used_filter to the filter you sent. An explicit last_used_filter in the same request wins.
Rich filters
A rich filter is a JSON object. Each key names a field of the event, either an envelope field such as event_type or project_id, or a field of the event's data object such as priority. A key can end in a lookup: __in, __gte, __gt, __lte, __lt, __range, __contains, __icontains, __isnull, or __exact. Keys in one object must all match. Combine objects with and, or, and not:
{
"and": [{ "priority__in": ["urgent", "high"] }, { "event_type": "workitem.created" }]
}PQL filters
A PQL filter is an object whose stripped key holds a PQL query, such as priority = "urgent". Plane checks the query when you save it. A query returns 400 if it uses:
- A function that needs a signed-in user or a lookup for each event:
currentUser(),membersOf(),workspaceMembers(),activeCycle(),completedCycles(),upcomingCycles(),userPropertyEquals(),moduleMatch(),releaseMatch(), orearliestUnreleasedRelease(). - A condition function other than
isDraft(),isArchived(),isEpic(),isTopLevel(),isSubWorkItem(),hasNoAssignee(),hasNoLabel(), andhasStartAndDueDates(). Plane can't evaluate the others, including relation and history functions such aschildOf()andwasEver(), against an event.
Date functions such as now() and daysAgo(7) are allowed. Other keys in the object, such as the json that the Plane editor stores, are saved and returned as sent.
Response shaping
Every webhook read accepts ?fields= for sparse responses. See Sparse fields. Errors follow the shared problem+json contract.

