You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -14,21 +14,22 @@ Webhooks in Plane work at the workspace level. A single webhook can subscribe to
14
14
15
15
The current webhook system is v2. V2 payloads use dot-notation event names (e.g., `workitem.created`) and include structured fields for deduplication, diffing, and filtering that were not available in the original version. If you have webhooks created before v2, they appear in the list with a **(deprecated)** tag. They still deliver but do not receive any v2 fields. Recreate them as new webhooks to get the full v2 feature set.
16
16
17
-
## Creating a webhook
18
-
19
-
### What you're configuring
20
-
21
-
When you create a webhook, you're telling Plane two things: where to send events, and which events to send.
22
-
23
-
**Webhook title** is a label for your own reference - it appears in the webhook list and helps you tell multiple webhooks apart.
17
+
:::warning Migrate your v1 webhooks to v2
18
+
V1 webhooks are deprecated. They continue to deliver but will not receive v2 payload features — including `delivery_id` and `event_id` for deduplication, `previous_attributes` for diffs on updated events, and dot-notation event names. There is no in-place upgrade. To move to v2, recreate each v1 webhook as a new webhook and update your server to handle the v2 payload structure.
24
19
25
-
**Payload URL** is the endpoint that Plane will POST to. It must be a publicly reachable `http://` or `https://` address. Local addresses (localhost, private IPs) are not accepted.
20
+
**To migrate a v1 webhook:**
26
21
27
-
**Events** control what triggers this webhook. The form groups events by type - Projects, Cycles, Modules, Work items, and so on. Check the specific actions you care about. You can subscribe to as many or as few as you need.
22
+
1. Open the v1 webhook (marked **deprecated**) and note its URL and event subscriptions.
23
+
2. Create a new webhook with the same URL and event subscriptions. See [How to create a webhook](#how-to-create-a-webhook).
24
+
3. Save the new secret key from the CSV download — your server will need it to verify v2 requests.
25
+
4. Update your server to expect the v2 payload structure. See [Payload structure](#payload-structure) for the full field reference.
26
+
5. Test that deliveries are arriving and your server is handling them correctly.
27
+
6. Delete the original v1 webhook once you're confident the new one is working.
28
+
:::
28
29
29
-
**Advanced configurations** lets you add a filter so the webhook only fires for work items that match specific conditions - for example, high-priority bugs in a particular project. See [Filtering work item events](#filtering-work-item-events) below.
30
+
## Creating a webhook
30
31
31
-
**Secret key** is generated automatically when you save the webhook. Plane downloads it as a CSV file the moment you click **Create webhook** and then returns you to the webhook list. It is not displayed on screen - the download is the only time you receive it automatically. Save the file. You need the key to verify incoming requests.
@@ -43,6 +44,20 @@ Plane downloads the secret key as a CSV file to your computer and returns you to
43
44
44
45
If you lose the CSV, you can re-generate the secret key from the edit form - but the old key stops working the moment you do.
45
46
47
+
### What you're configuring
48
+
49
+
When you create a webhook, you're telling Plane two things: where to send events, and which events to send.
50
+
51
+
-**Webhook title** is a label for your own reference - it appears in the webhook list and helps you tell multiple webhooks apart.
52
+
53
+
-**Payload URL** is the endpoint that Plane will POST to. It must be a publicly reachable `http://` or `https://` address. Local addresses (localhost, private IPs) are not accepted.
54
+
55
+
-**Events** control what triggers this webhook. The form groups events by type - Projects, Cycles, Modules, Work items, and so on. Check the specific actions you care about. You can subscribe to as many or as few as you need.
56
+
57
+
-**Advanced configurations** lets you add a filter so the webhook only fires for work items that match specific conditions - for example, high-priority bugs in a particular project. See [Filtering work item events](#filtering-work-item-events) below.
58
+
59
+
-**Secret key** is generated automatically when you save the webhook. Plane downloads it as a CSV file the moment you click **Create webhook** and then returns you to the webhook list. It is not displayed on screen - the download is the only time you receive it automatically. Save the file. You need the key to verify incoming requests.
60
+
46
61
## Filtering work item events
47
62
48
63
### How filtering works
@@ -66,7 +81,7 @@ Switching between modes is lossless - your filter is not lost when you switch.
66
81
67
82
1. Create or edit a webhook.
68
83
2. Check at least one **Work items** event.
69
-
3.Expand **Advanced configurations**.
84
+
3.Scroll down to the **Work item v2 filters** section.
70
85
4. Use the filter builder to define your conditions in Basic mode, or switch to PQL mode to type an expression directly.
71
86
5. Save the webhook.
72
87
@@ -93,43 +108,6 @@ assignee_id = "<user-uuid>" Specific assignee
93
108
project_id = "<project-uuid>" Specific project
94
109
```
95
110
96
-
## Securing requests
97
-
98
-
### Why Plane signs every request
99
-
100
-
Any server on the internet can send a POST request to your endpoint. Without a way to verify the source, someone could send fake webhook payloads to your system and trigger whatever logic you've built around them.
101
-
102
-
Plane solves this by signing every request with HMAC-SHA256 using your secret key. The signature is attached as an `X-Plane-Signature` header. Because only Plane and you know the secret, a valid signature proves the request came from Plane and was not modified in transit.
103
-
104
-
Skipping verification means your endpoint will process any request that arrives - forged or not.
105
-
106
-
### How to verify a webhook payload
107
-
108
-
On your server, compute the expected signature from the **raw request body bytes** and compare it to the value in `X-Plane-Signature`. Use a constant-time comparison to prevent timing attacks.
Use the raw bytes from the incoming request - not a parsed or re-serialized version. JSON re-serialization can change key ordering, spacing, or escaping, which will produce a different signature and cause verification to fail. Reject any request where the signature does not match before running any other logic.
|`X-Plane-Signature`| HMAC-SHA256 hex digest of the raw request body, keyed with your webhook secret |
130
-
131
-
The secret key is formatted as `plane_wh_` followed by a random string. Plane masks it in the UI. To view the full key, open the edit form for the webhook and use the show/hide toggle in the **Secret key** section.
132
-
133
111
## Managing webhooks
134
112
135
113
### Disabling versus deleting
@@ -175,6 +153,43 @@ Re-generate if your secret key is compromised. The old key is invalidated the mo
175
153
176
154
Plane downloads the new key as a CSV.
177
155
156
+
## Securing requests
157
+
158
+
### Why Plane signs every request
159
+
160
+
Any server on the internet can send a POST request to your endpoint. Without a way to verify the source, someone could send fake webhook payloads to your system and trigger whatever logic you've built around them.
161
+
162
+
Plane solves this by signing every request with HMAC-SHA256 using your secret key. The signature is attached as an `X-Plane-Signature` header. Because only Plane and you know the secret, a valid signature proves the request came from Plane and was not modified in transit.
163
+
164
+
Skipping verification means your endpoint will process any request that arrives - forged or not.
165
+
166
+
### How to verify a webhook payload
167
+
168
+
On your server, compute the expected signature from the **raw request body bytes** and compare it to the value in `X-Plane-Signature`. Use a constant-time comparison to prevent timing attacks.
Use the raw bytes from the incoming request - not a parsed or re-serialized version. JSON re-serialization can change key ordering, spacing, or escaping, which will produce a different signature and cause verification to fail. Reject any request where the signature does not match before running any other logic.
|`X-Plane-Signature`| HMAC-SHA256 hex digest of the raw request body, keyed with your webhook secret |
190
+
191
+
The secret key is formatted as `plane_wh_` followed by a random string. Plane masks it in the UI. To view the full key, open the edit form for the webhook and use the show/hide toggle in the **Secret key** section.
192
+
178
193
## Delivery and monitoring
179
194
180
195
### How Plane delivers events
@@ -361,3 +376,51 @@ All v2 payloads share this top-level structure:
0 commit comments