# Make

> BlueBot’s Make app sends texts from your own number and starts scenarios when a text comes in, a text changes state or somebody texts STOP. Every module, its fields and what it outputs.

The BlueBot app for Make (once called Integromat) puts your number into any scenario. It has five instant triggers, eight actions, four searches and **Make an API Call** for everything else.

The triggers are webhooks: BlueBot posts each event to Make as it happens, so a scenario starts within a second or two and uses no operations on polling. Texts sent from Make go through your sending rules like every other text (pacing, quiet hours, the daily limits, the stop list) and show `source: "make"` in BlueBot.

## Connect your account

### Make a key

In BlueBot, open **Developers → API keys** and press **New key**. Name it “Make” and tick every scope. The watch modules need `webhooks:manage` to attach their webhooks, the contact modules need `contacts:read` and `contacts:write`, and the connection check needs `account:read`. Copy the key; it is shown once.

### Add the connection in Make

Add any BlueBot module to a scenario. Next to **Connection**, press **Add**, give the connection a name, paste the key into **API Key** and press **Save**. Make checks it with `GET /v1/me`.

### Check it

| You got                                 | It means                                   | Do next                                                                                   |
| --------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------- |
| The connection saved and selected       | The key works.                             | Fill in the module.                                                                       |
| “That API key isn’t valid”              | The key is mistyped, revoked or cut short. | Paste it again or make a new key. [unauthorized](https://usebluebot.com/docs/errors/unauthorized)               |
| “This key needs the account:read scope” | The key is missing a scope.                | Make a key with every scope ticked. [insufficient_scope](https://usebluebot.com/docs/errors/insufficient_scope) |

To change keys later, open **Connections** in Make, find the BlueBot connection and press **Reauthorize**. Every module and webhook that uses the connection follows it.

## Instant triggers

Each watch module uses a Make webhook. When you add the module, press **Create a webhook**, name it and press **Save**. Make then makes a webhook in your BlueBot account that points at it, subscribed to the events the module needs, and shows it under **Developers → Webhooks** in BlueBot described as “Make: ” and the webhook’s name. Deleting the webhook in Make deletes it in BlueBot too. A module’s settings (such as the states to watch) are fixed when the webhook is made; to change them, make a new webhook.

When the scenario is off, Make keeps what arrives in the webhook’s queue and works through it when you turn the scenario back on. BlueBot also retries a delivery Make doesn’t accept for about three days, with each event’s id the same on every try.

Each bundle is the record as the API returns it (a message, a contact or an enrollment), plus `event_id`, `event_type` and `event_timestamp`. A text’s files are an array; put an **Iterator** after the trigger to handle each picture on its own.

### Watch Incoming Texts

Starts when somebody texts your number. BlueBot sends it `message.received`.

| Field               | Type    | Required | Help                                                |
| ------------------- | ------- | -------- | --------------------------------------------------- |
| Webhook             | Webhook | Yes      | Create one here.                                    |
| Include group chats | Boolean | No       | Also start for texts in group chats. Default: yes.  |
| Only from           | Text    | No       | Only texts from this phone number or email address. |

BlueBot copies the texts of people you’ve texted through it, unless you set **Which chats to copy** to **Everything** in **Settings → Sending rules**.

### Watch Text Status Changes

Starts when a text you sent changes state.

| Field                  | Type                                                                           | Required | Help                                                                         |
| ---------------------- | ------------------------------------------------------------------------------ | -------- | ---------------------------------------------------------------------------- |
| Webhook                | Webhook                                                                        | Yes      |                                                                              |
| States                 | Select, several: Sent, Delivered, Read, Failed, Unconfirmed, Expired, Canceled | Yes      | The changes to watch. BlueBot subscribes to the matching `message.*` events. |
| Only with metadata key | Text                                                                           | No       | Only texts whose metadata has this key, such as `record_id`.                 |

The bundle is the message after the change, with `state`, `failure` and `metadata`. Delivered and read come only from iMessage, and read only from people who share read receipts.

### Watch New Contacts

Starts when a person is added to your contacts, however they were added. BlueBot sends it `contact.created`. Its only field is the webhook.

### Watch Contact Stops

Starts when somebody goes on your stop list. Their queued texts are already canceled. BlueBot sends it `contact.stopped`.

| Field        | Type    | Required | Help                                                        |
| ------------ | ------- | -------- | ----------------------------------------------------------- |
| Webhook      | Webhook | Yes      |                                                             |
| Only replies | Boolean | No       | Only people who texted a stop word themselves. Default: no. |

### Watch Completed Sequences

Starts when a person reaches the end of a sequence or leaves it early. BlueBot sends it `sequence.completed`.

| Field    | Type                                | Required | Help                        |
| -------- | ----------------------------------- | -------- | --------------------------- |
| Webhook  | Webhook                             | Yes      |                             |
| Sequence | Select from your sequences          | No       | Empty means every sequence. |
| Outcome  | Select: Any, Completed, Ended early | No       | Default: Any.               |

The bundle is the enrollment (`id`, `sequence_id`, `contact_id`, `state`, `stop_reason`, `completed_at`) with `contact_handle`, `contact_first_name` and `contact_last_name`.

## Actions

Every action that sends a text carries an `Idempotency-Key` unique to that run of that module. If Make runs the module again in the same execution (a **Break** error handler retrying it, say), BlueBot answers with the text it already accepted instead of sending a second one.

### Send Text

Sends a text from your number now, or as soon as your sending rules allow. The output bundle is the message, usually `state: "queued"`.

| Field      | Type                                | Required                      | Help                                                                                                                                                                                                                  |
| ---------- | ----------------------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| To         | Text                                | Yes, unless Group chat is set | A mobile number in any format (US numbers can leave off +1), or an email address the person uses for iMessage.                                                                                                        |
| Group chat | Select from your group chats        | No                            | Text an existing group chat instead. Leave To empty.                                                                                                                                                                  |
| Text       | Text                                | Yes, unless Files has an item | Up to 2,000 characters.                                                                                                                                                                                               |
| Files      | Array of files (file name and data) | No                            | Up to 10, each up to 25 MB: pictures, video, audio, PDFs, contact cards (.vcf). Map the output of an HTTP **Get a file** module or any module that returns a file.                                                    |
| Service    | Select: Auto, iMessage, SMS         | No                            | Auto (the default) uses what the newest chat with the person used, else iMessage, and resends an iMessage that never went once as SMS. iMessage never falls back. SMS needs your iPhone with Text Message Forwarding. |
| Give up at | Date                                | No                            | If it’s still waiting then, it expires. Default: 24 hours after it’s due.                                                                                                                                             |
| Metadata   | Array of key and value              | No                            | Up to 20 keys of up to 40 characters, values up to 500. Sent back on every status change, so put the record’s id here.                                                                                                |

A held text (quiet hours, your Mac offline, a daily limit) still succeeds, with `hold.reason` and `hold.until` in the bundle. A text to somebody on your stop list succeeds with `state: "canceled"` and `cancel_reason: "opted_out"`; add a filter on **State** if later modules should only run for texts that will go.

### Send Template

| Field     | Type                       | Required | Help                                                                                                                                                                                                                                                                                                                                            |
| --------- | -------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| To        | Text                       | Yes      | As on Send Text.                                                                                                                                                                                                                                                                                                                                |
| Template  | Select from your templates | Yes      |                                                                                                                                                                                                                                                                                                                                                 |
| Variables | Array of key and value     | No       | A value for each `{{name}}` in the template, keyed by the name without braces. A variable you leave out comes from the contact when BlueBot knows it (`first_name`, `last_name`, `company` and custom fields) or from your business name (`business`), else from the template’s own fallback. One with none of those stops the send, naming it. |
| Service   | Select                     | No       | As on Send Text.                                                                                                                                                                                                                                                                                                                                |
| Metadata  | Array of key and value     | No       | As on Send Text.                                                                                                                                                                                                                                                                                                                                |

The bundle is the message, with the template’s words filled in as `text`. A variable with no value and no fallback fails the module with `invalid_request` and the variable’s name, and nothing is sent.

### Schedule Text

The fields of Send Text plus **Send at** (Date, required). The text waits as `scheduled` until then, then goes through your sending rules, so one due inside quiet hours goes in the morning. Files are uploaded when the module runs, and an unsent file is deleted after a day, so schedule texts with files at most a day ahead. Keep the output’s `id` to cancel it later.

### Cancel Scheduled Text

| Field      | Type | Required | Help                                         |
| ---------- | ---- | -------- | -------------------------------------------- |
| Message ID | Text | Yes      | The `msg_` id of a scheduled or queued text. |

The bundle is the message with `state: "canceled"`. A text the Mac already took can’t be called back, and the module fails with `conflict`.

### Create or Update Contact

| Field          | Type                   | Required | Help                                                |
| -------------- | ---------------------- | -------- | --------------------------------------------------- |
| Phone or email | Text                   | Yes      | Finds the person by it, or adds them.               |
| First name     | Text                   | No       |                                                     |
| Last name      | Text                   | No       |                                                     |
| Company        | Text                   | No       |                                                     |
| Tags           | Array of text          | No       | Added to the tags they have.                        |
| Custom fields  | Array of key and value | No       | Each key you send replaces that field; others stay. |

An empty field doesn’t clear what BlueBot has. The bundle is the contact, with `created: true` when they were new.

### Add Tag

| Field          | Type          | Required | Help                            |
| -------------- | ------------- | -------- | ------------------------------- |
| Phone or email | Text          | Yes      | Added as a contact if new.      |
| Tags           | Array of text | Yes      | Matched without regard to case. |

### Enroll in Sequence

| Field          | Type                       | Required | Help                                       |
| -------------- | -------------------------- | -------- | ------------------------------------------ |
| Phone or email | Text                       | Yes      | Added as a contact if new.                 |
| Sequence       | Select from your sequences | Yes      |                                            |
| Variables      | Array of key and value     | No       | Values for the sequence’s templates.       |
| Metadata       | Array of key and value     | No       | Put on every text the sequence sends them. |

Somebody already in the sequence, or on your stop list, isn’t started, and the module fails with `conflict`. Add an **Ignore** error handler to the module if the scenario should carry on.

### Remove from Sequence

| Field          | Type                       | Required | Help        |
| -------------- | -------------------------- | -------- | ----------- |
| Phone or email | Text                       | Yes      | Any format. |
| Sequence       | Select from your sequences | Yes      |             |

Their texts from it that haven’t gone are canceled. The bundle’s `enrollments` lists the enrollment that ended, or nothing when they weren’t in the sequence, which isn’t an error. To take somebody off every sequence, add a module for each one.

## Searches

### Search Messages

Lists texts, newest first, one bundle each. It calls `GET /v1/messages` and follows the cursor for you.

| Field          | Type                                                                                                        | Required | Help                                                 |
| -------------- | ----------------------------------------------------------------------------------------------------------- | -------- | ---------------------------------------------------- |
| Direction      | Select: In, Out                                                                                             | No       |                                                      |
| State          | Select: Scheduled, Queued, Sending, Sent, Delivered, Read, Failed, Unconfirmed, Expired, Canceled, Received | No       |                                                      |
| Person         | Text                                                                                                        | No       | Only texts with this number or email address.        |
| Group chat     | Select from your group chats                                                                                | No       |                                                      |
| Source         | Select                                                                                                      | No       | Such as API, Make, Zapier, Mac (typed by hand).      |
| Created from   | Date                                                                                                        | No       |                                                      |
| Created before | Date                                                                                                        | No       |                                                      |
| Limit          | Number                                                                                                      | No       | The most bundles to return. Default 10, up to 1,000. |

### Find Contact

| Field          | Type | Required | Help        |
| -------------- | ---- | -------- | ----------- |
| Phone or email | Text | Yes      | Any format. |

Returns one bundle for the contact, or none. Add a router with **Create or Update Contact** on the empty path to add people you don’t have.

### Find Conversation

| Field          | Type | Required | Help        |
| -------------- | ---- | -------- | ----------- |
| Phone or email | Text | Yes      | Any format. |

Returns one bundle, or none when you’ve never texted them: `conversation_id`, `contact_id`, `last_message_id`, `last_message_text`, `last_message_direction`, `last_message_state`, `last_message_at` and `waiting_on_you` (true when the newest text came from them). Texts in a group chat they’re in, and texts of yours that never went, don’t count.

### Check iMessage

| Field          | Type | Required | Help |
| -------------- | ---- | -------- | ---- |
| Phone or email | Text | Yes      |      |

Calls `GET /v1/lookup`, which reads your own Messages history through your Mac and waits up to 15 seconds. Returns `service` (`imessage`, `sms` or `unknown`), `basis` and `last_seen_at`. A number you’ve never texted is `unknown`: Apple gives no way to ask. You don’t need it before sending, since **Service: Auto** tries iMessage first.

## Make an API Call

Calls any endpoint in the [API](https://usebluebot.com/docs/api) with your connection’s key.

| Field        | Type                             | Required | Help                                                                                                                                                          |
| ------------ | -------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| URL          | Text                             | Yes      | The path after `https://usebluebot.com/api/v1`, such as `/messages` or `/webhooks/wh_1Hq2LxW9cVbN3mKpRtYs0a/deliveries`.                                      |
| Method       | Select: GET, POST, PATCH, DELETE | Yes      |                                                                                                                                                               |
| Headers      | Array of key and value           | No       | `Authorization` and `BlueBot-Client: make` are added for you. Add an `Idempotency-Key` on a POST that must not run twice, such as the triggering record’s id. |
| Query String | Array of key and value           | No       |                                                                                                                                                               |
| Body         | Text (JSON)                      | No       |                                                                                                                                                               |

The bundle is the status code, the headers and the body. A list answers one page; read `next_cursor` and call again with it as `cursor` for the next.

## When a module fails

The app turns BlueBot’s error into Make’s, with BlueBot’s message, its hint, the code and the request id. Quote the request id if you write to support.

| BlueBot answers                                                                    | Make raises               | What happens                                                                                     |
| ---------------------------------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------ |
| `invalid_request` (400), `payload_too_large` (413), `unsupported_media_type` (415) | DataError                 | The module fails on that bundle. Fix the mapping; the message names the field.                   |
| `unauthorized` (401)                                                               | InvalidAccessTokenError   | Make stops the scenario until you reauthorize the connection.                                    |
| `plan_lapsed` (402), `insufficient_scope`, `forbidden`, `account_held` (403)       | InvalidConfigurationError | Make turns the scenario off. Fix the account or the key, then turn it on.                        |
| `not_found` (404), `conflict`, `idempotency_conflict`, `limit_reached` (409)       | DataError                 | The module fails on that bundle.                                                                 |
| `rate_limited` (429)                                                               | RateLimitError            | Add a **Break** error handler to try again; wait at least `retry_after` seconds.                 |
| `internal`, `upstream_failed`, `unavailable` (5xx)                                 | ConnectionError           | Add a **Break** handler to try again. The idempotency key keeps a retried send from going twice. |

A held text is not an error, and neither is a text that fails after it was accepted: catch those with **Watch Text Status Changes**.

## Test a scenario

### Build it with your own number

Add **Send Text**, type your own mobile number in **To** and some words in **Text**.

### Run once

Press **Run once**. For a scenario that starts with a watch module, press **Run once** first and then cause the event: text your BlueBot number from another phone that you’ve texted through BlueBot before.

| You got                                                    | It means                                           | Do next                                                                                                   |
| ---------------------------------------------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| A bundle with `state: "queued"` and the text on your phone | It works.                                          | Map the real field into **To** and schedule the scenario.                                                 |
| `hold.reason: "quiet_hours"`                               | It’s quiet hours; it waits for morning.            | Nothing, or change quiet hours in **Settings → Sending rules**.                                           |
| `hold.reason: "device_offline"`                            | Your Mac is asleep or BlueBot isn’t running on it. | Wake the Mac; held texts go once it checks in.                                                            |
| The watch module still waiting                             | No event reached the webhook.                      | Check **Which chats to copy**, and that the webhook is listed under **Developers → Webhooks** in BlueBot. |

The [recipes](https://usebluebot.com/docs/recipes) show the fields to map for many apps, and [Webhooks](https://usebluebot.com/docs/webhooks) explains what BlueBot sends.
