All integrations
n8nintegrations.n8n

Chat & workflow

n8n

Run an n8n workflow on release events, check Stoaken's signature in a Code node, and read the release from the Stoaken API.

  • trigger on release
  • check the signature
  • call the API

Vendor docs

What it does

  • Trigger: a standard Stoaken webhook posts to an n8n Webhook node. The workflow runs on release.pending_approval, release.published and release.rejected (see /docs/webhooks).
  • Check: a Code node verifies the Standard Webhooks signature before anything else runs.
  • Act: later nodes post to a channel or create a task. The HTTP Request node can call the Stoaken REST API with an API key (see /docs/api).

Before you start

  • n8n Cloud (any plan, or the trial) or a self-hosted n8n. Self-hosted must be reachable on the public internet over https: Stoaken never calls private addresses.
  • Behind a reverse proxy, set WEBHOOK_URL (for example https://n8n.example.com/) so n8n shows the right address (docs).
  • Self-hosted only: allow the crypto module in the Code node with NODE_FUNCTION_ALLOW_BUILTIN=crypto (set it on the task runners if you use them). n8n Cloud provides crypto already.
  • Brand Admin in Stoaken, on the Team plan, to add the webhook and copy its signing secret.
  • To call the API: a Stoaken API key from Settings > API keys. It acts as the person who made it, with their roles. Reads work on every plan; writes need a paid plan.

Setup

  1. Add a Webhook node: HTTP Method POST, a Path such as stoaken, Authentication None, Respond Immediately. Under Options, turn on Raw Body.
  2. In Stoaken, go to Settings > Webhooks, choose Add a webhook, set Send as to Stoaken event, paste the node's Test URL and pick the events. Copy the signing secret (shown once).
  3. In n8n, choose Listen for test event, then use Send a sample in Stoaken's webhook lab.
  4. Add a Code node (JavaScript, Run Once for All Items) after the Webhook node:
const crypto = require('crypto')
const SECRET = 'whsec_…' // the webhook's signing secret

const h = $input.first().json.headers
const raw = await this.helpers.getBinaryDataBuffer(0, 'data') // the exact bytes Stoaken sent
const ts = Number(h['webhook-timestamp'])
if (!(Math.abs(Date.now() / 1000 - ts) <= 300)) throw new Error('Stale or missing timestamp')
const key = Buffer.from(SECRET.slice('whsec_'.length), 'base64')
const expected = crypto.createHmac('sha256', key).update(`${h['webhook-id']}.${ts}.`).update(raw).digest()
const ok = (h['webhook-signature'] ?? '').split(' ').some((part) => {
  const [version, sig] = part.split(',')
  const got = Buffer.from(sig ?? '', 'base64')
  return version === 'v1' && got.length === expected.length && crypto.timingSafeEqual(got, expected)
})
if (!ok) throw new Error('Not signed by Stoaken')
return [{ json: JSON.parse(raw.toString('utf8')) }]
  1. Add a Switch node on {{ $json.type }} with one output per event, then your nodes.
  2. Edit the Stoaken webhook's address to the Production URL, then publish the workflow.

To call the API, add an HTTP Request node: Method GET, URL https://www.stoaken.com/api/releases/{{ $json.data.release_id }}, Authentication Generic Credential Type, Bearer Auth, with the stk_… key as the token.

Configuration

Recipes

  • Release published, post to a channel: the release.published output, then Slack Send Message (or Teams, Discord, Mattermost): Tokens v{{ $json.data.version }} are live: {{ $json.data.changes.total }} changes, breaking: {{ $json.data.is_breaking }}.
  • Release published, create a task: an If node on data.is_breaking, then create an issue in Jira, GitHub, Linear or similar: Update to tokens v{{ $json.data.version }}.
  • Release needs review, notify reviewers: the release.pending_approval output, then message the reviewers' channel with https://www.stoaken.com/review/{{ $json.data.release_id }}. Reviewers approve or reject there.
  • Release rejected, tell the author: the release.rejected output, get the release, and send its rejection_reason to the person in created_by.

What the API gives you

  • The event carries ids, the version and change counts, not names. GET /api/themes/{id} and GET /api/brands/{id} return the theme's and Brand's name.
  • GET /api/releases/{id} returns status, created_by, approved_by, rejection_reason and change_summary. Add /changes for every change, mode by mode, or /timeline for who sent, approved or rejected it and when.
  • GET /api/releases/{id}/export?format=css returns the release as a file.
  • Writes need a JSON body and an Idempotency-Key header (Send Headers), for example {{ $json.data.event_id }}-submit. The API can propose a release (POST /api/themes/{id}/releases) and send a draft for review (POST /api/releases/{id}/submit). That's all it can do with releases.

About the signature check

  • Check against the raw body, not the parsed JSON. That's why Raw Body is on and the code reads the binary data property.
  • The Crypto node's HMAC takes its secret as text from a credential. Stoaken's key is the decoded bytes after whsec_, so use the Code node.
  • The Webhook node's own Authentication options (Basic, Header, JWT) need credentials Stoaken doesn't send. Leave it on None and rely on the signature.
  • During Rotate secret, deliveries carry two signatures for 24 hours. The code accepts either one, so paste the new secret any time in that window.

Try it

  1. Send test on the webhook sends a ping. The Code node should pass it, and the Switch should send it nowhere.
  2. Change one character of SECRET and send a sample: the execution should fail with "Not signed by Stoaken". Put it back.
  3. Publish the workflow, send a real release for review, and check Executions.

Troubleshooting

  • Nothing arrives: the Test URL only listens after Listen for test event, and the Production URL only works once the workflow is published. Make sure Stoaken has the one you mean.
  • Self-hosted address refused in Stoaken: it must be https and public. A localhost or private-network address is never called.
  • Cannot find module 'crypto': set NODE_FUNCTION_ALLOW_BUILTIN=crypto and restart n8n (self-hosted).
  • No binary data: Raw Body is off, or the property has another name. Check the Webhook node's output.
  • Every request fails the check: the secret is wrong or was rotated. The n8n server clock must also be within 5 minutes of real time.
  • Webhook switched off in Stoaken: after 5 failed deliveries in a row Stoaken switches it off. Fix n8n, then turn the webhook back on in Settings > Webhooks.
  • 401 from the API: check the Bearer Auth credential holds the whole stk_… key.
  • 400 idempotency-key-required: a write without an Idempotency-Key header. 403 on a write: the key's owner lacks the role, or you're on the Free plan.
  • 429: a key can make 120 requests a minute and 60 writes an hour.

Limits

  • With Respond Immediately, n8n answers 200 before the check runs, so a forged request gets 200 but stops at the Code node.
  • The signing secret sits in the Code node, and anyone who can open the workflow can read it.
  • Nothing in n8n can approve, reject or publish a release. People do that in Stoaken.
  • Deliveries can arrive more than once. webhook-id and data.event_id are the same on every retry, so use them to skip repeats.

Product names and logos are trademarks of their owners, shown only to say Stoaken works with their products; it doesn’t mean they endorse Stoaken.