Skip to content

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 ​

  • id string (uuid)

    Unique identifier for the webhook.

  • name string or null

    Display name. Maximum 255 characters.

  • url string (uri)

    The endpoint Plane posts events to. Unique within the workspace.

  • is_active boolean

    Whether Plane delivers events to the webhook.

  • version string

    The payload version. Defaults to v2.

  • content_type string

    application/json or application/x-www-form-urlencoded.

  • scopes array of string

    The events the webhook receives, such as workitem.created, workitem.comment.created, or cycle.updated.

  • last_used_filter string

    Which filter Plane evaluates when it delivers an event: rich_filters or pql_filters. Defaults to rich_filters. Plane doesn't validate the value, and any value other than pql_filters acts as rich_filters.

  • rich_filters object

    A structured filter, for example {"priority__in": ["urgent", "high"]}. {} means no filter.

  • pql_filters object

    A filter written in PQL, stored as {"stripped": "<query>", ...}, for example {"stripped": "priority = \"urgent\""}. Only stripped is evaluated. An empty stripped means no filter.

  • created_at string (date-time)

    When the webhook was created.

  • updated_at string (date-time)

    When the webhook was last updated.

  • created_by_id string (uuid)

    The user who created the webhook.

  • updated_by_id string (uuid) or null

    The user who last updated the webhook. null until someone updates it.

  • secret_key string

    The signing secret. Returned only by Create a webhook and Regenerate a webhook secret.

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": "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 ​

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

  1. The event must match one of the webhook's scopes. If it doesn't, the webhook doesn't receive it.
  2. The filter named by last_used_filter must match the event. Plane evaluates only that filter and ignores the other one. An empty filter matches every event.
  3. 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:

json
{
  "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(), or earliestUnreleasedRelease().
  • A condition function other than isDraft(), isArchived(), isEpic(), isTopLevel(), isSubWorkItem(), hasNoAssignee(), hasNoLabel(), and hasStartAndDueDates(). Plane can't evaluate the others, including relation and history functions such as childOf() and wasEver(), 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.