Skip to content

Commit 51c6963

Browse files
committed
fix(plane): align webhook cutover and pagination limits
1 parent cd340d6 commit 51c6963

14 files changed

Lines changed: 35 additions & 27 deletions

File tree

‎apps/docs/content/docs/integrations/plane.mdx‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,7 +1980,7 @@ List attachments in Plane. Supports API v1 compatibility.
19801980
| `offset` | number | No | Number of rows to skip from the start of the result set. |
19811981
| `order_by` | string | No | Field to order the list by. Prefix with '-' for descending \(e.g. '-created_at'\). Annotation-backed orders sort semantically and ride the default offset page. |
19821982
| `paginate` | string | No | Set to 'cursor' to opt into the COUNT-free keyset cursor envelope \(use for deep traversal\); omit for the default offset envelope with total_count. One of `cursor`. |
1983-
| `per_page` | number | No | Page size \(max 200\). |
1983+
| `per_page` | number | No | API v2 only. Page size \(maximum 200\). |
19841984
| `fields` | string | No | Comma-separated list of fields to return. Unrequested keys are **omitted** from each row, not returned as `null`. `id` always comes back. Pass `all` for every requestable field. An unknown name is a `400` that names the valid set, so a typo can't silently cost you the saving. See \[Sparse fields\]\(https://developers.plane.so/api-reference/v2/sparse-fields). Requestable here: `asset_url`, `attributes`, `content_type`, `created_at`, `created_by_id`, `external_id`, `external_source`, `id`, `is_uploaded`, `name`, `size`, `work_item_id`. |
19851985
| `cursor` | string | No | Cursor from next_cursor. Repeat the original filters, per_page, and order_by when following it. |
19861986

