Guides

Webhooks

11 min readBuilding

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:

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

  1. Create a webhook trigger in an automation.
  2. Copy the URL from the Webhook URL field in the trigger panel.
  3. Enable the automation. Taskade then generates the authorization token. See Authentication.
  4. Configure your external service to POST JSON data to the URL, with the token in the Authorization header.
  5. Use the webhook payload as dynamic data in subsequent actions.


Taskade generates one webhook URL per automation. The URL has the form https://www.taskade.com/webhooks/flow/<automation-id>/sync. It identifies the automation, so it does not change.

Webhook triggers run on Pro and above. On Free and Starter, a call returns 402 with code: "PAYMENT_REQUIRED", and the automation does not run.

Payload Structure

The webhook accepts a JSON body (application/json) or multipart/form-data. Taskade rejects any other content type with 400. A JSON body larger than about 1.1 MB returns 413. Taskade applies the limit after it encodes the body, so the message of a PAYLOAD_TOO_LARGE error states about 1.5 MB. Each payload field becomes a dynamic variable for subsequent actions.

Example payload:

Json
{
  "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

A webhook trigger requires a Bearer token by default. When you enable the automation, Taskade generates the token and rejects every call that does not send it. The token is the secret that protects the webhook, because the URL does not change.

Get the token:

  1. Open the webhook trigger panel in your automation.
  2. Make sure that Require Authorization Token is on.
  3. Enable the automation. Taskade generates the token.
  4. In the Authorization Token field, click Show or Copy.

Calling the webhook:

Every inbound request must include the token in the Authorization header:

Http
POST https://www.taskade.com/webhooks/flow/<automation-id>/sync
Authorization: Bearer your_webhook_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.

To accept calls without a token, turn off Require Authorization Token. The panel then warns that anyone with the URL can trigger the automation. If you do this, validate each payload in your automation logic. For example, require an expected event value.


Treat the authorization token like a password. Do not share it publicly. Do not commit it to source control.

Return a response to the caller

The URL ends in /sync. If the automation defines a Webhook Response output, the call waits for the run and returns that response. Otherwise, Taskade returns 200 with an empty body as soon as it accepts the call.

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 Send HTTP Request action in an automation. It can call an external API. Later steps can use the response.

Configuration

Setting Details
Method GET, POST, PATCH, PUT, DELETE, HEAD
URL The external endpoint
Headers Request headers such as Authorization and Content-Type
Query Parameters Values added to the URL query string
Body Type none, json, raw, formData, or multipart
Response Type No parsed body, or JSON
Timeout (ms) Maximum wait. Invalid, zero, or negative values use 30 seconds
Follow Redirects Off by default. When enabled, Taskade follows up to five safe redirects
Return Status On Error Return the response and status instead of failing on a non-2xx response


Response data from the HTTP request becomes dynamic variables in subsequent automation steps. Use these variables to chain API calls.

Choose a body type

Match the body mode to the API contract.

Body type What Taskade sends Use it for
none No request body GET, HEAD, or another bodyless request
json A JSON value or supported structured value JSON APIs
raw The configured body without JSON conversion Text, XML, or another raw payload
formData Object fields as form data Simple form submissions
multipart Validated multipart fields and files File uploads and mixed form data

JSON mode sets Content-Type: application/json when you do not provide another content type. If the body is text, enter valid JSON when the receiving API expects JSON.

Use none for a request without a body. Do not send an empty JSON object as a placeholder.

Insert dynamic values with the variable controls in the automation editor. The editor writes the supported expression into the field.

Example: Post to an External API

Setting Value
Method POST
URL https://api.example.com/notifications
Headers Content-Type: application/json
Authorization: Bearer your_api_token_placeholder

Body:

Json
{
  "channel": "#alerts",
  "text": "New task created: {{task.name}}"
}

Webhook Registration API


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.

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:

Http
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):

Json
{
  "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. When you use it as a path parameter, URL-encode it.

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:

Json
{
  "targetUrl": "https://your-app.example.com/hooks/taskade",
  "events": ["project.created"],
  "spaceIds": ["SPACE_ID_1", "SPACE_ID_2"]
}

List, inspect, delete

Bash
# 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:

Typescript
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. Deliveries are not signed.

Use POST /api/v2/webhooks for new integrations. To migrate, register the same URL there. Then 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:

Json
{
  "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:

Json
{
  "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. You can also add a queue on the sender.


Next Steps