All docs
2 min read

n8n recipe

n8n is the self-hostable alternative when you want Zapier-style flows without per-task pricing or a third party seeing your data. Cloud version exists too if you don't want to run it yourself.

Setup

1. Add a Webhook node

In your n8n workflow: Add node → Webhook.

  • HTTP Method: POST
  • Path: something unique like formspring-contact
  • Response Mode: Immediately (respond 200 fast; do work after)
  • Authentication: None (we'll do HMAC ourselves)

Save and execute the workflow once to get the test URL. For production, copy the production URL.

2. Verify the signature

Drop a Code node right after the Webhook node:

const crypto = require('crypto');

const sig = $input.first().json.headers['x-formspring-signature'];
const raw = $input.first().json.body;          // raw body string
const secret = $env.FORMSPRING_SECRET;

const expected = crypto.createHmac('sha256', secret).update(raw).digest('hex');

if (
  sig.length !== expected.length ||
  !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
) {
  throw new Error('Invalid signature');
}

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

For this to work, set the Webhook node's Raw Body option to true so body is the unparsed string. Without that, the JSON gets re-serialized and the HMAC won't match.

Store FORMSPRING_SECRET in n8n's environment (n8n cloud: workflow variables; self-hosted: .env).

3. Wire it up in Formspring

Webhooks → Add webhook → Generic. Paste the n8n production URL.

4. Build downstream steps

Common patterns:

  • HTTP Request → forward to your API with auth.
  • Set + Postgres/MySQL → insert into your DB directly.
  • IF → branch on body.type (created vs flagged) or on body.payload.email domain.
  • Email → send a templated reply via SMTP/SendGrid/Postmark.
  • AI → run the message through an LLM for classification, then route.

Self-hosted vs cloud

Self-hosted n8n cloud
Per-execution cost Free (your infra) Metered
Data residency Yours n8n's
Setup effort Docker + reverse proxy Sign up
Best for Sensitive data, high volume Quick start, low ops

For Formspring-style payloads on a moderately busy form, self-hosted on a small VM (1 vCPU, 2 GB RAM) handles thousands of submissions per day comfortably.

Idempotency

The Webhook node fires once per HTTP request. If a Formspring retry hits, you'll see the same submission_id again. Add an IF node early that queries your dedupe table (or a Redis SET NX) on body.submission_id and short-circuits if already processed.

What's next