From 45e195ad7a69bb4cc32c28d69a27e9ad93e51be9 Mon Sep 17 00:00:00 2001 From: johnxie Date: Fri, 19 Jun 2026 04:20:51 -0700 Subject: [PATCH] feat(task_due): subscribe via public Action API v2 (POST /api/v2/subscribeWebhook) Move the task_due trigger off the internal /webhooks/zapier/{subscribe,unsubscribe} routes onto the public, documented Action API v2: - performSubscribe -> POST /api/v2/subscribeWebhook { targetUrl, triggerType:'task.due' } - performUnsubscribe -> POST /api/v2/unsubscribeWebhook { hookId } (was DELETE + query param) - account-level: the public endpoint ignores scope, so space/project inputs no longer narrow the subscription (kept for forward-compat once scoped subscriptions ship) - requires a paid plan (Pro+); free/Starter receive 402 - performList still uses the internal sample route (no public equivalent yet) Depends on taskcade#26765 (subscribeWebhook endpoint + paywall), now merged. README: drop the 'in progress' note; bump 1.1.0 -> 1.2.0. --- README.md | 2 +- package.json | 2 +- src/triggers/taskDue.ts | 37 +++++++++++++++++++------------------ 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 750c642..8c5c36e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Hidden dropdown helpers (not user-facing): `get_all_spaces`, `get_all_projects`, Auth: OAuth2 (`www.taskade.com/oauth2/*`). The API also supports [Personal Access Tokens](https://www.taskade.com/settings/api) (`Authorization: Bearer tskdp_…`) for other platforms. -> Note: the `task_due` trigger currently uses Taskade-internal webhook routes. A public webhook-subscription API (`POST /api/v2/subscribeWebhook`) is in progress — once live, event triggers become portable to any platform. +> Note: the `task_due` trigger subscribes via the public **Action API v2** (`POST /api/v2/subscribeWebhook` / `unsubscribeWebhook`, available on **Pro and above**), so event triggers are portable to any platform. Its test-sample fetch still uses an internal route pending a public sample endpoint. ## Development diff --git a/package.json b/package.json index 85ed3a8..e613e6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "taskade", - "version": "1.1.0", + "version": "1.2.0", "description": "Taskade is a collaboration platform for remote teams to organize and manage projects.", "main": "index.js", "scripts": { diff --git a/src/triggers/taskDue.ts b/src/triggers/taskDue.ts index dc585dd..b491733 100644 --- a/src/triggers/taskDue.ts +++ b/src/triggers/taskDue.ts @@ -21,6 +21,9 @@ const perform = async (z: ZObject, bundle: Bundle) => { return [payload]; }; +// performList still uses the internal route — the public Action API v2 does not +// yet expose a "list recent due tasks" sample endpoint. Subscribe/unsubscribe are +// fully on the public API; this remains until a public sample endpoint ships. const performList = async (z: ZObject, bundle: Bundle) => { const options: HttpRequestOptions = { url: 'https://www.taskade.com/webhooks/zapier/taskdue/performlist', @@ -45,53 +48,51 @@ const performList = async (z: ZObject, bundle: Bundle) => { }); }; +// Subscribe via the public Action API v2 (POST /api/v2/subscribeWebhook). +// Account-level only: the public endpoint takes { targetUrl, triggerType } and +// ignores scope, so the space/project inputs do not narrow the subscription yet +// (they remain for forward-compatibility once scoped subscriptions ship). +// Requires a paid plan (Pro+); free/Starter accounts receive 402. const performSubscribe = async (z: ZObject, bundle: Bundle) => { const options: HttpRequestOptions = { - url: 'https://www.taskade.com/webhooks/zapier/subscribe', + url: 'https://www.taskade.com/api/v2/subscribeWebhook', method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: `Bearer ${bundle.authData.access_token}`, }, - params: {}, body: { - hookUrl: bundle.targetUrl, - triggerType: 'TaskDue', - spaceId: bundle.inputData.space_id != null ? bundle.inputData.space_id : null, - projectId: bundle.inputData.project_id != null ? bundle.inputData.project_id : null, + targetUrl: bundle.targetUrl, + triggerType: 'task.due', }, }; return z - .request('https://www.taskade.com/webhooks/zapier/subscribe', options) + .request('https://www.taskade.com/api/v2/subscribeWebhook', options) .then((response) => { response.throwForStatus(); - const results = response.json; - - // You can do any parsing you need for results here before returning them - - return results; + // { ok: true, hookId } — hookId is read back in performUnsubscribe via bundle.subscribeData. + return response.json; }); }; const performUnsubscribe = async (z: ZObject, bundle: Bundle) => { const options: HttpRequestOptions = { - url: 'https://www.taskade.com/webhooks/zapier/unsubscribe', - method: 'DELETE', + url: 'https://www.taskade.com/api/v2/unsubscribeWebhook', + method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: `Bearer ${bundle.authData.access_token}`, }, - params: { - // @ts-ignore + body: { + // @ts-ignore - subscribeData carries the hookId returned by performSubscribe hookId: bundle.subscribeData.hookId, }, }; - return z.request('https://www.taskade.com/webhooks/zapier/unsubscribe', options); - // return z.request(options).then((response) => z.JSON.parse(response.content)); + return z.request('https://www.taskade.com/api/v2/unsubscribeWebhook', options); }; export default {