@@ -2063,7 +2063,7 @@ List comments in Plane. Supports API v1 compatibility.
20632063
| `external_source` | string | No | Return comments that came from this system, for example `github` or `zendesk`. |
20642064
| `search` | string | No | Match comments against their plain-text body \(`comment_stripped`\), so HTML markup in `comment_html` never affects whether a term hits. |
20652065
| `order_by` | string | No | Field to sort by. Prefix with `-` for descending. Send it explicitly whenever order matters — a thread you render should not depend on the server's unstated default. - `created_at` — oldest first - `-created_at` — newest first - `id` - `-id` |
2066-
| `per_page` | number | No | Page size. Defaults to 50, maximum 200. |
2066+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
20672067
| `offset` | number | No | Number of rows to skip from the start of the result set. Maximum 10000 — for deeper traversal switch to cursor pagination. |
20682068
| `paginate` | string | No | Set to `cursor` to opt into the COUNT-free keyset envelope instead of the default offset envelope. The response then carries `next_cursor` and `has_more`; send the value of `next_cursor` back as `?cursor=` to fetch the next page. See \[Pagination\]\(https://developers.plane.so/api-reference/v2/pagination) for the full envelope. |
20692069
| `count` | boolean | No | Defaults to `true`. Set to `false` to skip the `COUNT\(*\)` and omit `total_count` from the offset envelope. |
@@ -2162,7 +2162,7 @@ List cycles in Plane. Supports API v1 compatibility.
21622162
| `external_source` | string | No | Return only cycles imported from this source, for example `jira`. |
21632163
| `search` | string | No | Free-text search term matched against the cycle. |
21642164
| `order_by` | string | No | Field to sort by. Prefix with `-` for descending. - `sort_order` / `-sort_order` — the project's manual cycle ordering - `created_at` / `-created_at` — newest or oldest first - `id` / `-id` |
2165-
| `per_page` | number | No | Page size. Defaults to 50, maximum 200. |
2165+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
21662166
| `offset` | number | No | Number of rows to skip from the start of the result set. Maximum 10000 — past that, switch to cursor pagination. |
21672167
| `paginate` | string | No | Set to `cursor` to opt into the COUNT-free keyset envelope instead of the default offset envelope. The response then carries `next_cursor` and `has_more` rather than `next`, `previous`, and `total_count`; pass `next_cursor` back as `cursor` to walk to the following page. Use it for deep traversal, where offset paging gets expensive. |
21682168
| `count` | boolean | No | Defaults to `true`. Set to `false` to skip the `COUNT\(*\)` behind `total_count` — the field is then omitted from the envelope. Worth doing when you only need the rows. |
@@ -2268,7 +2268,7 @@ List labels in Plane. Supports API v1 compatibility.
22682268
| `external_source` | string | No | Return labels that came from this system, for example `github` or `jira`. |
22692269
| `search` | string | No | A search term matched against the label `name`. Use it to power type-ahead in a picker rather than downloading every page and filtering client-side. |
22702270
| `order_by` | string | No | Field to sort by. Prefix with `-` for descending. Defaults to `sort_order`. - `sort_order` , `-sort_order` — the project's own label ordering - `created_at` , `-created_at` — newest or oldest first - `id` , `-id` A value outside this list is not rejected — it silently falls back to the default `sort_order`. Check your spelling: a typo in `order_by` fails silently and shows up as a differently sorted page, not as an error. |
2271-
| `per_page` | number | No | Page size. Defaults to 50, maximum 200. |
2271+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
22722272
| `offset` | number | No | Number of rows to skip from the start of the result set. Maximum 10000. Read the `next` value from the response and send it back as `offset` to walk forward. |
22732273
| `paginate` | string | No | Set to `cursor` to switch from the default offset envelope to the keyset cursor envelope, which skips the `COUNT\(*\)` and returns `next_cursor` and `has_more` instead of `next` and `total_count`. Send the returned `next_cursor` back as `cursor` to fetch the following page. Only `created_at` and `id` are cursor-eligible, because a keyset needs a strictly ordered column and `sort_order` is neither unique nor monotonic. Pair `paginate=cursor` with `order_by=created_at` or `order_by=id` — the default `sort_order` ordering is rejected with `400 ordering_not_cursor_eligible`. Most projects have few enough labels that the default offset envelope is all you need. |
22742274
| `count` | boolean | No | Defaults to `true`. Set to `false` to omit `total_count` and skip the count query. |
@@ -2353,7 +2353,7 @@ List links in Plane. Supports API v1 compatibility.
23532353
| `offset` | number | No | Number of rows to skip from the start of the result set. |
23542354
| `order_by` | string | No | Field to order the list by. Prefix with '-' for descending \(e.g. '-created_at'\). Annotation-backed orders sort semantically and ride the default offset page. |
23552355
| `paginate` | string | No | Set to 'cursor' to opt into the COUNT-free keyset cursor envelope \(use for deep traversal\); omit for the default offset envelope with total_count. One of `cursor`. |
2356-
| `per_page` | number | No | Page size \(max 200\). |
2356+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
23572357
| `search` | string | No | A search term. |
23582358
| `title` | string | No | Filter by `title`. |
23592359
| `url` | string | No | Filter by `url`. |
@@ -2437,7 +2437,7 @@ List modules in Plane. Supports API v1 compatibility.
24372437
| `external_source` | string | No | Return only modules that came from this system, for example `github` or `jira`. |
24382438
| `search` | string | No | Free-text match on the module name. |
24392439
| `order_by` | string | No | Field to sort by. Prefix with `-` for descending. - `sort_order` , `-sort_order` - `created_at` , `-created_at` - `id` , `-id` Defaults to `sort_order`. |
2440-
| `per_page` | number | No | Page size. Defaults to 50, maximum 200. |
2440+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
24412441
| `offset` | number | No | Number of rows to skip from the start of the result set. Maximum 10000 — go deeper with cursor pagination. |
24422442
| `paginate` | string | No | Set to `cursor` to opt into the COUNT-free keyset envelope, then follow `next_cursor` with `?cursor=`. |
24432443
| `count` | boolean | No | Set to `false` to skip the count query and omit `total_count` from the offset envelope. Defaults to `true`. |
@@ -2550,7 +2550,7 @@ List project pages in Plane. Supports API v1 compatibility.
25502550
| `owned_by_id` | string | No | Filter by `owned_by_id`. |
25512551
| `paginate` | string | No | Set to 'cursor' to opt into the COUNT-free keyset cursor envelope \(use for deep traversal\); omit for the default offset envelope with total_count. One of `cursor`. |
25522552
| `parent_id` | string | No | Filter by `parent_id`. |
2553-
| `per_page` | number | No | Page size \(max 200\). |
2553+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
25542554
| `search` | string | No | A search term. |
25552555
| `type` | string | No | - `all` - All - `public` - Public - `private` - Private - `shared` - Shared - `archived` - Archived One of `all`, `archived`, `private`, `public`, `shared`. |
25562556
| `fields` | string | No | Comma-separated list of fields to return. Unrequested keys are **omitted** from each row, not returned as `null`. `id` always comes back. Pass `all` for every requestable field. An unknown name is a `400` that names the valid set, so a typo can't silently cost you the saving. See \[Sparse fields\]\(https://developers.plane.so/api-reference/v2/sparse-fields). Requestable here: `access`, `archived_at`, `collection_id`, `color`, `created_at`, `created_by_id`, `description_html`, `description_stripped`, `external_id`, `external_source`, `id`, `is_global`, `is_locked`, `logo_props`, `name`, `owned_by_id`, `parent_id`, `sort_order`, `view_props`. |
@@ -2670,7 +2670,7 @@ List projects in Plane. Supports API v1 compatibility.
26702670
| `offset` | number | No | Number of rows to skip from the start of the result set. |
26712671
| `order_by` | string | No | Field to order the list by. Prefix with '-' for descending \(e.g. '-created_at'\). Annotation-backed orders sort semantically and ride the default offset page. |
26722672
| `paginate` | string | No | Set to 'cursor' to opt into the COUNT-free keyset cursor envelope \(use for deep traversal\); omit for the default offset envelope with total_count. One of `cursor`. |
2673-
| `per_page` | number | No | Page size \(max 200\). |
2673+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
26742674
| `priority` | string | No | - `none` - None - `low` - Low - `medium` - Medium - `high` - High - `urgent` - Urgent One of `high`, `low`, `medium`, `none`, `urgent`. |
26752675
| `priority__in` | json | No | Multiple values may be separated by commas. - `none` - None - `low` - Low - `medium` - Medium - `high` - High - `urgent` - Urgent |
26762676
| `search` | string | No | A search term. |
@@ -2818,7 +2818,7 @@ List states in Plane. Supports API v1 compatibility.
28182818
| `fields` | string | No | Comma-separated list of fields to return on each row. Unrequested keys are **omitted** from the response, not returned as `null`, so absent means "not requested" and `null` means "actually null". `id` always comes back whether or not you name it. Pass `all` for every requestable field. An unknown name is a `400` that lists the valid set and suggests the closest match, so a typo can't silently cost you the saving. Requestable here: `color`, `created_at`, `created_by_id`, `description`, `external_id`, `external_source`, `group`, `id`, `is_default`, `is_triage`, `name`, `sequence`. See \[Sparse fields\]\(https://developers.plane.so/api-reference/v2/sparse-fields). |
28192819
| `group__in` | string | No | Documented filter variant. Return only states in this workflow group. One of `backlog`, `unstarted`, `started`, `completed`, `cancelled`, or `triage`. Use the `group__in` variant to match several groups at once, passing them comma-separated — `?group__in=started,completed`. Filtering by group is the portable way to ask "what counts as in progress here", because every project names its states differently but the groups are fixed. |
28202820
| `order_by` | string | No | Field to sort by. Prefix with `-` for descending. - `sequence` , `-sequence` — the project's own workflow order - `created_at` , `-created_at` — when each state was added - `id` , `-id` Order by `sequence` when you are rendering the workflow to a user; it is the order the project itself uses. |
2821-
| `per_page` | number | No | Page size. Defaults to 50, maximum 200. Most projects have fewer than 20 states, so one page is usually the whole workflow. |
2821+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
28222822
| `offset` | number | No | Number of rows to skip from the start of the result set. Maximum 10000. Read the `next` value from the response rather than computing offsets yourself. |
28232823
| `paginate` | string | No | Set to `cursor` to opt into the COUNT-free keyset envelope, which returns `next_cursor` and `has_more` instead of `next` and `total_count`. Omit it for the default offset envelope. |
28242824
| `count` | boolean | No | Defaults to `true`. Set to `false` to skip the `COUNT\(*\)` behind `total_count`; the field is then omitted from the response. |
@@ -2981,7 +2981,7 @@ List work items in Plane. Supports API v1 compatibility.
29812981
| `target_date__lte` | string | No | Bound the planned due date. `?target_date__lte=2026-01-31&state_group__in=backlog,unstarted,started` is the "what is about to slip" query. |
29822982
| `search` | string | No | Free-text search over the work item name. |
29832983
| `order_by` | string | No | Field to sort by. Prefix with `-` for descending. Defaults to `-created_at`. - `created_at`, `-created_at` - `updated_at`, `-updated_at` - `sequence_id`, `-sequence_id` - `id`, `-id` - `sort_order`, `-sort_order` — the manual board ordering - `priority`, `-priority` — semantic: `urgent` → `high` → `medium` → `low` → `none`, not alphabetical - `state_group`, `-state_group` — semantic: workflow order, not alphabetical `priority` and `state_group` sort by meaning, which is what you want for a board but is not cursor-eligible. Pair either with `?paginate=cursor` and you get `400 ordering_not_cursor_eligible`; use the default offset pages instead. |
2984-
| `per_page` | number | No | Page size. Defaults to 50, maximum 200. |
2984+
| `per_page` | number | No | Page size. Maximum 200 for API v2 and 100 for API v1. |
29852985
| `offset` | number | No | Rows to skip from the start of the result set. Maximum 10000 — past that, switch to cursor pagination. |
29862986
| `count` | boolean | No | Defaults to `true`. Pass `?count=false` to skip the `COUNT\(*\)` and omit `total_count` from the envelope. Worth doing on large projects when you only need the rows. |
29872987
| `paginate` | string | No | Set to `cursor` to opt into keyset pagination. The envelope changes to `next_cursor` / `has_more` and drops `total_count`. Use it for deep or long-running traversals where offset pages would drift as rows are inserted. Follow the returned `next_cursor` as described in \[Pagination\]\(https://developers.plane.so/api-reference/v2/pagination). |

‎apps/sim/lib/webhooks/providers/plane.test.ts‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,25 @@ describe('Plane signed webhook delivery', () => {
6969
).toBe(401)
7070
})
7171

72-
it.each(['webhook-a', 'untracked-webhook'])(
73-
'accepts the tracked previous secret only for its subscription: %s',
74-
async (webhookId) => {
72+
it.each([
73+
['webhook-a', true, 200],
74+
['webhook-a', false, 401],
75+
['webhook-a', undefined, 401],
76+
['untracked-webhook', true, 401],
77+
])(
78+
'accepts the tracked previous secret only during pending activation: %s, %s',
79+
async (webhookId, pending, expectedStatus) => {
7580
const raw = JSON.stringify({ ...V2, webhook_id: webhookId })
7681
const signature = createHmac('sha256', SECRET).update(raw).digest('hex')
7782
const ctx = authContext(raw, signature, 'replacement-secret')
83+
ctx.providerConfig.subscriptionActivationPending = pending
7884
ctx.providerConfig.previousSubscription = {
7985
provider: 'plane',
8086
providerConfig: { externalId: 'webhook-a', webhookSecret: SECRET },
8187
}
8288
if (!planeHandler.verifyAuth) throw new Error('Plane authentication is missing')
8389
const response = await planeHandler.verifyAuth(ctx)
84-
expect(response?.status ?? 200).toBe(webhookId === 'webhook-a' ? 200 : 401)
90+
expect(response?.status ?? 200).toBe(expectedStatus)
8591
}
8692
)
8793

‎apps/sim/lib/webhooks/providers/plane.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,10 @@ const verifyPlaneSignature = createHmacVerifier({
103103
export const planeHandler: WebhookProviderHandler = {
104104
verifyAuth(ctx) {
105105
let providerConfig = ctx.providerConfig
106-
if (providerConfig.previousSubscription) {
106+
if (
107+
providerConfig.subscriptionActivationPending === true &&
108+
providerConfig.previousSubscription
109+
) {
107110
try {
108111
const payload: unknown = JSON.parse(ctx.rawBody)
109112
providerConfig = previousPlaneDeliveryConfig(providerConfig, payload) ?? providerConfig

‎apps/sim/tools/generated/tool-metadata.ts‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

‎apps/sim/tools/plane/list_attachments.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export const planeListAttachmentsTool: ToolConfig<
101101
type: 'number',
102102
required: false,
103103
visibility: 'user-or-llm',
104-
description: 'Page size (max 200).',
104+
description: 'API v2 only. Page size (maximum 200).',
105105
},
106106
fields: {
107107
type: 'string',

‎apps/sim/tools/plane/list_comments.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export const planeListCommentsTool: ToolConfig<PlaneListCommentsParams, PlaneLis
9090
type: 'number',
9191
required: false,
9292
visibility: 'user-or-llm',
93-
description: 'Page size. Defaults to 50, maximum 200.',
93+
description: 'Page size. Maximum 200 for API v2 and 100 for API v1.',
9494
},
9595
offset: {
9696
type: 'number',

‎apps/sim/tools/plane/list_cycles.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export const planeListCyclesTool: ToolConfig<PlaneListCyclesParams, PlaneListCyc
7474
type: 'number',
7575
required: false,
7676
visibility: 'user-or-llm',
77-
description: 'Page size. Defaults to 50, maximum 200.',
77+
description: 'Page size. Maximum 200 for API v2 and 100 for API v1.',
7878
},
7979
offset: {
8080
type: 'number',

‎apps/sim/tools/plane/list_labels.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export const planeListLabelsTool: ToolConfig<PlaneListLabelsParams, PlaneListLab
7575
type: 'number',
7676
required: false,
7777
visibility: 'user-or-llm',
78-
description: 'Page size. Defaults to 50, maximum 200.',
78+
description: 'Page size. Maximum 200 for API v2 and 100 for API v1.',
7979
},
8080
offset: {
8181
type: 'number',

‎apps/sim/tools/plane/list_links.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export const planeListLinksTool: ToolConfig<PlaneListLinksParams, PlaneListLinks
7575
type: 'number',
7676
required: false,
7777
visibility: 'user-or-llm',
78-
description: 'Page size (max 200).',
78+
description: 'Page size. Maximum 200 for API v2 and 100 for API v1.',
7979
},
8080
search: {
8181
type: 'string',

‎apps/sim/tools/plane/list_modules.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export const planeListModulesTool: ToolConfig<PlaneListModulesParams, PlaneListM
8282
type: 'number',
8383
required: false,
8484
visibility: 'user-or-llm',
85-
description: 'Page size. Defaults to 50, maximum 200.',
85+
description: 'Page size. Maximum 200 for API v2 and 100 for API v1.',
8686
},
8787
offset: {
8888
type: 'number',

0 commit comments

Comments
 (0)