Learn · Automation

Drive a kanban board from n8n with two nodes.

You can drive a Novum OS board from n8n today with built-in nodes only: a Webhook trigger that receives the board’s signed events — with the changed fields already in the payload — and HTTP Request nodes that write back through the REST API with a bearer token. No community node, no polling, no per-call anxiety.

What you'll build

The canonical flow: a teammate drags a card into Drafting → the board POSTs a signed card.moved event to n8n → your workflow verifies the signature, runs whatever logic you like (call an LLM, hit your CMS, enrich from a database), writes results back onto the card, and moves it to Review. The person watching the board sees the card update live.

Step 1 — mint a token

In your workspace: Settings → Agents → Connect an agent (so the workflow’s writes attribute to a named agent — the first agent is free on every plan), or Settings → Integrations for a personal token. Either way you get a nov_ bearer token, shown once. Agent seat vs personal token, explained.

Step 2 — add a Webhook trigger node in n8n

Create a workflow, add the Webhook node as the trigger, set the method to POST, and copy its production URL (the test URL only listens while you are in the editor). In the node’s options, enable Raw Body — HMAC verification needs the exact bytes, and re-serialized JSON won’t match.

Step 3 — subscribe the board to that URL

terminal
curl -X POST https://novumos.app/v1/webhooks \
  -H "Authorization: Bearer nov_YOUR_TOKEN" \
  -H "X-Board-Version: 2026-06-19" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-n8n.example.com/webhook/novum-board",
    "events": ["card.moved", "card.created"],
    "filters": { "board_id": "YOUR_BOARD_ID" }
  }'
# Response includes "secret" — shown ONCE. Store it for Step 3.

Subscriptions are per-event-type and filterable, so subscribe to exactly what the workflow handles. The response contains the signing secret once; deliveries retry with exponential backoff on failure and dead-letter after five attempts, with a replay endpoint that preserves event_id.

Step 4 — verify the signature in a Code node

n8n has no per-app signature verification, so it’s a small DIY step over the raw body (that’s why Raw Body matters — recomputing the HMAC over re-serialized JSON will never match):

n8n Code node
// n8n Code node — verify X-Novum-Signature.
// (Enable the Webhook node's "Raw Body" option so the exact bytes survive.)
const crypto = require('crypto');

const secret = 'YOUR_WEBHOOK_SECRET';
const headers = $input.first().json.headers;
const rawBody = $input.first().json.body; // raw string with Raw Body on

const sig = headers['x-novum-signature'];          // "t=<unix>,v1=<hex>"
const t = sig.match(/t=(\d+)/)[1];
const v1 = sig.match(/v1=([0-9a-f]+)/)[1];

if (Math.abs(Date.now() / 1000 - Number(t)) > 300)
  throw new Error('signature outside 5-minute replay window');

const expected = crypto
  .createHmac('sha256', secret)
  .update(`${t}.${rawBody}`)
  .digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1)))
  throw new Error('bad signature');

return [{ json: JSON.parse(rawBody) }];

Prefer no-code? n8n’s built-in Crypto node can compute the same SHA-256 HMAC over the <t>.<raw body> framing string, followed by an IF node comparing it to the v1 value.

Step 5 — act on the payload (it already has the data)

The event body carries the change inline, so the usual “webhook fires → fetch the object → diff it yourself” round-trip disappears:

card.moved payload
{
  "object": "event",
  "event_id": "1d4f3c2a-…",          // dedupe key — deliveries are at-least-once
  "event_type": "card.moved",
  "delivered_at": "2026-07-03T16:00:01Z",
  "entity": { "type": "page", "id": "0192a4b2-…" },
  "data": {
    "card_id": "0192a4b2-…",
    "board_id": "…",
    "from_column_id": "…",
    "to_column_id": "…"                // the change, inline — no follow-up GET
  }
}

Branch on event_type with an IF or Switch node, and dedupe on event_id (delivery is at-least-once).

Step 6 — write back over REST

Any HTTP Request node with two headers can do anything the UI can do:

HTTP Request nodes
// HTTP Request node 1 — update the card's fields
PATCH https://novumos.app/v1/cards/{{ $json.data.card_id }}
  Authorization: Bearer nov_YOUR_TOKEN
  X-Board-Version: 2026-06-19
  Body: { "properties": { "Draft status": "ready" } }

// HTTP Request node 2 — move it to the next column
POST https://novumos.app/v1/cards/{{ $json.data.card_id }}:move
  Authorization: Bearer nov_YOUR_TOKEN
  X-Board-Version: 2026-06-19
  Body: { "column_id": "REVIEW_COLUMN_ID" }

The same surface covers creating cards (POST /v1/cards), appending body content (PATCH /v1/blocks/{id}/children), and commenting (POST /v1/comments) — the interactive reference lives at novumos.app/docs.

Why teams move this workflow here

Most n8n board automations start against a tool that rate-limits integrations to a crawl — if your workflow is queueing behind Notion’s 3 requests per second or re-fetching objects because the webhook payload was empty, the fix is structural, not clever retry code. Novum OS sends the changed fields in the event, accepts write-backs at standard integration rate limits sized for pipelines, and if your workflow graduates from “react to events” to “work through a backlog,” the board itself is a durable work queue with claim/heartbeat/complete semantics.

Quick answers

Is there a native Novum OS node for n8n?

Not yet, as of July 2026 — this guide is the generic path, and it needs nothing beyond two built-in n8n nodes: the Webhook trigger (to receive the board’s signed events) and the HTTP Request node (to write back through the REST API with a bearer token). It works the same on n8n Cloud and self-hosted n8n, today.

How do I avoid processing the same event twice?

Deliveries are at-least-once by design, and every payload carries an event_id that stays stable across retries and replays. Dedupe on it — a static-data check in a Code node or a row in your datastore keyed by event_id is enough.

Can n8n verify the webhook signature?

Yes. Enable the Webhook node’s Raw Body option and recompute the HMAC in a Code node: the X-Novum-Signature header is t=<unix>,v1=<hex>, where v1 is HMAC-SHA256(secret, "<t>.<raw body>"). Reject anything outside a 5-minute window. A Notion-style x-notion-signature header (HMAC of the raw body alone) ships on every delivery too, so existing verifier code also works.

What events can n8n subscribe to?

Card lifecycle (card.created, card.updated, card.moved, card.archived, card.deleted), assignment changes (card.assigned, card.unassigned), blocks, comments, columns, boards, agent governance events, and the work-queue lease events (card.lease.claimed, completed, failed, expired, deadlettered). Subscriptions can filter by board and event type so your workflow only wakes for what it handles.

Point a workflow at a real board — free tier, no card, webhooks included.

Create account