Overview
Webhooks connect Taskade automations to external services in both directions:
- Inbound webhooks — external services send data into Taskade to trigger automations.
- Outbound HTTP requests — automations call out to external APIs as action steps.
- Receiving Taskade events — combine a Taskade trigger (for example, task completed) with an outbound HTTP action to push events to your app.
Two ways to receive Taskade events:
- No-code: build an automation with a Taskade trigger plus an HTTP action. See Receiving Taskade Events.
- Programmatic: register a signed outbound webhook with
POST /api/v2/webhooks— see the Webhook Registration API. Available on Pro and above.
When your integration needs registrations managed in code and verifiable HMAC deliveries, use the signed API. Its events are the explicit list in Supported events.
The no-code route is broader. Automation triggers also cover events such as task added, task completed, due-date changes, custom-field updates, schedules, and connected services. You choose the outgoing payload in the HTTP action.
Inbound Webhooks
Receive data from an external service to start a Taskade automation.
How It Works
- Create a webhook trigger in an automation flow.
- Copy the unique webhook URL that Taskade generates.
- Configure your external service to POST JSON data to the URL.
- Use the webhook payload as dynamic data in subsequent actions.
Taskade generates one webhook URL per automation. Find it in the trigger configuration panel after you select the Webhook trigger.
Payload Structure
The webhook accepts any valid JSON body. Each payload field becomes a dynamic variable for subsequent actions.
Example payload:
{
"event": "form_submitted",
"name": "Jane Doe",
"email": "jane@example.com",
"message": "Interested in a demo"
}
All four fields (event, name, email, message) are available as dynamic variables in your automation steps.
Authentication
Webhook URLs are unique and unguessable: each contains a cryptographically random token. For additional security:
- Validate incoming payloads in your automation logic. For example, require an expected
eventvalue. - If you suspect exposure, delete and re-create the trigger to rotate its webhook URL.
Treat your webhook URLs like passwords. Do not share them publicly or commit them to source control.
Bearer Token Authentication
For stronger protection on inbound webhook triggers, you can require a secret bearer token from the caller. When you enable the token, Taskade rejects every request without a valid token before the automation runs.
Setup:
- Open the webhook trigger configuration panel in your automation.
- Enable Bearer Token authentication and set a secret token value.
- Generate or enter a secret.
- Store the secret securely. Taskade does not show it again.
Calling the webhook:
Every inbound request must include the token in the Authorization header:
POST https://www.taskade.com/webhooks/<your-webhook-id>
Authorization: Bearer your_api_token_placeholder
Content-Type: application/json
{
"event": "form_submitted",
"name": "Jane Doe"
}
Taskade returns 401 Unauthorized for a request with a missing or incorrect token. The automation does not run.
Webhook automations are available on Pro and above. Free and Starter plans cannot create webhook triggers or subscriptions. See taskade.com/pricing.
Common Patterns
| Source | What Happens in Taskade |
|---|---|
| External form submission | Create a task + notify the team |
| Stripe payment webhook | Update project status + send confirmation |
| GitHub CI/CD webhook | Update deployment status in a project |
| CRM event (HubSpot and others) | Sync contact data to a Taskade project |
Outbound HTTP Requests
For outbound communication, use the HTTP Request action in any automation to call external APIs.
Configuration
| Setting | Details |
|---|---|
| Method | GET, POST, PUT, DELETE |
| URL | Any valid endpoint |
| Headers | Custom headers supported (for example, Authorization, Content-Type) |
| Body | JSON or form data |
Response data from the HTTP request becomes dynamic variables in subsequent automation steps. Use these variables to chain API calls.
Example: Post to an External API
| Setting | Value |
|---|---|
| Method | POST |
| URL | https://api.example.com/notifications |
| Headers | Content-Type: application/jsonAuthorization: Bearer your_api_token_placeholder |
Body:
{
"channel": "#alerts",
"text": "New task created: {{task.name}}"
}
Webhook Registration API
Requires Pro or above. Registration returns a signing secret exactly once, so store it before anything else. The authoritative schema is the live Action API v2 spec.
Register signed outbound webhooks through the public API. You do not need an automation flow.
Taskade sends the event payload with POST. It signs every delivery with an HMAC secret.
The programmatic event list is smaller than the no-code automation trigger catalog.
This API supersedes the unsigned subscribeWebhook and unsubscribeWebhook operations. Those operations still work and are deprecated. See Legacy unsigned subscriptions.
Register a webhook
POST /api/v2/webhooks takes one target URL, one or more events, and optional workspace scoping:
POST https://www.taskade.com/api/v2/webhooks
Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN
Content-Type: application/json
{
"targetUrl": "https://your-app.example.com/hooks/taskade",
"events": ["task.due", "task.assigned"],
"spaceIds": []
}
Response (secret is shown once):
{
"ok": true,
"webhook": {
"id": "https://your-app.example.com/hooks/taskade",
"url": "https://your-app.example.com/hooks/taskade",
"events": ["task.due", "task.assigned"],
"spaceIds": [],
"createdAt": "2026-07-21T09:00:00.000Z"
},
"secret": "your_signing_secret_placeholder"
}
A webhook's id is its target URL. URL-encode it whenever you use it as a path parameter.
Supported events
The events array accepts only these six names. Any other value returns 400:
| Event | Fires when |
|---|---|
task.due |
A task's due date arrives |
task.assigned |
A task is assigned to someone |
comment.created |
A comment is added to a task |
project.created |
A project is created |
project.assigned |
A project is assigned to someone |
project.joined |
Someone joins a project |
Delivery payload
The delivery body is the event's own object. There is no event-name envelope. Branch on the fields you require rather than on a type discriminator:
| Event | Top-level fields |
|---|---|
task.due |
spaceName, spaceId, projectName, projectId, id, text, isCompleted, assignees, taskStartDate, taskStartTime, taskStartTimezone, taskEndDate, taskEndTime, taskEndTimezone |
task.assigned |
projectName, projectId, assignerName, assignedNodes[] (each nodeId, nodeText, isCompleted, assignees) |
comment.created |
projectName, projectId, nodeId, nodeText, commenterDisplayName, commenterHandle, commentBody, commentBodyType, assignees, mentionedHandles |
project.created |
spaceName, spaceId, projectName, projectId, creatorName |
project.assigned |
spaceName, spaceId, projectName, projectId, assignerName, assigneeName, assigneeId |
project.joined |
spaceId, projectName, projectId, joinerName, joinerUserId |
When your handler needs to know which event arrived, register one URL per event. Otherwise, key off a field that only one event carries.
Scope to specific workspaces
"spaceIds": [] (the default) delivers matching events from all your workspaces. Pass workspace ids to receive events from only those workspaces:
{
"targetUrl": "https://your-app.example.com/hooks/taskade",
"events": ["project.created"],
"spaceIds": ["SPACE_ID_1", "SPACE_ID_2"]
}
List, inspect, delete
# list all registered webhooks
curl https://www.taskade.com/api/v2/webhooks \
-H "Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN"
# get or delete one — the :id is the URL-encoded target URL
curl -X DELETE \
"https://www.taskade.com/api/v2/webhooks/https%3A%2F%2Fyour-app.example.com%2Fhooks%2Ftaskade" \
-H "Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN"
GET /api/v2/webhooks returns { "ok": true, "items": [ ... ] }.
DELETE /api/v2/webhooks/{id} returns { "ok": true, "deleted": <boolean> }. deleted is false when no webhook matched that id. The status is 200 either way.
GET /api/v2/webhooks/{id} returns { "ok": true, "webhook": { ... } }.
Validate delivery signatures
Every delivery carries an X-Taskade-Signature header. Its value is sha256= followed by the hex HMAC-SHA256 of the raw request body, keyed with your webhook's secret:
X-Taskade-Signature: sha256=5f4dcc3b5aa765d61d8327deb882cf99...
Before JSON parsing, recompute the HMAC over the raw body. Compare the signatures in constant time:
import crypto from "node:crypto";
function verifyTaskadeWebhook(rawBody: Buffer, signatureHeader: string, secret: string): boolean {
const expected = `sha256=${crypto.createHmac("sha256", secret).update(rawBody).digest("hex")}`;
return (
expected.length === signatureHeader.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader))
);
}
Reject each delivery whose signature does not match.
Limits & requirements
| Rule | Detail |
|---|---|
| Plan | Pro or above, otherwise 402 with code: "PAYMENT_REQUIRED". Deleting is always allowed, so a downgraded account can still clean up. |
| Account | The account email must be verified, otherwise 403 with code: "FORBIDDEN". |
| Target URL | Must be https (deliveries use an SSRF-guarded fetch). Max 2,048 characters once URL-encoded, because the encoded URL is the :id path parameter. |
| Limit | 100 event-workspace combinations per account. One webhook with 3 events scoped to 2 workspaces counts as 6. |
| Scope | All workspaces by default. Narrow the scope with spaceIds. |
| Dashboard | You can also create and manage outgoing webhooks in Settings > API. |
Legacy: unsigned subscriptions (deprecated)
The subscribeWebhook and unsubscribeWebhook operations still work, but they are deprecated.
Each subscription covers one event. Its scope is account-wide, and its deliveries are not signed.
Use POST /api/v2/webhooks for new integrations. To migrate, register the same URL there and remove the old subscription.
Receiving Taskade Events
To send Taskade events to your app, build an automation with two ends. Start it with a Taskade trigger, such as a new task or a completed task.
End it with an Outbound HTTP Request to your endpoint. The trigger's fields are available as dynamic variables in the HTTP body.
Common triggers and their payloads
Task added fires when a new task is added to a project:
{
"projectId": "abc123",
"nodeId": "node_456",
"nodeText": "Follow up with client",
"projectTitle": "Sales Pipeline",
"nodeNote": "Optional note text",
"projectLink": "https://www.taskade.com/d/abc123",
"assignees": [ { "handle": "jane" } ],
"startDate": "2026-06-10",
"endDate": "2026-06-12"
}
Task completed fires when a task is marked complete:
{
"projectId": "abc123",
"nodeId": "node_456",
"nodeText": "Follow up with client",
"projectTitle": "Sales Pipeline",
"projectLink": "https://www.taskade.com/d/abc123",
"completedBy": "jane",
"completedAt": "2026-06-11T14:30:00Z",
"triggerTime": "2026-06-11T14:30:01Z",
"assignees": [ { "handle": "jane" } ]
}
Task custom-field values appear as additional keys. Other triggers use the same pattern.
See the Action & Trigger Reference for new comments, dates, project completion, and schedules.
Rate Limits
Taskade can throttle excessive inbound webhook calls. For high-volume traffic, batch events or add a queue to the sender.
Next Steps
- Authentication — set up API tokens for outbound requests
- Native integrations — Use a built-in connector for supported services.
- Outbound MCP — Use an MCP Client connector for another MCP server.