# Make a sequence

> A sequence is texts with waits between them.

`POST /v1/sequences`

A sequence is texts with waits between them. Each person added runs through it on their own, and stops when they text back (unless `stop_on_reply` is off) or text STOP. With `send_window`, a text due outside it waits for the window to open.

Needs a key with the `messages:send` scope. [Keys and scopes](https://usebluebot.com/docs/concepts/api-keys)

Send an `Idempotency-Key` so a retry never acts twice. [Idempotency](https://usebluebot.com/docs/concepts/idempotency)

## Headers

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | No | Any string of up to 255 characters, new for each request. A retry with the same key gets the first answer back for 24 hours, with `Idempotent-Replayed: true`. Up to 255 characters |

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | Up to 120 characters |
| `description` | string | No | Up to 500 characters |
| `stop_on_reply` | boolean | No | Default `true` |
| `send_window` | object or null | No | When steps may send, in your time zone. A step due outside it waits for it to open. |
| `send_window.days` | array of strings | Yes | The days it may send on. One of `mon`, `tue`, `wed`, `thu`, `fri`, `sat`, `sun` |
| `send_window.start` | string | Yes | A time of day as HH:MM in your account’s time zone. |
| `send_window.end` | string | Yes | A time of day as HH:MM in your account’s time zone. |
| `steps` | array of any | Yes | The steps in order. Up to 50 items |

## Example

```bash
curl -X POST "https://usebluebot.com/api/v1/sequences" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0f6d8c2e-5b1a-4c7e-9d3f-2a8b6e1c4d70" \
  -d '{
    "name": "New lead follow-up",
    "steps": [
      {
        "kind": "text",
        "text": "Hi {{first_name|there}}, thanks for asking about {{listing}}. Want to see it?"
      },
      {
        "kind": "wait",
        "wait_seconds": 172800
      },
      {
        "kind": "text",
        "text": "Just checking in. Still interested in {{listing}}?"
      }
    ],
    "send_window": {
      "days": [
        "mon",
        "tue",
        "wed",
        "thu",
        "fri"
      ],
      "start": "09:00",
      "end": "18:00"
    }
  }'
```

```ts
import BlueBot from '@usebluebot/sdk';

const client = new BlueBot({ apiKey: process.env.BLUEBOT_API_KEY });

const sequence = await client.sequences.create({
  name: 'New lead follow-up',
  steps: [
    {
      kind: 'text',
      text: 'Hi {{first_name|there}}, thanks for asking about {{listing}}. Want to see it?',
    },
    {
      kind: 'wait',
      waitSeconds: 172800,
    },
    {
      kind: 'text',
      text: 'Just checking in. Still interested in {{listing}}?',
    },
  ],
  sendWindow: {
    days: ['mon', 'tue', 'wed', 'thu', 'fri'],
    start: '09:00',
    end: '18:00',
  },
}, { idempotencyKey: '0f6d8c2e-5b1a-4c7e-9d3f-2a8b6e1c4d70' });
console.log(sequence);
```

```python
import os
from bluebot import BlueBot

client = BlueBot(api_key=os.environ["BLUEBOT_API_KEY"])

sequence = client.sequences.create(
    name="New lead follow-up",
    steps=[
        {
            "kind": "text",
            "text": "Hi {{first_name|there}}, thanks for asking about {{listing}}. Want to see it?",
        },
        {
            "kind": "wait",
            "wait_seconds": 172800,
        },
        {
            "kind": "text",
            "text": "Just checking in. Still interested in {{listing}}?",
        },
    ],
    send_window={
        "days": ["mon", "tue", "wed", "thu", "fri"],
        "start": "09:00",
        "end": "18:00",
    },
    idempotency_key="0f6d8c2e-5b1a-4c7e-9d3f-2a8b6e1c4d70",
)
print(sequence)
```

## Response

`201`: The sequence.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes | A seq_ id. Starts with `seq_` |
| `object` | "sequence" | Yes |   |
| `name` | string | Yes |   |
| `description` | string or null | Yes |   |
| `state` | string | Yes | `active` takes new people and sends; `paused` holds every enrollment where it is; `archived` ends them. One of `active`, `paused`, `archived` |
| `stop_on_reply` | boolean | Yes | Stop a person’s run when they text back. On unless you turn it off. A stop word always stops it. |
| `send_window` | object or null | Yes | When steps may send, in your time zone. A step due outside it waits for it to open. |
| `send_window.days` | array of strings | Yes | The days it may send on. One of `mon`, `tue`, `wed`, `thu`, `fri`, `sat`, `sun` |
| `send_window.start` | string | Yes | A time of day as HH:MM in your account’s time zone. |
| `send_window.end` | string | Yes | A time of day as HH:MM in your account’s time zone. |
| `steps` | array of SequenceStep | Yes |   |
| `steps[].id` | string | Yes | A step_ id. Starts with `step_` |
| `steps[].position` | integer | Yes | Its place in the sequence, from 0. |
| `steps[].kind` | string | Yes | One of `text`, `wait` |
| `steps[].wait_seconds` | integer or null | Yes | For a wait: how long, from a minute to a year. |
| `steps[].text` | string or null | Yes | For a text: the words, with `{{variables}}`. |
| `steps[].template_id` | string or null | Yes | For a text: the template it uses instead of `text`. |
| `steps[].service` | string | Yes | One of `auto`, `imessage`, `sms` |
| `counts` | map of integer | Yes | Enrollments by state: `active`, `completed`, `stopped`, `canceled`. |
| `created_via` | string | Yes | One of `dashboard`, `api`, `assistant`, `mcp`, `zapier`, `cli` |
| `created_at` | timestamp | Yes | When it was made. |

The answer, `201`:

```json
{
  "id": "seq_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "sequence",
  "name": "New lead follow-up",
  "description": "For people who ask about a listing.",
  "state": "active",
  "stop_on_reply": true,
  "send_window": {
    "days": [
      "mon",
      "tue",
      "wed",
      "thu",
      "fri"
    ],
    "start": "09:00",
    "end": "18:00"
  },
  "steps": [
    {
      "id": "step_1Hq2LxW9cVbN3mKpRtYs0a",
      "position": 0,
      "kind": "text",
      "wait_seconds": null,
      "text": "Hi {{first_name|there}}, thanks for asking about {{listing}}. Want to see it?",
      "template_id": null,
      "service": "auto"
    },
    {
      "id": "step_2Bf8QzD4kJmA6nXwEuTr1c",
      "position": 1,
      "kind": "wait",
      "wait_seconds": 172800,
      "text": null,
      "template_id": null,
      "service": "auto"
    },
    {
      "id": "step_3Lp3VsC7hGqE5tZyKbWn2d",
      "position": 2,
      "kind": "text",
      "wait_seconds": null,
      "text": "Just checking in. Still interested in {{listing}}?",
      "template_id": null,
      "service": "auto"
    }
  ],
  "counts": {},
  "created_via": "dashboard",
  "created_at": "2026-11-01T15:00:00.000Z"
}
```

## Errors

Every refusal has the same envelope and a page of its own. These are the ones this operation can give.

| Code                                                        | Status | What it means                                                                                                                                    |
| ----------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`unauthorized`](https://usebluebot.com/docs/errors/unauthorized)                 | 401    | The request carried no key, or a key BlueBot doesn’t know: mistyped, revoked, or a test key sent to the live API.                                |
| [`insufficient_scope`](https://usebluebot.com/docs/errors/insufficient_scope)     | 403    | The key doesn’t carry the scope the endpoint needs. Each endpoint’s reference names its scope.                                                   |
| [`rate_limited`](https://usebluebot.com/docs/errors/rate_limited)                 | 429    | Too many requests. A key may make 120 requests a minute. The `RateLimit` header says how many are left, and `Retry-After` how long to wait.      |
| [`internal`](https://usebluebot.com/docs/errors/internal)                         | 500    | Something went wrong on BlueBot’s side. It was reported. Send the request again; with an Idempotency-Key that is always safe.                    |
| [`invalid_request`](https://usebluebot.com/docs/errors/invalid_request)           | 400    | Something in the request doesn’t fit: a missing or malformed field, a bad id, or a combination the endpoint refuses. `details` names each field. |
| [`not_found`](https://usebluebot.com/docs/errors/not_found)                       | 404    | There is no such thing on this account. Ids are prefixed by kind, so a message id starts with `msg_`.                                            |
| [`limit_reached`](https://usebluebot.com/docs/errors/limit_reached)               | 409    | The account has as many of something as it may have.                                                                                             |
| [`plan_lapsed`](https://usebluebot.com/docs/errors/plan_lapsed)                   | 402    | The account’s plan isn’t active, so BlueBot isn’t taking new texts. Texts already queued wait and go once the plan is active again.              |
| [`idempotency_conflict`](https://usebluebot.com/docs/errors/idempotency_conflict) | 409    | The Idempotency-Key was used in the last 24 hours with a different request. A key stands for one request.                                        |

## Try it
