Skip to content
Miss Blue

Product guide

Automations

Something happens, and then a series of things happen because of it. Answer a common question the instant somebody asks it, or follow up two days later if they never replied.

Build them in the console, or entirely through the API, mb or an agent. The last section, From the API, mb or an agent, has a complete request for a sequence with a wait, a condition and personalized messages.

Send

A message from the line they wrote to (or, for a list or a tag, the line the flow sends from), with variables filled in for that person from their contact as it is when the message goes. The next step runs once it has gone out, so two sends in a row arrive in order, usually a few seconds apart. A first contact held for pacing holds the rest of the flow with it. If a message still hasn't gone out after seven days, the flow ends there for that person and says why.

Wait

Minutes or days, up to a month, counted from when the message before it went out. Nothing is held in memory: the flow records where somebody is and comes back to them, so a restart loses nobody.

Only if

Checked the moment the flow gets there: only if they haven't replied since the last message, or only if they have. If not, the flow ends there for them. Put a Wait before it, or it is checked before anybody could answer.

Stop

End the flow here. Useful at the end of a branch you do not want falling through into the steps below it.

Follow up if they don’t reply

The most common flow, and a starting point on the new automation page: when somebody gets a tag, send a message; wait three hours; then, only if they haven’t replied since that message, send a follow-up. If they answer at any point, nothing more is sent.

That last part is Stop when they reply, on for every new flow: anybody who answers a message from the flow leaves it, and a wait in progress ends without sending. Something they said before the flow’s first message went out is not a reply to it, so a second text sent before your answer to the first one arrived does not call that answer off.

Only send during business hours

Turn on Only send during these hours under “When” and pick the times, the time zone and the days: 8 AM to 6 PM Eastern, Monday to Friday, say. It is off unless you turn it on. Changing the hours later applies to everybody already waiting for them.

  • What starts it still starts it at any time. A tag added at 11 PM starts the flow at 11 PM; its first message waits and goes at 8 AM.
  • Every message waits for the hours. A first message, a follow-up whose wait ends in the evening, or a keyword reply goes when the hours next open. On Friday evening with weekdays only, that is Monday at 8.
  • Replies still count overnight. An “Only if” right before a message is checked when the message is about to go, so somebody who answers at 2 AM does not get the 8 AM follow-up. Waits are still counted from when the message before them went.
  • First contacts are still spread out. People who have never messaged you go out at the usual pace from 8 AM, not all at once, and anybody the pace would push past the end of the day waits for the next morning. A short window reaches fewer people a day, and the switch-on screen says how many.
  • Nothing waiting goes out after closing. A message still waiting to go when the hours close, because this number was unavailable for a while, is cancelled and sent again the next morning. The cancelled copy shows in the conversation. One already on its way at 5:59 PM can still arrive a moment after six. The same goes for a held text you resend after closing: that copy is cancelled, and the flow sends a new one when the hours open, by iMessage like its other messages.
  • The time zone decides the day. 8 AM is 8 AM there, on both sides of a clock change. Hours that run past midnight are not supported yet: the end has to be after the start.
  • Seven days still means seven days. A message that cannot go because this number stays unavailable ends the flow for that person after seven days on the calendar, nights and weekends included. With weekday hours, that is about five working days of tries.

What starts one

  • They text a word. The word has to be the whole message, so “what are your hours?” will not trigger a flow on “hours”. It is the same rule as STOP, and for the same reason: a keyword inside a sentence is just a word.
  • They message you for the first time. An opener for somebody who has just found you.
  • They message you at all. Every inbound message, which is usually more than you want.
  • They are added to a list. Starts the moment somebody joins, by hand, by import, or through the API. This is how a sequence starts for a customer who has never texted you.
  • They get a tag. Starts the moment a tag appears on somebody. Lists and tags are independent: a person can be on a list, carry tags, both, or neither.

The two that reach strangers

The first three wait for somebody to write to you. A list and a tag do not, which is the point of them, and it means these two can send a first message to somebody who has never heard from your line. They carry two rules the others do not.

  • They send from Auto, or from a number you choose. Auto picks each person’s number the way Auto does when you send by hand: somebody you already talk to hears from the same number, and new people take turns across your numbers that can send. It is chosen when their first message goes and kept for the rest of the flow.
  • A person reads the first one. Your project’s first flow of this kind waits for somebody here to read it, the same as your first announcement and for the same reason. After one is approved, the rest go straight out.

People who have never messaged you are first contacts, so they count against each number’s daily limit (50 a day by default) and are spread out. On Auto the limit adds up across your numbers: two numbers reach about a hundred new people a day, so a list of four hundred takes about four days rather than eight. The screen tells you how many days before you switch it on.

Switching one on

