Integrations
Outbound webhooks and Slack messages for board events, plus an inbound email address per board. Available on every plan.
Add an integration
- Open Workspace settings and choose Integrations. Owners and admins can add and edit integrations.
- Choose Webhook (any https URL) or Slack (an incoming webhook URL from Slack: Apps, Incoming Webhooks, Add to Slack, pick a channel, copy the URL).
- Give it a name, pick the events it should receive (or all of them) and the boards it applies to (or all of them).
- Save. For a webhook, the signing secret is shown once; copy it into your receiver's configuration.
- Choose Send test event from the row menu. A
pingevent arrives at your URL or channel.
Events
| Event | When it is sent |
|---|---|
item.created | A new item is added to a board, by hand, from a form, by email or through the API. |
item.status_changed | An item moves to another status. data carries from, to and their labels. |
item.priority_changed | An item's priority is set. data carries from and to. |
item.column_changed | A custom column value is edited. data carries column_id, column_name and value. |
item.assigned | Someone is assigned to an item. data carries the assignees. |
item.commented | An update is posted on an item. data carries a short text preview. |
item.due | An item with a due date reaches its due day. Sent by the daily check, once per item and date. |
Webhook delivery
Every event is one POST with a JSON body and these headers. Requests time out after 5 seconds and are not retried. The last 50 attempts per integration, with HTTP status and response time, are under Recent deliveries. After 20 consecutive failures the integration switches itself off; fix the receiver and switch it back on.
| Header | Value |
|---|---|
X-TallyWeek-Event | The event name, for example item.status_changed. |
X-TallyWeek-Delivery | A unique id per delivery. Use it to ignore a payload you have already processed. |
X-TallyWeek-Timestamp | Unix seconds when the request was sent. |
X-TallyWeek-Signature | sha256= followed by the hex HMAC-SHA256 of the raw request body, keyed with the integration's secret. |
Payload
{
"id": "5d4c0f2a-…",
"event": "item.status_changed",
"created_at": "2026-09-29T14:02:11.000Z",
"workspace": { "id": "…", "name": "Acme" },
"board": { "id": "…", "short_id": "b7Kq2", "name": "Bug tracker" },
"item": {
"id": "…",
"name": "Login button unresponsive on Safari",
"status": "in_progress",
"status_label": "In progress",
"priority": "high",
"due_date": "2026-10-02",
"group": { "id": "…", "name": "Triaged" },
"url": "https://tallyweek.com/board/b7Kq2?item=…"
},
"actor": { "id": "…", "name": "Dana" },
"data": { "from": "backlog", "from_label": "Backlog", "to": "in_progress", "to_label": "In progress" }
}item is null for the ping event. group.name can be null when the group could not be loaded. data differs per event as listed above.
Verify the signature in Node
Compute HMAC-SHA256 over the raw request body with your secret, prefix it with sha256= and compare it to the header with a constant-time comparison. Parse the JSON only after the check passes.
import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";
const SECRET = process.env.TALLYWEEK_WEBHOOK_SECRET; // shown once when you saved the webhook
const app = express();
// Keep the raw body: the signature is computed over the exact bytes sent.
app.post("/tallyweek", express.raw({ type: "application/json" }), (req, res) => {
const expected = "sha256=" + createHmac("sha256", SECRET).update(req.body).digest("hex");
const given = String(req.get("X-TallyWeek-Signature") || "");
const ok = expected.length === given.length && timingSafeEqual(Buffer.from(expected), Buffer.from(given));
if (!ok) return res.status(401).end();
const payload = JSON.parse(req.body.toString("utf8"));
console.log(req.get("X-TallyWeek-Event"), payload.item?.name);
res.status(204).end();
});
app.listen(3000);Reject requests whose X-TallyWeek-Timestamp is far from now if you want protection against replays, and ignore repeated X-TallyWeek-Delivery ids.
Slack
Slack integrations post a message per event with the item name, what changed, the board, who did it and an Open item button. Comment events include a short preview of the update. Messages go one way, from TallyWeek to the channel; there is no Slack app to install and no slash commands.
Zapier, Make and n8n
Create a webhook trigger in the tool, paste the URL it gives you into a TallyWeek webhook integration and send a test event to capture the payload shape. To write back into a board from the same workflow, call the REST API with a scoped key (Pro plan).
Email to board
Under Integrations, pick a board and switch on Email to board. The board gets its own address. An email sent to it becomes an item: the subject is the item name, the plain-text body is the first update, and the item lands in the group you choose. Items created this way are attributed to the board's creator and fire item.created like any other new item. Switch the address off to stop accepting mail.
Email to board needs an inbound mail domain configured by the operator of the TallyWeek instance. If the address is not shown in your workspace, it has not been set up there yet.
Related
- Calendar feed: subscribe to your items from a calendar app.
- Automations for rules that act inside the board.
- REST API and MCP server for the inbound direction.
Start a free workspace for your team.
14 days of Pro with no card, then Free for up to 3 members with every view and every automation.