Skip to content
Search⌘K

Webhooks, Zapier and Make

A webhook sends what happens on your boards to an address on the internet: your own server, a Zapier Zap or a Make scenario. Every delivery is a signed POST with IDs only – no titles, no texts. The receiver reads the details through the API with its own token, so that token’s access decides what it may see.

Who sets them up: board admins for their board; workspace owners and admins for every board that the whole workspace can see. A private board needs a webhook of its own, set up by its admins. Confidential boards never send anything.

  1. Open the webhooks page: on the workspace settings page (your avatar → the workspace) → Webhooks, Zapier and Make → Webhooks; for one board: board header → Settings → Webhooks of this board.
  2. Add a webhook: a Name (for people), the Address (URL), Which boards – Every board visible to the whole workspace or One board – and the Events.
  3. Save webhook. Copy the Signing secret now – it is shown only once. Your receiver checks every delivery with it.
  4. Open the webhook and Send a test event; the Delivery log shows whether it arrived.

The address must be https on the standard port, on a public host. Addresses in private networks (10.x, 192.168.x, localhost, link-local and cloud metadata addresses, also IPv6 and names that point there) are refused – when you save and again at every delivery. Redirects are not followed. The address and the secret are stored encrypted; the page shows only the host and the last four characters.

  • Zapier: create a Zap with the trigger Webhooks by Zapier → Catch Hook, copy its address and paste it as the webhook’s address in Contals.
  • Make: create a scenario with Webhooks → Custom webhook, copy its address and paste it in Contals.
  • To act on the event, add a step that reads the card through the Contals API (for example Zapier’s Webhooks by Zapier → GET with Authorization: Bearer <token>, using the links.card of the delivery).

Contals apps for both are ready on our side and wait for their listing in the Zapier and Make directories. They connect with a personal API token with the scopes read, write and admin, subscribe by themselves when you switch a Zap or scenario on, unsubscribe when you switch it off, and fill in the card, comment or status update for you. Subscriptions made that way appear on the webhooks page like any other, marked Zapier or Make.

EventWhen
card.createdA card is created
card.updatedA card’s title or description changes
card.movedA card moves to another list
card.completed / card.reopenedA card is marked done / not done
card.archived / card.restoredA card is archived / restored
card.assignees_changedPeople are added to or removed from a card
card.labels_changedLabels on a card change
card.due_date_changedA card gets a new due date (or loses it); data has dueDate and previousDueDate (plain dates), dueAt and previousDueAt (the time as an instant, or null when due all day), startDate and startAt
comment.addedSomeone comments on a card
checklist_item.completedA checklist item is done
list.created / list.archivedA list is created / archived
status.postedA board gets a status update
webhook.testSend a test event (always delivered)

Changes made by imports, copies between boards and Contals itself stay quiet; changes through the API, automation and public pages send events.

POST /your/address HTTP/1.1
Content-Type: application/json
User-Agent: Contals-Webhooks/1.0
webhook-id: itg_01jq8m6g1hm5b7e9g1j3m5p7r9:v42
webhook-timestamp: 1792137600
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
{
"id": "itg_01jq8m6g1hm5b7e9g1j3m5p7r9:v42",
"type": "card.created",
"format": "contals-webhook/1",
"occurredAt": "2026-10-16T08:00:00.000Z",
"workspaceId": "wsp_01jq8m1v7hb2f5j9m3q7t1w5y9",
"boardId": "brd_01jq8m2x9kd4h7n1p3s5v7w9y1",
"boardVersion": 42,
"actor": { "type": "person", "id": "usr_01jq8m0t5f9z3d7h1k5n9r3v7x" },
"data": { "cardId": "crd_01jq8m3a5bf9w8x0e2r4t6y8z0", "listId": "lst_01jq8m2zz4c8g2k6m0q4t8w2a6" },
"links": {
"board": "https://app.contals.com/api/public/v1/boards/brd_01jq8m2x9kd4h7n1p3s5v7w9y1",
"card": "https://app.contals.com/api/public/v1/boards/brd_01jq8m2x9kd4h7n1p3s5v7w9y1/cards/crd_01jq8m3a5bf9w8x0e2r4t6y8z0",
"lists": "https://app.contals.com/api/public/v1/boards/brd_01jq8m2x9kd4h7n1p3s5v7w9y1/lists"
}
}
  • id is the same for every attempt of one delivery: use it to ignore repeats.
  • actor.type is person, automation, guest (a public page) or system.
  • Fetch the details from links with your own token. A board the token cannot open answers 404.

The headers follow Standard Webhooks: webhook-signature holds v1,<signature> – a base64 HMAC-SHA256 of <webhook-id>.<webhook-timestamp>.<body> with the bytes of your secret after whsec_ (base64). Refuse deliveries whose timestamp is more than five minutes old.

import { createHmac, timingSafeEqual } from 'node:crypto'
function verify(secret, headers, rawBody) {
const id = headers['webhook-id'], ts = headers['webhook-timestamp']
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false
const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64')
const expected = Buffer.from(createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest('base64'))
return headers['webhook-signature'].split(' ').some((part) => {
const sig = Buffer.from(part.replace(/^v1,/, ''))
return sig.length === expected.length && timingSafeEqual(sig, expected)
})
}

New signing secret on the webhook’s page creates a new secret, shown once. For 24 hours both secrets sign every delivery (the header then carries two signatures), so your receiver can switch without missing one.

  • Answer with a 2xx status within 10 seconds. Timeouts, 429 and 5xx answers are retried with growing pauses – after 30 seconds, 2 and 10 minutes, half an hour, 1, 3, 6 and 12 hours – about a day in all; then the delivery is marked Gave up.
  • Other 4xx answers and redirects are not retried. 410 Gone switches the webhook off at once (Zapier answers this way for a Zap that was switched off).
  • After 10 failed deliveries in a row the webhook switches itself off, and its owner gets an e-mail with a link to the delivery log. Switch it on again on its page once the receiver works – that resets the count and makes you its owner.
  • The Delivery log keeps the last 100 deliveries of 30 days with status, HTTP code, attempts and the body. Failed, given-up and skipped deliveries can be Sent again.
  • A webhook whose owner can no longer manage its boards switches itself off. If its board becomes confidential, it sends nothing more; you can still pause or delete it.
FreeTeamBusiness
Webhooks per organization225100
Deliveries per day50010,00050,000

A board can have at most 10 webhooks. Deliveries over the daily limit are skipped and marked in the log. Zapier and Make subscriptions count as webhooks.

Zapier, Make and your own tools can manage subscriptions through the API with a token that has the admin scope (subscribing is configuration, like sharing a board):

  • POST /api/public/v1/webhooks with url, events and either boardId or workspaceId (and an optional name) – the answer carries the subscription and its secret, the only time it is shown.
  • GET /api/public/v1/webhooks?workspaceId=… – the subscriptions you manage (never the address or the secret).
  • DELETE /api/public/v1/webhooks/{webhookId} – unsubscribe.

Creating, changing, rotating, sending again and deleting are recorded in the audit log.