A flow attached to a list can either start everybody already on it or only the people who join from now on. It asks, every time, and defaults to only new arrivals, because the two answers differ by ten thousand people and there is no safe guess between them.

Adding the same people to a list twice does not start them twice. Only the rows the call actually created count as somebody arriving, so re-uploading yesterday’s spreadsheet is not an event.

One person, one run

Somebody who triggers a flow twice in a minute goes through it once. That is enforced in the database rather than remembered by the code, so it holds however the flow is triggered.

Editing a flow people are already in

Everybody keeps their step number. Somebody waiting for step 3 carries on from step 3 of the edited flow, with whatever it says now: change its words and they get the new words. Steps are counted from the top, so a step you add or remove above them changes what their step 3 is, and they carry on from whatever is third now. If the flow no longer has a step 3, it is finished for them. A message already on its way still goes.

Testing two or three versions

Any message in a flow can have a version B, and a version C, to see which one gets replies and which one makes people opt out. Choose Add a version under the message, write the other versions, and give each a weight: its share of new people, in percent. The line under them says how they split, like “Splits 50 / 30 / 20”.

Each person is given a version the first time they reach a message with versions, and keeps it: somebody on B hears B’s follow-up too. So a later message with versions follows the first one’s split, and can only have its letters. A later message without a B sends them A. A message with one text sends everybody that text.

Results shows the versions side by side: sent, delivered, read, replied and opted out, with reply and opt-out rates, and a verdict in one sentence, like “B gets more replies (18% vs 11%), and opt-outs are about the same.” Until every version has reached 30 people it says how many more it needs instead. Replies and opt-outs are each checked for a gap bigger than chance (95%; for opt-outs, which are rare, with a stricter test), and a gap chance could make is called “about the same”, never a winner.

From Results, Use this one sends that version to everybody who reaches that message from now on, including people given another version earlier. Change weights changes the split on the first message with versions: people already given a version keep it. Every version’s results stay. Changing a version’s words mixes the old words’ results with the new, so the editor offers Start fresh results, which compares from when you save. Taking a version out sends its people A from then on.

Quiet hours

Under When it sends, a flow keeps to quiet hours unless you choose your own: each message reaches its person only between 8 AM and 9 PM in their time, or tighter where their state requires it, worked out from their area code. A step due at night waits for their morning, and an “Only if” right before it is asked then. A reply to somebody who wrote to you in the last hour is not held. Choose My own hours and those are used instead — one window, in one time zone, for everybody — and following the law where each person is is yours to answer for. How quiet hours work.

When a number leaves your project

A flow that sends from it moves to another of your numbers, and says which on the automation. Anybody partway through hears from the new number from their next message. If your project has no other number, the flow is switched off and says so; turn it back on once you have one.

New flows start switched off

A flow that ran the moment it was saved would send the half-written version to whoever texted next. Turn it on when you are happy with it.

Every message a flow sends goes through the same checks as anything you send by hand, at the moment it sends. Somebody who opts out partway through a sequence stops receiving the rest of it.

To see how one is doing, open it and choose Results, or read its stats and replies from the API.

From the API, mb or an agent

Everything on this page can be built without opening the console: a multi-step sequence with waits, “Only if” conditions and messages written for each person. The example below is a cart reminder. When a customer is tagged cart-abandoned, it texts them about what they left, waits a day, and follows up only if they have not replied since.

Step bodies are Liquid. The variables in them are filled in for each person when that message is sent, from their contact as it is at that moment: {{ contact.first_name }} from their name, and anything you store on the contact as {{ contact.custom.<name> }}. Update a field before the follow-up goes and the follow-up says the new value. Give every variable a default: so somebody with nothing saved reads “Hi there”, not “Hi ,”. Templates and Liquid lists every variable, and the Campaigns API reference has every field and route.

1. Put the details on the contact

Save the customer by their number with the fields the messages need. Fields you name are set and the rest are kept; a field sent as "" is removed.

curl -X PUT "https://api.missblue.dev/v1/contacts?project_id=$PROJECT" \
  -H "Authorization: Bearer $MISS_BLUE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "handle": "+15555550100",
    "name": "Ada Lovelace",
    "custom_data": {
      "product": "Blue hoodie",
      "amount": "$48",
      "checkout_link": "https://shop.example/c/91"
    }
  }'

2. Create the automation

It is created switched off. With no number_id it sends from Auto. stop_on_reply ends a person’s run as soon as they answer, and is on unless you say otherwise. send_hours is optional. With it, as below, the flow keeps to your hours instead of quiet hours, and following the law where each person is is yours to answer for. Leave it out and each message keeps to quiet hours, 8 AM–9 PM in the recipient’s own time, unless you also send "quiet_hours": false to send at any time. A wait is in seconds, so a day is 86400.

