# n8n

> The BlueBot community node for n8n, with every resource and operation in the API and a trigger node that starts a workflow when a text arrives. Installing it on n8n Cloud and on your own server.

`n8n-nodes-bluebot` adds two nodes to n8n. The **BlueBot** node calls every operation in the BlueBot API: send a text, schedule one, read texts, check a number, manage webhooks. The **BlueBot Trigger** node starts a workflow when something happens, such as a text coming in, through a webhook BlueBot posts to.

Texts sent from n8n go through your sending rules like every other text and show `source: "n8n"` in BlueBot. Because n8n can run on your own server, a workflow’s logic and the data it reads stay on machines you control; only the texts themselves pass through BlueBot and your Mac. [A self-hosted n8n flow](https://usebluebot.com/docs/guides/n8n-self-hosted) walks through one.

## Install the node

The package is `n8n-nodes-bluebot` on npm. It needs n8n 1.85 or newer.

On your own n8n, as the owner or an admin:

### Open Community Nodes

Go to **Settings → Community Nodes** and press **Install a community node**.

### Install it

Type `n8n-nodes-bluebot`, tick the box that says you understand the risks of community nodes, and press **Install**. n8n downloads it and restarts its node list. Search the nodes panel for “BlueBot” to check.

If your n8n can’t install from the panel (community packages turned off, no network from the container, or a read-only image), install it by hand in n8n’s folder and restart n8n:

```bash title="A manual install"
mkdir -p ~/.n8n/nodes
cd ~/.n8n/nodes
npm install n8n-nodes-bluebot
# then restart n8n
```

In Docker, run the same inside a volume mounted at `/home/node/.n8n`, or build your own image `FROM n8nio/n8n` with the package installed there, so it survives the container being replaced. In queue mode, every worker runs nodes too, so each worker’s image needs the package.

n8n Cloud installs only community nodes that n8n has verified. The BlueBot node follows n8n’s rules for verified nodes; until n8n Cloud lists it, use n8n’s **HTTP Request** node there, as described in [Without the node](#without-the-node).

## Add your credentials

### Make a key

In BlueBot, open **Developers → API keys**, press **New key**, name it “n8n” and tick the scopes your workflows need. The trigger needs `webhooks:manage`, and the credential test needs `account:read`. Copy the key; it is shown once.

### Make the credential

In n8n, open **Credentials**, press **Add credential** and choose **BlueBot API**.

| Field    | Required | What it is                                                                         |
| -------- | -------- | ---------------------------------------------------------------------------------- |
| API Key  | Yes      | Your `bb_live_…` key. n8n stores it encrypted with your instance’s encryption key. |
| Base URL | No       | Leave it as `https://usebluebot.com/api/v1`.                                       |

Press **Save**. n8n tests it with `GET /v1/me` and shows **Connection tested successfully**, or BlueBot’s message (such as “That key isn’t valid. It may have been revoked.”) when it fails.

## The BlueBot node

Pick a **Resource**, then an **Operation**. Each operation is one API call, and every field matches the API’s field of the same name. The node sends one request per input item, so 30 items in means 30 texts, paced by your sending rules.

| Resource         | Operations                                                            | Calls                                    |
| ---------------- | --------------------------------------------------------------------- | ---------------------------------------- |
| Message          | Send Text, Get, Get Many, Update, Cancel, Resolve                     | [Messages](https://usebluebot.com/docs/api#messages)           |
| File             | Upload, Get                                                           | [Files](https://usebluebot.com/docs/api#files)                 |
| Chat             | Get, Get Many                                                         | [Chats](https://usebluebot.com/docs/api#chats)                 |
| Conversation     | Get, Get Many                                                         | [Conversations](https://usebluebot.com/docs/api#conversations) |
| Lookup           | Check iMessage                                                        | [Lookup](https://usebluebot.com/docs/api#lookup)               |
| Device           | Get Mac, Get BlueBot Status                                           | [Device](https://usebluebot.com/docs/api#device)               |
| Account          | Get                                                                   | [Account](https://usebluebot.com/docs/api#account)             |
| Settings         | Get, Update                                                           | [Settings](https://usebluebot.com/docs/api#settings)           |
| Stop             | Add, Get Many, Remove                                                 | [Stops](https://usebluebot.com/docs/api#stops)                 |
| Template         | Get, Get Many                                                         | [Templates](https://usebluebot.com/docs/api#templates)         |
| Event            | Get, Get Many                                                         | [Events](https://usebluebot.com/docs/api#events)               |
| Webhook          | Create, Get, Get Many, Update, Delete, Send Test Event, Rotate Secret | [Webhooks](https://usebluebot.com/docs/api#webhooks)           |
| Webhook Delivery | Get Many, Replay                                                      | [Webhooks](https://usebluebot.com/docs/api#webhooks)           |

### Message: Send Text

| Field         | Type                        | Required                                    | What it is                                                                                                     |
| ------------- | --------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Send To       | Options: Person, Group Chat | Yes                                         | Who gets it. Default: Person.                                                                                  |
| To            | String                      | For Person                                  | A mobile number in any format (US numbers can leave off +1), or an email address the person uses for iMessage. |
| Group Chat ID | String                      | For Group Chat                              | A `chat_` id from Chat → Get Many. BlueBot can’t start a new group.                                            |
| Text          | String                      | Unless files are added or a template is set | Up to 2,000 characters. Use expressions such as `{{ $json.first_name }}`.                                      |

Under **Add Field**:

| Field              | Type                                 | What it is                                                                                                                                                                                                                                                                                                |
| ------------------ | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Files              | Options: File IDs, Binary Properties | **File IDs** takes `file_` ids from File → Upload. **Binary Properties** names binary properties on the item (such as `data`), which the node uploads first. Up to 10, each up to 25 MB.                                                                                                                  |
| Service            | Options: Auto, iMessage, SMS         | Auto (the default) uses what the newest chat with the person used, else iMessage, and resends an iMessage that never went once as SMS. SMS needs your iPhone with Text Message Forwarding.                                                                                                                |
| Send At            | Date and time                        | Schedules the text. It waits as `scheduled` and can be changed or canceled until then.                                                                                                                                                                                                                    |
| Expires At         | Date and time                        | Give up if it’s still waiting then. Default: 24 hours after it’s due.                                                                                                                                                                                                                                     |
| Metadata           | Key and value pairs                  | Up to 20 keys of up to 40 characters, values up to 500. Echoed on every webhook about the text.                                                                                                                                                                                                           |
| Template ID        | String                               | Send one of your templates instead of words, by its `tpl_` id from Template → Get Many. Leave Text empty.                                                                                                                                                                                                 |
| Template Variables | Name and value pairs                 | A value for each `{{name}}` in the template. A variable you leave out comes from the contact (`first_name`, `last_name`, `company` and custom fields) or your business name (`business`), else from the template’s own fallback. One with none of those stops the send with `invalid_request`, naming it. |
| Idempotency Key    | String                               | Defaults to one made from the execution, the node and the item’s index, so **Retry On Fail** never sends a text twice. Set your own to make a send safe across executions, such as the record’s id.                                                                                                       |

The output item is the message, usually `state: "queued"`. A text that can’t go yet (quiet hours, your Mac offline, a daily limit) still succeeds, with `hold.reason` and `hold.until`. A text to somebody on your stop list comes back `state: "canceled"` with `cancel_reason: "opted_out"`.

### Message: Get Many

| Field      | Type       | What it is                                                                                      |
| ---------- | ---------- | ----------------------------------------------------------------------------------------------- |
| Return All | Boolean    | Follow the cursor to the end. Off by default.                                                   |
| Limit      | Number     | How many to return when Return All is off. Default 50.                                          |
| Filters    | Collection | Direction (In, Out), State, Person, Contact ID, Chat ID, Source, Created After, Created Before. |

Each text is one output item, newest first.

### Message: Update, Cancel and Resolve

**Update** changes a scheduled text before it’s due: Text, Send At, Expires At and Metadata (which replaces the metadata whole). **Cancel** takes a Message ID and cancels a scheduled or queued text; one the Mac already took fails with `conflict`. **Resolve** settles an `unconfirmed` text with Action **Mark Sent** (the person got it) or **Send Again** (a new text with the same words).

### File: Upload and Get

**Upload** takes a binary property (default `data`) and an optional Name, and outputs the file with its `file_` id. **Get** takes a File ID and outputs the file; turn on **Download** to put its bytes in a binary property as well, which is how you save a picture or voice memo someone sent you. A file’s `url` works for an hour.

### Lookup: Check iMessage

Takes a Number (a phone number or email address) and outputs `service` (`imessage`, `sms` or `unknown`), `basis` and `last_seen_at`. It reads your own Messages history through your Mac and waits up to 15 seconds. A number you’ve never texted is `unknown`, because Apple gives no way to ask.

### Webhook operations

**Create** takes a URL (public `https`) and Events, and outputs the webhook with its signing `secret`, the one time the API shows it. **Send Test Event** sends an example of the type you pick to that webhook. **Rotate Secret** makes a new secret; the old one signs beside it for 24 hours. **Webhook Delivery → Replay** sends one delivery again. You rarely need these with the trigger node, which manages its own webhook.

### When a call fails

The node shows BlueBot’s message as the error, its hint as the description, and the code, HTTP status and request id in the details, such as “Send `to` or `chat_id`.” with “Check the fields named in the message and send it again.” Quote the request id if you write to support.

- Turn on **Retry On Fail** in the node’s settings for `rate_limited` (429) and the 5xx errors. The node waits at least the `retry_after` BlueBot asks for, and its default idempotency key keeps a retried send from going twice.
- Turn on **Continue On Fail** to let the other items go on when one has a bad number. The failed item’s output carries the error.
- A held text is not an error, and neither is a text that fails after it was accepted. Catch those with the trigger node on **Message Failed**, **Message Expired** and **Message Unconfirmed**.

## The BlueBot Trigger node

Starts a workflow when BlueBot posts an event. It makes its own webhook in your BlueBot account when the workflow is activated, pointing at n8n’s production webhook URL, and deletes it when the workflow is deactivated.

| Field      | Type                         | Required | What it is                                                                                                                                                |
| ---------- | ---------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Credential | BlueBot API                  | Yes      | Needs `webhooks:manage`.                                                                                                                                  |
| Events     | Multi-options                | Yes      | Any of the [event types](https://usebluebot.com/docs/webhooks/events), such as **Message Received**, **Message Failed** or **Contact Stopped**. Default: Message Received.      |
| Output     | Options: Record, Whole Event | No       | **Record** (the default) outputs `data`: the message, contact or enrollment. **Whole Event** adds the envelope: `id`, `type`, `api_version`, `timestamp`. |

The node keeps the webhook’s signing secret in the workflow and checks `webhook-signature` on every request. A request without a valid signature, or more than five minutes old, is answered 401 and never starts the workflow, so nobody who learns the URL can fake a text.

To try it, press **Listen for test event**. The node makes a webhook to n8n’s test URL for as long as it listens. Then text your BlueBot number from another phone, one you’ve texted through BlueBot before (BlueBot copies only those chats unless **Which chats to copy** is set to **Everything**). The event shows in the node’s output.

| You got                                                        | It means                                                       | Do next                                                            |
| -------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------ |
| The event in the output                                        | It works.                                                      | Build the rest of the workflow, then activate it.                  |
| “BlueBot couldn’t reach this URL” when listening or activating | n8n’s webhook URL isn’t public `https`, so BlueBot refused it. | Set `WEBHOOK_URL` as in [On your own server](#on-your-own-server). |
| Still listening after your text                                | No event came.                                                 | Check that your Mac is online and the chat is one BlueBot copies.  |

## On your own server

BlueBot only posts to public `https` addresses on the default port, and doesn’t follow redirects. A self-hosted n8n behind a reverse proxy must tell its nodes the public address, or the trigger node registers `http://localhost:5678/…`, which BlueBot refuses.

```bash title=".env for n8n behind a proxy"
WEBHOOK_URL=https://n8n.example.com/
N8N_PROXY_HOPS=1
```

- Put n8n behind a proxy that ends TLS (Caddy, nginx, Traefik) with a real certificate. A self-signed certificate fails BlueBot’s check.
- For a laptop with no public address, run a tunnel such as `cloudflared tunnel --url http://localhost:5678` and set `WEBHOOK_URL` to the address it prints. Restart n8n after changing it.
- Deactivate and activate a workflow after the address changes, so the trigger node makes a new webhook at the new address.
- Keep n8n’s encryption key (`N8N_ENCRYPTION_KEY`) when you move servers, or the BlueBot credential can’t be read.

## Without the node

Any n8n, n8n Cloud included, can call the API with the **HTTP Request** node.

### Make a header credential

Make a **Header Auth** credential with Name `Authorization` and Value `Bearer bb_live_…`.

### Send a text

Add an **HTTP Request** node: Method `POST`, URL `https://usebluebot.com/api/v1/messages`, Authentication **Generic Credential Type → Header Auth** with that credential. Under **Send Headers**, add `BlueBot-Client: n8n` and an `Idempotency-Key`, such as `{{ $execution.id }}-{{ $itemIndex }}`. Under **Send Body**, choose JSON and send `to` and `text`.

To receive events without the trigger node, use n8n’s **Webhook** node and make the webhook yourself with `POST /v1/webhooks`. Check each request’s signature in a **Code** node before trusting it, as [Verify signatures](https://usebluebot.com/docs/webhooks/verify) shows.
