> ## Documentation Index
> Fetch the complete documentation index at: https://staging.docs.flowsign.app/llms.txt
> Use this file to discover all available pages before exploring further.

# n8n

> Trigger n8n workflows from FlowSign events and create or send packages from a workflow.

You can automate FlowSign with n8n using its own **Webhook** and **HTTP Request** nodes: trigger a workflow when a package completes, or create and send a package from another system through a workflow.

## Receiving events

Create a webhook endpoint in FlowSign at **Settings > Webhooks** ([my.flowsign.app/settings/webhooks](https://my.flowsign.app/settings/webhooks)), or with the API (see [Webhooks](/webhooks/overview)).

1. Add a **Webhook** node, set it to accept `POST`, and activate the workflow so it gets a production URL.
2. Paste that URL into the endpoint's **URL** field in FlowSign.
3. Tick the events to subscribe to (for example **Package Completed**) and save. FlowSign shows the endpoint's signing secret once; store it.

Every delivery is a `POST` with three headers and a JSON body:

| Header                   | Value                                                                   |
| ------------------------ | ----------------------------------------------------------------------- |
| `X-FlowSign-Event`       | The event name, for example `PACKAGE_COMPLETED`                         |
| `X-FlowSign-Delivery-Id` | A stable id for this delivery; retries reuse it                         |
| `X-FlowSign-Signature`   | Hex-encoded HMAC-SHA256 of the raw body, keyed with the endpoint secret |

```json theme={null}
{
  "event": "PACKAGE_COMPLETED",
  "timestamp": "2026-09-17T03:40:11.000Z",
  "data": {
    "packageId": "pkg_9f3c2e",
    "packageTitle": "Employment agreement: Ana Reid",
    "completedAt": "2026-09-17T03:40:10.884Z"
  }
}
```

`data` differs per event. See [Events](/webhooks/events) for every event's shape.

## Verifying the signature

<Warning>
  Skipping verification means your workflow acts on any unauthenticated `POST` to its webhook URL, not just genuine FlowSign deliveries.
</Warning>

Compute a hex HMAC-SHA256 of the raw body with the endpoint secret and compare it to `X-FlowSign-Signature`. n8n parses the body into JSON by default, and re-serialising it back to a string isn't guaranteed to match the exact bytes FlowSign signed. In the **Webhook** node's options, turn on **Raw Body** so the unparsed body is available at `$json.rawBody` on the production URL.

Add a **Crypto** node next, with **Action** set to **Hmac**, **Type** set to **SHA256**, **Value** set to `{{ $json.rawBody }}`, **Encoding** set to **hex**, and the secret in its **Crypto** credential. Follow it with an **IF** node comparing the Crypto node's output to `{{ $json.headers["x-flowsign-signature"] }}`, and stop the workflow on the false branch.

To do the same in a **Code** node instead:

```javascript theme={null}
const crypto = require("crypto");

const expected = crypto
  .createHmac("sha256", $env.FLOWSIGN_WEBHOOK_SECRET)
  .update($json.rawBody)
  .digest("hex");

return [{ json: { valid: expected === $json.headers["x-flowsign-signature"] } }];
```

## Calling the API

Use the **HTTP Request** node for any FlowSign API call.

Base URL: `https://my.flowsign.app`. Every request needs:

| Header           | Value                                                                                |
| ---------------- | ------------------------------------------------------------------------------------ |
| `Authorization`  | `Bearer fsk_your_key_here`                                                           |
| `X-Workspace-Id` | Optional; the workspace to act in. Omit to use the organisation's default workspace. |

Create the key at **Settings > API keys**; see [Authentication](/api-reference/authentication). Store it in an n8n credential (Header Auth, with `Authorization` as the header name and `Bearer fsk_your_key_here` as the value) rather than pasting it into the node.

### List packages

Method **GET**, URL `https://my.flowsign.app/api/v1/packages?status=IN_PROGRESS`.

```json theme={null}
{
  "data": {
    "packages": [
      {
        "id": "pkg_9f3c2e",
        "title": "Employment agreement: Ana Reid",
        "status": "IN_PROGRESS",
        "description": null,
        "recipients": [
          { "name": "Ana Reid", "email": "ana@example.com", "action": "Sign", "actionType": "SIGNER", "signed": false }
        ],
        "documentsCount": 1,
        "signingProgress": { "completed": 0, "total": 1 },
        "createdAt": "2026-09-17T01:12:44.000Z",
        "updatedAt": "2026-09-17T01:12:50.000Z",
        "expiresAt": null,
        "completedAt": null
      }
    ],
    "totalCount": 1,
    "page": 1,
    "pageSize": 25
  }
}
```

### Create a package from a template

Method **POST**, URL `https://my.flowsign.app/api/v1/packages/from-template`, body type JSON:

```json theme={null}
{
  "templateId": "tmpl_abc123",
  "recipients": [
    { "role": "Employee", "name": "Ana Reid", "email": "ana@example.com" },
    { "role": "Manager", "name": "Ben Toa", "email": "ben@example.com" }
  ],
  "fields": { "start_date": "1 October 2026" },
  "externalId": "order_4471",
  "status": "sent"
}
```

`role` must match one of the template's role names and `fields` keys must match its merge field keys; a mismatch returns `422` with the unknown or missing names in `details`. `status` is `"draft"` (default) or `"sent"`, which sends immediately. `externalId` is optional and makes the call idempotent: retrying with the same value returns the existing package instead of creating a duplicate.

```json theme={null}
{ "data": { "packageId": "pkg_9f3c2e", "externalId": "order_4471", "status": "IN_PROGRESS" } }
```

Creating requires the key's user to have the send permission; see [Errors](/api-reference/errors) for the full status code list.

## Plan and cost notes

The **Webhook**, **HTTP Request** and **Crypto** nodes are core n8n nodes with no premium gate, on n8n Cloud or self-hosted.