curl -X POST "https://api.missblue.dev/v1/projects/$PROJECT/automations" \
  -H "Authorization: Bearer $MISS_BLUE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'JSON'
{
  "name": "Cart reminder",
  "trigger_kind": "tag_added",
  "trigger_tag": "cart-abandoned",
  "stop_on_reply": true,
  "send_hours": {
    "start": "08:00",
    "end": "18:00",
    "time_zone": "America/New_York",
    "days": ["mon", "tue", "wed", "thu", "fri"]
  },
  "steps": [
    {
      "kind": "send",
      "body": "Hi {{ contact.first_name | default: \"there\" }}, your {{ contact.custom.product }} ({{ contact.custom.amount }}) is still waiting: {{ contact.custom.checkout_link }}"
    },
    { "kind": "wait", "wait_seconds": 86400 },
    { "kind": "condition", "condition_kind": "not_replied_since_last" },
    {
      "kind": "send",
      "body": "Still thinking it over, {{ contact.first_name | default: \"there\" }}? Your cart is saved: {{ contact.custom.checkout_link }}"
    }
  ]
}
JSON

The answer is the automation, with its id, "enabled": false and its steps. To see what a step will say to one customer before anything goes, send its body to POST /v1/projects/{id}/templates/preview with their handle.

3. Switch it on, and start somebody

curl -X POST "https://api.missblue.dev/v1/projects/$PROJECT/automations/$AUTOMATION/enabled" \
  -H "Authorization: Bearer $MISS_BLUE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true, "include_existing": false }'

curl -X POST "https://api.missblue.dev/v1/projects/$PROJECT/tags" \
  -H "Authorization: Bearer $MISS_BLUE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tag": "cart-abandoned", "handles": ["+15555550100"] }'

include_existing: false starts only people tagged from now on. true also starts everybody who already carries the tag, which messages them straight away; ask GET …/automations/$AUTOMATION/effect first for how many that is and how long the first contacts take. Tagging somebody starts the flow for them, and the answer’s started counts them. A project’s first flow that writes to people first comes back awaiting_review and starts once a person at Miss Blue has read it.

The same flow with mb

mb builds the same request from flags. The follow-up goes only to people who have not replied since the first message unless you pass --follow-up-if, and Stop when they reply is on. An agent connected with mb mcp calls the same commands as tools.

mb contact-add --handle +15555550100 --first-name Ada --last-name Lovelace \
  --field product="Blue hoodie" --field amount='$48' \
  --field checkout_link=https://shop.example/c/91

mb automation-create --name "Cart reminder" --tag cart-abandoned \
  --text 'Hi {{ contact.first_name | default: "there" }}, your {{ contact.custom.product }} ({{ contact.custom.amount }}) is still waiting: {{ contact.custom.checkout_link }}' \
  --wait 1d \
  --follow-up 'Still thinking it over, {{ contact.first_name | default: "there" }}? Your cart is saved: {{ contact.custom.checkout_link }}' \
  --hours 08:00-18:00 --time-zone America/New_York --days mon-fri

mb automation-on --id <automation id>
mb tag --tag cart-abandoned --handles +15555550100 --confirm

mb tag asks for --confirm because tagging somebody now starts a flow that messages them.

Watch it run

The runs route says who is in the flow, which step each person is on, when their next message goes and what it is waiting for (their quiet hours, your sending hours, the daily new-contact limit or a wait), with their time zone, and why anybody left early. Add order=next for soonest first. mb automation-runs --id prints the same fields, and the console’s People tab shows them in each person’s time and yours.

curl "https://api.missblue.dev/v1/projects/$PROJECT/automations/$AUTOMATION/runs?status=running" \
  -H "Authorization: Bearer $MISS_BLUE_API_KEY"
{
  "total": 1,
  "data": [{
    "run_id": "0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
    "handle": "+15555550100",
    "status": "running",
    "reason": null,
    "step_position": 20,
    "due_at": "2026-09-28T14:00:00Z",
    "deferred_until": "2026-09-28T14:00:00Z",
    "waiting_for": "quiet_hours",
    "next_message_at": "2026-09-28T14:00:00Z",
    "time_zone": "America/Denver",
    "state": "CO",
    "started_at": "2026-09-27T14:00:00Z",
    "finished_at": null
  }]
}

Or be told. A webhook receives automation.run.started when somebody starts, and automation.run.finished when their run ends, with an outcome: completed, replied, stopped, number_left, gave_up or failed. Each message.sent from the flow names the automation, the run and the step in its source. See Delivery for the payloads.

NextScheduled messagesFor one message at one time, rather than a sequence triggered by something.