Skip to main content
FlowFn
IntegrationsTemplatesPricingDocsBlogSign inStart free
All documentation

Triggering Workflows via Webhook

UpdatedJun 15, 2026Reading time2 min read

Overview

Add a Webhook trigger in the workflow builder and set a secret. Use the webhook URL (shown in the app or built from your app base URL and path below) in the external service (e.g. Slack, Zapier).

URL pattern

New URL (preferred) — uses a rotatable routing token:

POST app/workflow/hook/:platform/:webhook_token

Full URL: https://hooks.flowfn.com/v1/app/workflow/hook/:platform/:webhook_token. Path parameters:

  • platform (e.g. slack, stripe, github, shopify, twilio, typeform, or other)
  • webhook_token = the rotatable routing token shown in the workflow trigger panel. Click Rotate URL to mint a new one (the old URL stops working immediately; the signing secret is untouched, so subscribers using only the signature header keep verifying as before).

Legacy URL (still supported) — uses your app + workflow + trigger codes:

POST app/workflow/hook/:platform/:app/:workflow/:trigger

Existing webhook subscribers on this URL continue to work. New triggers default to surfacing the token URL.

Webhook secret

Each webhook trigger has a webhook_secret. Signature validation is provider-specific:

  • slack uses x-slack-signature and x-slack-request-timestamp.
  • stripe uses stripe-signature.
  • github uses x-hub-signature-256.
  • gitlab uses x-gitlab-token (secret token).
  • shopify uses x-shopify-hmac-sha256.
  • other uses x-signature with HMAC SHA-256 of the raw body.

The server validates the signature using the trigger's webhook_secret.

Calling from your own backend (platform = other)

For custom integrations, use the other platform — sign the raw body with HMAC SHA-256 (hex digest) and send it in the x-signature header.

curl:

curl -X POST 'https://hooks.flowfn.com/v1/app/workflow/hook/other/<app>/<workflow>/<trigger>' \
  -H 'Content-Type: application/json' \
  -H 'x-signature: <hmac sha256 hex of body>' \
  -d '{"event":"user.created","user":{"id":"u_123"}}'

Node.js (sign + POST):

import crypto from 'node:crypto';

const SECRET = process.env.FLOWFN_WEBHOOK_SECRET;
const url = 'https://hooks.flowfn.com/v1/app/workflow/hook/other/<app>/<workflow>/<trigger>';
const body = JSON.stringify({ event: 'user.created', user: { id: 'u_123' } });

const signature = crypto.createHmac('sha256', SECRET).update(body).digest('hex');

await fetch(url, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-signature': signature },
  body,
});

Python (sign + POST):

import hmac, hashlib, json, os, urllib.request

SECRET = os.environ['FLOWFN_WEBHOOK_SECRET'].encode()
url = 'https://hooks.flowfn.com/v1/app/workflow/hook/other/<app>/<workflow>/<trigger>'
body = json.dumps({'event': 'user.created', 'user': {'id': 'u_123'}}, separators=(',', ':')).encode()

signature = hmac.new(SECRET, body, hashlib.sha256).hexdigest()

req = urllib.request.Request(
    url,
    data=body,
    method='POST',
    headers={'Content-Type': 'application/json', 'x-signature': signature},
)
urllib.request.urlopen(req).read()

Request body

The request body is passed as trigger inputs to the workflow. Paste a representative payload into the trigger drawer's Sample payload editor — FlowFn derives mapping paths from it for downstream tasks.

Responses

  • 200 OK{ "ok": true }. The workflow run is enqueued asynchronously.
  • 400 / 401 / 403 – Invalid signature, unknown app/workflow, or webhook not configured for this trigger.
  • 429 – Per-trigger and per-client rate-limited. Honour Retry-After.

Version behavior

Webhook runtime executions resolve to the published active version for the given app code + workflow code and trigger id.

Spotted an issue or have feedback?

support@flowfn.com
Back to docs hub →