Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/publish-n8n.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Publish n8n node

# n8n verified community nodes must be published from GitHub Actions with npm
# provenance (mandatory since 2026-05-01). Requires the NPM_TOKEN repo secret.
on:
workflow_dispatch:
push:
tags: ['n8n-v*']

permissions:
contents: read
id-token: write # npm provenance (OIDC)

jobs:
publish:
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/n8n-nodes-taskade
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org
- run: npm install
- run: npm run build
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ typings/
.next

lib

# package build output
dist/
30 changes: 30 additions & 0 deletions packages/n8n-nodes-taskade/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# n8n-nodes-taskade

Official [n8n](https://n8n.io) community node for [Taskade](https://www.taskade.com) — tasks, projects, and AI agents on the [Taskade public API](https://docs.taskade.com).

## Operations

| Resource | Operations |
|---|---|
| Task | Create, Complete, Uncomplete, Update, Delete, Move, Get Many |
| Project | Create (Markdown), Create From Template, Get Many |
| AI Agent | Prompt (synchronous response via the v2 Action API) |

The node is `usableAsTool`, so n8n AI agents can call Taskade directly.

## Credentials

Personal Access Token — create one at taskade.com → Settings → API (tokens start with `tskdp_`). The credential test calls `GET /api/v1/workspaces`.

## Installation

Self-hosted n8n: **Settings → Community Nodes → Install** → `n8n-nodes-taskade`.

## Development

```bash
npm install
npm run build # tsc -> dist/ + icon copy
```

Part of [taskade/integrations](https://github.com/taskade/integrations) — the public source-of-truth for Taskade integrations. MIT.
42 changes: 42 additions & 0 deletions packages/n8n-nodes-taskade/credentials/TaskadeApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type {
IAuthenticateGeneric,
ICredentialTestRequest,
ICredentialType,
INodeProperties,
} from 'n8n-workflow';

export class TaskadeApi implements ICredentialType {
name = 'taskadeApi';

displayName = 'Taskade API';

documentationUrl = 'https://docs.taskade.com';

properties: INodeProperties[] = [
{
displayName: 'Personal Access Token',
name: 'accessToken',
type: 'string',
typeOptions: { password: true },
default: '',
description:
'Create a token at taskade.com → Settings → API (tokens start with tskdp_)',
},
];

authenticate: IAuthenticateGeneric = {
type: 'generic',
properties: {
headers: {
Authorization: '=Bearer {{$credentials.accessToken}}',
},
},
};

test: ICredentialTestRequest = {
request: {
baseURL: 'https://www.taskade.com/api/v1',
url: '/workspaces',
},
};
}
46 changes: 46 additions & 0 deletions packages/n8n-nodes-taskade/nodes/Taskade/GenericFunctions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type {
IExecuteFunctions,
IHttpRequestMethods,
IHttpRequestOptions,
ILoadOptionsFunctions,
IDataObject,
} from 'n8n-workflow';

const BASE_V1 = 'https://www.taskade.com/api/v1';
const BASE_V2 = 'https://www.taskade.com/api/v2';

export async function taskadeApiRequest(
this: IExecuteFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
path: string,
body?: IDataObject,
version: 'v1' | 'v2' = 'v1',
qs?: IDataObject,
): Promise<IDataObject> {
const options: IHttpRequestOptions = {
method,
url: `${version === 'v2' ? BASE_V2 : BASE_V1}${path}`,
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
body,
qs,
json: true,
};
if (body === undefined) {
delete options.body;
}
return (await this.helpers.httpRequestWithAuthentication.call(
this,
'taskadeApi',
options,
)) as IDataObject;
}

/** Returns `items` from a Taskade `{ ok, items }` response, tolerating absent fields. */
export async function taskadeApiList(
this: IExecuteFunctions | ILoadOptionsFunctions,
path: string,
qs?: IDataObject,
): Promise<IDataObject[]> {
const response = await taskadeApiRequest.call(this, 'GET', path, undefined, 'v1', qs);
return (response.items as IDataObject[]) ?? [];
}
Loading
Loading