n8n
Call the API from n8n and receive webhooks with signature checking.
Calling the API
- In n8n, Credentials → New → Header Auth: name
Authorization, valueBearer bym_live_…. - Add an HTTP Request node: method and URL from the reference (for example
POST https://api.bymundi.com/v1/trips), Authentication Generic → Header Auth with that credential, body JSON. - For writes, add a header
Idempotency-Keywith the expression{{ $execution.id }}-{{ $runIndex }}, so an n8n retry never creates a duplicate.
List operations page with a cursor: enable Pagination, mode Update a parameter in each request, parameter cursor in the query = {{ $response.body.nextCursor }}, and stop when {{ $response.body.nextCursor === null }}.
Receiving webhooks
- Add a Webhook trigger node, method
POST, and under Options turn on Raw Body. Copy its production URL. - Create the endpoint with that URL (Webhooks guide) and keep the
whsec_…secret in an n8n credential or variable. - Add a Code node that verifies the signature before anything else. Self-hosted n8n must allow the built-in module:
NODE_FUNCTION_ALLOW_BUILTIN=crypto.
const crypto = require("crypto");
const secret = $env.BYMUNDI_WEBHOOK_SECRET;
const h = $json.headers;
const raw = Buffer.from($binary.data.data, "base64").toString("utf8");
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = crypto.createHmac("sha256", key).update(`${h["webhook-id"]}.${h["webhook-timestamp"]}.${raw}`).digest("base64");
const ok = h["webhook-signature"].split(" ").some((s) => s.split(",")[1] === expected);
if (!ok || Math.abs(Date.now() / 1000 - Number(h["webhook-timestamp"])) > 300) throw new Error("bad signature");
return [{ json: JSON.parse(raw) }];
The Webhook node answers 200 immediately by default, which is what bymundi wants.