Pipedream
BlueBot’s Pipedream components send texts from your own number and start workflows when a text comes in. Every action and source, and how to call BlueBot from your own code steps.
BlueBot on Pipedream is an app you connect once, a set of actions (Send Text, Schedule Text and the rest) and instant sources that start a workflow when BlueBot posts an event. Because Pipedream runs code too, you can also call BlueBot from a Node.js or Python step with the connected account, which is the quickest way to do something the actions don’t.
Texts sent from Pipedream go through your sending rules like every other text and show source: "pipedream" in BlueBot.
Connect your account
Make a key
In BlueBot, open Developers → API keys, press New key, name it “Pipedream” and tick every scope. Sources need webhooks:manage, the contact actions need contacts:read and contacts:write, and the connection test needs account:read. Copy the key.
Connect it in Pipedream
Add any BlueBot step or source, press Connect a BlueBot account, paste the key into API Key and press Save. Pipedream tests it with GET /v1/me.
The connected account is the bluebot app prop: every component and code step that names it gets your key as this.bluebot.$auth.api_key, and Pipedream keeps the key out of your workflow’s code and logs.
Sources
Each source is instant. When you deploy it, it makes a webhook in your BlueBot account pointing at the source’s own HTTP endpoint, subscribed to the events it needs, and keeps the webhook’s id and signing secret in its $.service.db. When you delete the source, it deletes the webhook. The webhook shows under Developers → Webhooks in BlueBot, described as “Pipedream: ” and the source’s name.
Every request is checked against webhook-signature with that secret before anything is emitted, and one that fails is answered 401. Each emitted event uses BlueBot’s event id as its id with dedupe: "unique", so a delivery BlueBot retries never starts your workflow twice.
On deploy, a source also emits up to 10 recent matching events from GET /v1/events, so you have real data to build the next steps with.
| Source | Key | Emits | BlueBot events |
|---|---|---|---|
| New Incoming Text (Instant) | bluebot-new-incoming-text-instant | Each text somebody sends you, as the message. | message.received |
| Text Status Changed (Instant) | bluebot-text-status-changed-instant | Each change of state on a text you sent. Prop States picks which. | message.sent, message.delivered, message.read, message.failed, message.unconfirmed, message.expired, message.canceled |
| New Contact (Instant) | bluebot-new-contact-instant | Each person added to your contacts. | contact.created |
| Contact Stopped (Instant) | bluebot-contact-stopped-instant | Each person who goes on your stop list. | contact.stopped |
| Sequence Completed (Instant) | bluebot-sequence-completed-instant | Each person who reaches the end of a sequence or leaves it early. Prop Sequence narrows it to one. | sequence.completed |
The event a source emits is the record (steps.trigger.event is the message, contact or enrollment, exactly as the API returns it), and the summary names it, such as “New text from +15555550123”. The envelope’s id is steps.trigger.context.id and its timestamp is steps.trigger.context.ts, in milliseconds. The record carries the rest: a message’s state says which change it was.
New Incoming Text hears the texts of people you’ve texted through BlueBot, unless you set Which chats to copy to Everything in Settings → Sending rules. Its props are Include Group Chats (default true) and Only From (a number or email address).
Actions
| Action | Key | What it does |
|---|---|---|
| Send Text | bluebot-send-text | Sends a text now, or as soon as your sending rules allow. |
| Send Template | bluebot-send-template | Sends one of your templates with the variables you give it. |
| Schedule Text | bluebot-schedule-text | Sends a text at a time. It can be changed or canceled until then. |
| Cancel Scheduled Text | bluebot-cancel-scheduled-text | Cancels a scheduled or queued text by its msg_ id. |
| Create or Update Contact | bluebot-create-or-update-contact | Finds a person by number or email and updates them, or adds them. |
| Add Tag | bluebot-add-tag | Adds tags to a person. |
| Enroll in Sequence | bluebot-enroll-in-sequence | Starts a person on a sequence. |
| Remove from Sequence | bluebot-remove-from-sequence | Takes a person off one sequence or all of them. |
| Find Contact | bluebot-find-contact | Finds a person by number or email. |
| Find Conversation | bluebot-find-conversation | Your conversation with a person and its newest text. |
| Check iMessage | bluebot-check-imessage | Whether your newest chat with a number used iMessage or SMS. |
Send Text props
| Prop | Type | Required | What it is |
|---|---|---|---|
| To | string | Unless Group Chat is set | A mobile number in any format (US numbers can leave off +1), or an iMessage email address. |
| Group Chat | string, options from your group chats | No | Text an existing group chat instead. |
| Text | string | Unless Files is set | Up to 2,000 characters. |
| Files | string[] | No | Up to 10 file URLs or paths in /tmp. Each is uploaded to BlueBot first, up to 25 MB. |
| Service | string, options auto, imessage, sms | No | auto by default: the newest chat’s service, else iMessage, with one SMS retry for an iMessage that never went. |
| Expires At | string (ISO 8601) | No | Give up if it’s still waiting then. Default: 24 hours after it’s due. |
| Metadata | object | No | Up to 20 keys; echoed on every webhook about the text. |
Schedule Text adds Send At (required, ISO 8601). Send Template takes To, Template (options from your templates), Variables (object), Service and Metadata. A variable you leave out comes from the contact or your business name, else from the template’s own fallback, and one with none of those stops the send with invalid_request, naming it. Find Conversation takes Phone or Email and returns conversation_id, contact_id, last_message_id, last_message_text, last_message_direction, last_message_state, last_message_at and waiting_on_you, or nothing when you’ve never texted them. The contact and sequence actions take the fields of the same names on the , as props.
Each action exports a summary, such as “Queued a text to +15555550123” or, for a held text, “Accepted a text to +15555550123; it waits for quiet hours to end”, and returns the record the API answered. Every action that sends a text carries an Idempotency-Key made from the workflow’s event, the action and what the step was given, so Pipedream retrying the step after an error doesn’t send twice.
Your own code steps
Add the bluebot app prop to a Node.js step and use the TypeScript SDK, which Pipedream installs from the import:
import BlueBot from "@usebluebot/sdk";
export default defineComponent({
props: {
bluebot: { type: "app", app: "bluebot" },
},
async run({ steps, $ }) {
const client = new BlueBot({ apiKey: this.bluebot.$auth.api_key });
const lead = steps.trigger.event;
const message = await client.messages.send(
{
to: lead.phone,
text: `Hi ${lead.first_name}, thanks for reaching out. When is a good time to talk?`,
metadata: { source: "pipedream", lead_id: String(lead.id) },
},
// The same trigger event never sends twice, even when Pipedream retries this step.
{ idempotencyKey: `${steps.trigger.context.id}-welcome` },
);
$.export("$summary", `Text to ${message.to} is ${message.state}`);
return message;
},
});Or the Python SDK in a Python step:
from bluebot import BlueBot
def handler(pd: "pipedream"):
client = BlueBot(api_key=pd.inputs["bluebot"]["$auth"]["api_key"])
lead = pd.steps["trigger"]["event"]
message = client.messages.send(
to=lead["phone"],
text=f"Hi {lead['first_name']}, thanks for reaching out.",
idempotency_key=f"{pd.steps['trigger']['context']['id']}-welcome",
)
return message.model_dump(mode="json", by_alias=True)The and pages list every method.
Test a workflow
Use your own number first
In the action’s To, type your own mobile number, and press Test.
| You got | It means | Do next |
|---|---|---|
A message with state: "queued", and the text on your phone | It works. | Put the real value back in To and deploy. |
hold.reason: "quiet_hours" | It’s quiet hours, so it waits for morning. | Nothing, or change quiet hours in Settings → Sending rules. |
hold.reason: "device_offline" | Your Mac isn’t checking in. | Wake it; the text goes once it’s back. |
invalid_request | A field didn’t fit; the message names it. | Fix that prop. |
Check a source
Deploy the source, then text your BlueBot number from another phone you’ve texted through BlueBot before. The event shows in the source’s list within a second or two.
When a step fails
Actions throw BlueBot’s error with its message, hint, code and request id, and Pipedream shows it on the step. rate_limited (429) and the 5xx errors are worth retrying: turn on Auto-retry in the workflow’s settings, and the idempotency key keeps a retried send from going twice. A held text, and a text that fails after it was accepted, are not errors; use Text Status Changed to hear about those.