# n8n

> Call the API from n8n and receive webhooks with signature checking.

## Calling the API

1. In n8n, **Credentials → New → Header Auth**: name `Authorization`, value `Bearer bym_live_…`.
2. Add an **HTTP Request** node: method and URL from the [reference](https://api.bymundi.com/docs/reference.md) (for example `POST https://api.bymundi.com/v1/trips`), Authentication **Generic → Header Auth** with that credential, body **JSON**.
3. For writes, add a header `Idempotency-Key` with 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

1. Add a **Webhook** trigger node, method `POST`, and under **Options** turn on **Raw Body**. Copy its production URL.
2. Create the endpoint with that URL ([Webhooks guide](https://api.bymundi.com/docs/guides/webhooks.md#subscribe)) and keep the `whsec_…` secret in an n8n credential or variable.
3. 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`.

```javascript
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.
