> For the complete documentation index, see [llms.txt](https://help.blotato.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.blotato.com/api/messages.md).

# Messages

Blotato allows you to read and send direct messages on your Instagram account and Facebook Page. Twitter/X, TikTok, LinkedIn, Pinterest, Threads, Bluesky, and YouTube are not supported at this time. Five endpoints let you list conversations, read a conversation, list messages, read a message, and send a message:

* [List Conversations](#list-conversations) — `GET /v2/conversations`
* [Get Conversation](#get-conversation) — `GET /v2/conversations/:conversationId`
* [List Messages](#list-messages) — `GET /v2/messages`
* [Get Message](#get-message) — `GET /v2/messages/:messageId`
* [Send Message](#send-message) — `POST /v2/messages`

Messages are available on all paid plans.

To manage Instagram and Facebook conversations in the Blotato web app, see [Comments and Messaging Inbox](/features/inbox.md).

To send automatic replies after a comment or incoming message, use [DM Automations](/support/dm-automations.md). You manage these automations in the web app or through an AI tool connected to Blotato MCP.

Each message has a `direction`:

* **Incoming messages** your contacts send you. These have `direction: "incoming"`.
* **Outgoing messages** you send through Blotato. These have `direction: "outgoing"`.

You reply to people who already have a conversation with you. You send to a `recipientId` taken from an existing conversation or an incoming message, not to an arbitrary user. The social platform limits who you can message and when. See [Messaging Windows](#messaging-windows).

Blotato retains messages for up to 45 days. Messages older than 45 days are not available through these endpoints.

## Before You Start

Blotato must have permissions to read and send messages on your account before you can use the Blotato messaging endpoints.

If you connected your account before messaging launched, reconnect it so Blotato has the new permission.

* For Instagram, see [Connect Instagram](/settings/social-accounts/instagram.md).
* For Facebook, see [Connect Facebook](/settings/social-accounts/facebook.md).

***

## List Conversations

### Endpoint

**Base URL:** `https://backend.blotato.com/v2`

**URL:** `/conversations`

**Method:** `GET`

### Description

Returns your conversations across connected accounts, ordered by most recent activity. Use cursor-based pagination and the optional filters below.

### Query Parameters

| Field       | Type      | Required | Description                                                      |
| ----------- | --------- | -------- | ---------------------------------------------------------------- |
| `limit`     | `integer` | No       | Maximum conversations to return (1-250). Default 50.             |
| `cursor`    | `string`  | No       | Cursor from a previous response. Pass it to fetch the next page. |
| `platform`  | `string`  | No       | Filter by platform. Values: `instagram`, `facebook`.             |
| `accountId` | `string`  | No       | Filter to a single connected account.                            |

### Response

**Status Code:** `200 OK`

```json
{
  "items": [
    {
      "id": "cnv_abc123",
      "accountId": "98434",
      "platform": "instagram",
      "participants": [
        {
          "id": "1784000000",
          "name": "Jamie Rivera",
          "username": "jamie.rivera",
          "profileImageUrl": "https://example.com/avatar.jpg"
        }
      ],
      "createdAt": "2026-07-01T12:00:00Z",
      "updatedAt": "2026-07-02T09:30:00Z"
    }
  ],
  "cursor": "eyJz..."
}
```

| Field    | Type     | Description                                                             |
| -------- | -------- | ----------------------------------------------------------------------- |
| `items`  | `array`  | List of conversations. See [Conversation Object](#conversation-object). |
| `cursor` | `string` | Cursor for the next page. Absent when there are no more conversations.  |

***

## Get Conversation

### Endpoint

**URL:** `/conversations/:conversationId`

**Method:** `GET`

### Description

Fetches a single conversation by its Blotato ID.

### Path Parameters

| Field            | Type     | Required | Description                     |
| ---------------- | -------- | -------- | ------------------------------- |
| `conversationId` | `string` | Yes      | Blotato ID of the conversation. |

### Response

**Status Code:** `200 OK`

Returns a [Conversation Object](#conversation-object).

***

## List Messages

### Endpoint

**URL:** `/messages`

**Method:** `GET`

### Description

Returns your messages across connected accounts, ordered by creation time (most recent first). Use cursor-based pagination and the optional filters below.

### Query Parameters

| Field            | Type      | Required | Description                                                      |
| ---------------- | --------- | -------- | ---------------------------------------------------------------- |
| `limit`          | `integer` | No       | Maximum messages to return (1-250). Default 50.                  |
| `cursor`         | `string`  | No       | Cursor from a previous response. Pass it to fetch the next page. |
| `conversationId` | `string`  | No       | Filter to messages in a single conversation.                     |
| `platform`       | `array`   | No       | Filter by platform. Values: `instagram`, `facebook`.             |
| `accountId`      | `string`  | No       | Filter to a single connected account.                            |

### Response

**Status Code:** `200 OK`

```json
{
  "items": [
    {
      "id": "msg_abc123",
      "conversationId": "cnv_abc123",
      "platform": "instagram",
      "direction": "incoming",
      "senderId": "1784000000",
      "recipientId": "17841400000000000",
      "text": "Hi! Is this still available?",
      "status": "delivered",
      "errorCode": null,
      "errorMessage": null,
      "createdAt": "2026-07-02T09:30:00Z"
    }
  ],
  "cursor": "eyJz..."
}
```

| Field    | Type     | Description                                                       |
| -------- | -------- | ----------------------------------------------------------------- |
| `items`  | `array`  | List of messages. See [Message Object](#message-object).          |
| `cursor` | `string` | Cursor for the next page. Absent when there are no more messages. |

***

## Get Message

### Endpoint

**URL:** `/messages/:messageId`

**Method:** `GET`

### Description

Fetches a single message by its Blotato ID. Poll this after [Send Message](#send-message) to check whether an outgoing message reached `sent` or `failed`.

### Path Parameters

| Field       | Type     | Required | Description                |
| ----------- | -------- | -------- | -------------------------- |
| `messageId` | `string` | Yes      | Blotato ID of the message. |

### Response

**Status Code:** `200 OK`

Returns a [Message Object](#message-object).

***

## Send Message

### Endpoint

**URL:** `/messages`

**Method:** `POST`

### Description

Sends a direct message to one recipient. Blotato queues the message and sends it in the background, so the response returns status `queued`. Poll [Get Message](#get-message) with the returned `id` to confirm the message reached `sent` or `failed`.

Send to a `recipientId` taken from an existing conversation or an incoming message. The social platform limits who you can message and when. See [Messaging Windows](#messaging-windows).

### Request Body

```json
{
  "accountId": "98434",
  "recipientId": "1784000000",
  "text": "Thanks for reaching out! Yes, it's available.",
  "target": {
    "targetType": "instagram"
  }
}
```

| Field         | Type     | Required | Description                                                                                                                                                                                                                |
| ------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accountId`   | `string` | Yes      | Blotato ID of the connected account the message is sent from.                                                                                                                                                              |
| `recipientId` | `string` | Yes      | Social platform (e.g. Instagram) ID of the recipient. Get it from an existing conversation or incoming message.                                                                                                            |
| `text`        | `string` | Yes      | Plain-text message body. Instagram messages are limited to 1000 bytes, Facebook to 2000 characters. With buttons attached, the limit drops to 640 characters. See [Buttons and Quick Replies](#buttons-and-quick-replies). |
| `target`      | `object` | Yes      | Where and how to send. See [Target](#target).                                                                                                                                                                              |

### Target

| Field          | Type     | Required     | Description                                                                                                                                                    |
| -------------- | -------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `targetType`   | `string` | Yes          | Value: `instagram` or `facebook`.                                                                                                                              |
| `pageId`       | `string` | For Facebook | ID of the Facebook Page to send from, from [subaccounts](/api/accounts.md#list-subaccounts-pages). Required when `targetType` is `facebook`.                   |
| `commentId`    | `string` | No           | Blotato comment ID. When set, Blotato delivers the message as a private reply to that comment instead of a direct message.                                     |
| `attachment`   | `object` | No           | Up to 3 call-to-action buttons pinned under the message. See [Buttons and Quick Replies](#buttons-and-quick-replies).                                          |
| `quickReplies` | `array`  | No           | Up to 13 tappable reply chips shown under the message. See [Buttons and Quick Replies](#buttons-and-quick-replies).                                            |
| `responseType` | `string` | No           | How the message fits the platform's messaging window: `RESPONSE`, `UPDATE`, or `MESSAGE_TAG`. Default `RESPONSE`. See [Messaging Windows](#messaging-windows). |
| `tag`          | `string` | No           | Required when `responseType` is `MESSAGE_TAG` (e.g. `HUMAN_AGENT`).                                                                                            |

### Buttons and Quick Replies

Facebook and Instagram support buttons and quick replies in direct messages. Set `target.attachment` for buttons, or `target.quickReplies` for chips. The two are mutually exclusive: a request carrying both is rejected with `422`.

For any platform-applied limitations, see:

* [Instagram Limitations](/platforms/instagram/limitations.md#direct-messages-and-dm-automations)
* [Facebook Limitations](/platforms/facebook/limitations.md#direct-messages-and-dm-automations)

#### Buttons

Buttons sit under the message and stay there. Up to 3 buttons are supported.

**Instagram Limitation:** Instagram only renders buttons in the Instagram mobile app. A recipient reading the conversation on instagram.com in a desktop browser sees the message text with no buttons.

Send an `attachment` or a URL inside `text`, not both. A message carrying both leaves the URL in `text` unclickable on desktop, so a desktop recipient ends up with no working link. For a primarily desktop audience, drop the `attachment` and put the URL in `text`.

```json
{
  "accountId": "98434",
  "recipientId": "1784000000",
  "text": "Thanks for reaching out! Pick an option below.",
  "target": {
    "targetType": "instagram",
    "attachment": {
      "type": "button",
      "buttons": [
        { "type": "web_url", "title": "View pricing", "url": "https://example.com/pricing" },
        { "type": "postback", "title": "Talk to sales", "payload": "SALES" }
      ]
    }
  }
}
```

| Field     | Type     | Required | Description      |
| --------- | -------- | -------- | ---------------- |
| `type`    | `string` | Yes      | Value: `button`. |
| `buttons` | `array`  | Yes      | 1 to 3 buttons.  |

Each button has:

| Field     | Type     | Required       | Description                                                     |
| --------- | -------- | -------------- | --------------------------------------------------------------- |
| `type`    | `string` | Yes            | `web_url` opens a link. `postback` reports the tap back to you. |
| `title`   | `string` | Yes            | Button label, 1 to 20 characters.                               |
| `url`     | `string` | For `web_url`  | Link the button opens. Starts with `https://`.                  |
| `payload` | `string` | For `postback` | Value echoed back on tap, 1 to 1000 characters.                 |

With buttons set, `text` is required and limited to 640 characters.

#### Quick Replies

Quick replies are tappable chips offered as canned answers. They disappear once the person taps one or types their own message. Pass 1 to 13.

```json
{
  "accountId": "98434",
  "recipientId": "1784000000",
  "text": "What size do you need?",
  "target": {
    "targetType": "instagram",
    "quickReplies": [
      { "title": "Small", "payload": "SIZE_S" },
      { "title": "Medium", "payload": "SIZE_M" },
      { "title": "Large", "payload": "SIZE_L" }
    ]
  }
}
```

| Field     | Type     | Required | Description                                     |
| --------- | -------- | -------- | ----------------------------------------------- |
| `title`   | `string` | Yes      | Chip label, 1 to 20 characters.                 |
| `payload` | `string` | Yes      | Value echoed back on tap, 1 to 1000 characters. |

Quick replies require non-empty message `text`.

#### Reading a Tap

A quick-reply tap and a postback tap both arrive as the next **incoming** message carrying `payload.selection`, but they reach you differently.

Quick replies send a real text message. `text` holds the chip label, adn Blotato attaches `payload.selection` alongside it.

```json
{
  "id": "msg_def456",
  "direction": "incoming",
  "text": "Your chip label",
  "payload": {
    "selection": { "type": "quick-reply", "payload": "The chip payload" }
  }
}
```

Postbacks do not send a text message. Blotato records the tap as an incoming message, sets `text` to the button label, and attaches `payload.selection`.

```json
{
  "id": "msg_ghi789",
  "direction": "incoming",
  "text": "Your button label",
  "payload": {
    "selection": { "type": "postback", "payload": "SALES" }
  }
}
```

| Field               | Value         | Meaning                                                                                         |
| ------------------- | ------------- | ----------------------------------------------------------------------------------------------- |
| `selection.type`    | `quick-reply` | The person tapped a chip. `text` is the chip label.                                             |
| `selection.type`    | `postback`    | The person tapped a button you attached. `text` is the button label.                            |
| `selection.payload` | your string   | The `payload` you set on the chip or button. A postback carries `null` when you set no payload. |

Branch on `selection.payload`, not on `text`. Two chips that share a label are distinguishable only by their payload.

A `web_url` button produces no selection. The link opens and nothing comes back.

Blotato subscribes your account to the postback webhook when you connect it. If you connected your account before buttons were launched, [reconnect](https://my.blotato.com/settings) to start receiving postback events. Quick-reply taps need no reconnect.

### Response

**Status Code:** `201 Created`

Returns a [Message Object](#message-object) with status `queued`.

### Errors

Send Message returns `201` on success, `422` when the request is rejected, and `429` when you exceed 30 requests per minute.

Messaging is available on every plan, so there is no "not enabled" rejection, and this endpoint does not return `404`. A connected account that is missing or expired surfaces after the message is queued, as a `failed` message.

A `422` means one of:

* The message exceeds the platform's character limit. Instagram allows 1000 bytes, Facebook 2000 characters, and either drops to 640 characters when buttons are set.
* You passed both `attachment` and `quickReplies`. Send one or the other.
* You set buttons or quick replies without message `text`.
* The messaging window has closed.
* The comment you are replying to is invalid, or it already received a private reply.
* You reached your plan's monthly active-contacts limit (error code 20101).
* `responseType` is `MESSAGE_TAG` and you did not set `tag`.

Message-send failures that happen after the message is queued do not return an error here. The message reaches status `failed` with an `errorCode` and `errorMessage`. See [Messaging Errors](/support/errors.md#messaging-errors).

***

## Messaging Windows

The social platform limits who you can message and when. You reply to people who already have a conversation with you, not arbitrary users.

* **Standard window:** send a `RESPONSE` within 24 hours of the contact's last message.
* **Private reply to a comment:** set `commentId` on the target to reply once, within 7 days of the comment.
* **Outside the window:** set `responseType` to `MESSAGE_TAG` with an approved `tag` (e.g. `HUMAN_AGENT`) to send a permitted follow-up.

These windows come from the social platform, not Blotato. A message sent outside an allowed window reaches status `failed`.

Sending a message to a new person also counts toward your plan's monthly active-contacts limit. See [Active Contacts](/settings/billing-and-credits.md#active-contacts).

***

## Conversation Object

| Field          | Type     | Description                                                                                                                 |
| -------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| `id`           | `string` | Blotato conversation ID.                                                                                                    |
| `accountId`    | `string` | ID of the connected account this conversation belongs to.                                                                   |
| `platform`     | `string` | `instagram` or `facebook`.                                                                                                  |
| `participants` | `array`  | The other people in the conversation. Each has `id`, `name`, `username`, and `profileImageUrl`, any of which may be `null`. |
| `createdAt`    | `string` | ISO 8601 timestamp when the conversation started.                                                                           |
| `updatedAt`    | `string` | ISO 8601 timestamp of the most recent activity.                                                                             |

***

## Message Object

| Field            | Type              | Description                                                                                    |
| ---------------- | ----------------- | ---------------------------------------------------------------------------------------------- |
| `id`             | `string`          | Blotato message ID.                                                                            |
| `conversationId` | `string or null`  | Blotato ID of the parent conversation.                                                         |
| `platform`       | `string`          | `instagram` or `facebook`.                                                                     |
| `direction`      | `string`          | `incoming` for messages you receive, `outgoing` for messages you send.                         |
| `senderId`       | `string or null`  | Social platform (e.g. Instagram) ID of the sender.                                             |
| `recipientId`    | `string`          | Social platform (e.g. Instagram) ID of the recipient.                                          |
| `text`           | `string`          | Message text.                                                                                  |
| `payload`        | `object or null`  | Rich content on the message. See [Payload](#payload).                                          |
| `status`         | `string`          | Message status. See [Status Values](#status-values).                                           |
| `errorCode`      | `integer or null` | Set only when status is `failed`. See [Messaging Errors](/support/errors.md#messaging-errors). |
| `errorMessage`   | `string or null`  | Set only when status is `failed`.                                                              |
| `createdAt`      | `string`          | ISO 8601 timestamp when the message was created.                                               |

### Payload

`payload` is `null` on a plain-text message. Otherwise it holds one or more of:

| Field          | Type     | Description                                                                                                                                                                                       |
| -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `attachment`   | `object` | Buttons you attached to an outgoing message. See [Buttons](#buttons).                                                                                                                             |
| `quickReplies` | `array`  | Quick-reply chips you attached to an outgoing message. See [Quick Replies](#quick-replies).                                                                                                       |
| `selection`    | `object` | Set on an incoming message where the person tapped a postback button or a quick reply. Holds `type` (`postback` or `quick-reply`) and your `payload` string. See [Reading a Tap](#reading-a-tap). |

### Status Values

An outgoing message you send moves through `queued`, `processing`, then `sent`, or `failed` if it does not go through. An incoming message you receive shows as `delivered`.

| Status       | Meaning                               |
| ------------ | ------------------------------------- |
| `queued`     | Accepted and waiting to send.         |
| `processing` | Sending to the social platform.       |
| `sent`       | Handed to the social platform.        |
| `delivered`  | An incoming message delivered to you. |
| `failed`     | Did not send. See `errorMessage`.     |

### Rate Limits

| Endpoint                             | Limit    |
| ------------------------------------ | -------- |
| `GET /conversations`                 | 60 / min |
| `GET /conversations/:conversationId` | 60 / min |
| `GET /messages`                      | 60 / min |
| `GET /messages/:messageId`           | 60 / min |
| `POST /messages`                     | 30 / min |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.blotato.com/api/messages.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
