Guide to Trello Webhooks: Features and Best Practices
Trello webhooks notify your application when a board or card changes: a card is created, a card is updated, a comment is added. If you're syncing Trello with another system or automating off board activity, webhooks are how you react without polling the API.
This guide covers how Trello webhooks work, the actions you can watch, how to verify the x-trello-webhook signature (which is SHA1 over the body concatenated with your callback URL), the creation HEAD check, the retry behavior, and the best practices for production.
What are Trello webhooks?
A Trello webhook watches a model (a board, list, card, or member) and POSTs to your callback URL when an action occurs on that model. The payload contains an action (with action.type), the model being watched, and the webhook object. You create webhooks through the REST API, and Trello signs each delivery so you can confirm it came from Trello.
The signature construction is unusual: it covers the request body plus the callback URL, and it uses SHA1.
Trello webhook features
| Feature | Details |
|---|---|
| Configuration | REST API: POST /1/tokens/{token}/webhooks with idModel + callbackURL |
| Signature header | x-trello-webhook |
| Signature scheme | base64 HMAC-SHA1 over raw body + callbackURL, keyed with the OAuth application secret |
| Creation check | HTTP HEAD to the callback URL; must return 200 (invalid SSL also fails) |
| Payload | action (with action.type), model, webhook |
| Retries | 3 attempts with backoff (30s, 60s, 120s) |
| Auto-disable | After ~30 days of consecutive failures (>1,000 failures) |
| SDK | No official server-side npm/pip SDK |
Common actions
Trello events are identified by action.type. Card actions are the common ones:
| Action type | Fires when |
|---|---|
createCard | A card is created |
updateCard | A card is updated (moved, renamed, due date changed) |
commentCard | A comment is added to a card |
deleteCard | A card is deleted |
addMemberToCard | A member is added to a card |
addChecklistToCard | A checklist is added to a card |
Branch on action.type, and consult Trello's action-types reference for the full list.
Setting up Trello webhooks
Create a webhook via the API, pointing it at a model (idModel) and your callbackURL:
curl -X POST "https://api.trello.com/1/tokens/{token}/webhooks/?key={apiKey}" \
-H "Content-Type: application/json" \
-d '{ "idModel": "{boardOrCardId}", "callbackURL": "https://your-app.example.com/webhook" }'
At creation, Trello sends an HTTP HEAD request to your callbackURL and won't create the webhook unless it returns 200. An invalid SSL certificate also fails creation (a missing certificate does not). Make sure your endpoint answers HEAD with a 200.
Securing Trello webhooks
Each delivery carries an x-trello-webhook header: a base64-encoded HMAC-SHA1 where the signed content is the raw request body concatenated with the exact callbackURL you registered, keyed with your application's OAuth secret. Two things to get right: it's SHA1 (not SHA256), and the callback URL is appended to the body before hashing.
const crypto = require("crypto");
const SECRET = process.env.TRELLO_OAUTH_SECRET;
const CALLBACK_URL = process.env.TRELLO_CALLBACK_URL; // exactly as registered
function verify(rawBody, signature) {
const content = Buffer.concat([rawBody, Buffer.from(CALLBACK_URL)]);
const expected = crypto.createHmac("sha1", SECRET).update(content).digest("base64");
const a = Buffer.from(expected);
const b = Buffer.from(signature || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.head("/webhook", (req, res) => res.sendStatus(200)); // creation HEAD check
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
if (!verify(req.body, req.headers["x-trello-webhook"])) {
return res.sendStatus(401);
}
res.sendStatus(200); // acknowledge fast
processQueue.add(JSON.parse(req.body)); // process asynchronously
});
The same check in Python:
import base64
import hashlib
import hmac
import os
SECRET = os.environ["TRELLO_OAUTH_SECRET"].encode()
CALLBACK_URL = os.environ["TRELLO_CALLBACK_URL"].encode()
def verify(raw_body: bytes, signature: str) -> bool:
content = raw_body + CALLBACK_URL
digest = hmac.new(SECRET, content, hashlib.sha1).digest()
expected = base64.b64encode(digest).decode()
return hmac.compare_digest(expected, signature or "")
Trello's own example hashes JSON.stringify(request.body) + callbackURL; verifying against the raw body plus the callback URL avoids re-serialization mismatches.
Trello webhook limitations and pain points
The signature covers body plus callback URL, with SHA1
The Problem: Two easy mistakes: using SHA256 instead of SHA1, and hashing only the body instead of body + callbackURL. Either one makes every delivery fail verification.
Why It Happens: Trello's scheme predates SHA256 conventions and binds the signature to the registered callback URL.
Workarounds:
- Use SHA1, base64, and concatenate the exact registered
callbackURLafter the raw body. - Keep the
callbackURLvalue byte-identical to what you registered.
How Hookdeck Can Help: Hookdeck verifies the Trello signature at the edge, including the body-plus-callback-URL construction, so your app receives pre-verified events without reproducing the scheme.
The creation HEAD check
The Problem: If your endpoint doesn't answer a HEAD request with 200, or has an invalid SSL cert, webhook creation fails outright, which is confusing if you only implemented POST.
Why It Happens: Trello verifies the endpoint is reachable and valid before creating the webhook.
Workarounds:
- Implement a HEAD handler that returns 200.
- Ensure a valid TLS certificate on the callback URL.
How Hookdeck Can Help: Hookdeck provides a stable, valid HTTPS URL that answers Trello's HEAD check, then forwards verified events to your endpoint.
Limited retries then auto-disable
The Problem: Trello retries a failed delivery only 3 times (30s, 60s, 120s), and after roughly 30 days of consecutive failures (over 1,000) the webhook is auto-disabled. A short outage can drop events; a sustained one loses the webhook.
Why It Happens: Trello's retry budget is small, and it prunes long-dead webhooks.
Workarounds:
- Acknowledge fast so transient issues don't consume the 3-attempt budget.
- Monitor webhook status and recreate a disabled webhook.
- Reconcile against the API for anything you can't afford to miss.
How Hookdeck Can Help: Hookdeck accepts every delivery and retries to your downstream on a schedule you control, so Trello's 3-attempt limit isn't your only safety net and a sustained outage doesn't disable the webhook.
Duplicates and thin actions
The Problem: The same action can be delivered more than once, and the payload is an action summary rather than full state.
Why It Happens: At-least-once delivery plus compact action payloads.
Workarounds:
- Dedupe on
action.id. - Fetch full state from the API when the action summary isn't enough.
How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so retries don't double-process. See our guide to webhook idempotency.
Best practices
Verify SHA1 over body + callbackURL
Use sha1, base64, concatenate the raw body with the exact registered callbackURL, key with your OAuth secret, and compare in constant time.
Answer the HEAD check
Return 200 to HEAD requests and serve a valid TLS certificate so webhook creation succeeds.
Acknowledge fast, process asynchronously
Return 200 quickly and defer work to a queue so transient slowness doesn't burn the 3-attempt retry budget. See why to process webhooks asynchronously.
Dedupe on action.id
Use action.id as an idempotency key so retries don't double-process.
Monitor for auto-disable
Watch webhook status and recreate a webhook that's been disabled after sustained failures.
Make Trello webhooks production-ready
Hookdeck answers the HEAD check, verifies the SHA1 signature, deduplicates, and durably queues every action
Conclusion
Trello webhooks put board and card activity on a push channel your automation can act on, but the details are specific: a HEAD check at creation, and an x-trello-webhook signature that's base64 HMAC-SHA1 over the raw body concatenated with your callback URL. The delivery model is thin too: only 3 retries, auto-disable after sustained failures, and compact action payloads that often need a follow-up read.
That leaves the HEAD handler, correct SHA1 verification, deduplication, and monitoring on you. Hookdeck answers the HEAD check, verifies the signature, deduplicates, and durably queues every action at the edge, so your app only ever processes verified, unique events.
Get started with Hookdeck for free and handle Trello webhooks reliably in minutes.