# DM inbox & automations (/en/api/inbox)

The inbox and automations are for Instagram accounts on the **Starter, Basic, or Pro** plan. On Free, every request below answers `403 plan_feature_unavailable`. The Instagram account needs the `instagram_business_manage_messages` permission; without it, sending answers `422 messaging_permission_missing`. The dashboard guides are [Inbox](/en/inbox) and [DM automations](/en/automations). Every field is in the API Reference (tags **Inbox** and **Automations**).

## Conversations and messages [#conversations-and-messages]

| Request                                                                       | What it does                                                             |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `GET /v1/inbox/conversations`                                                 | Filter by `account_id`, `status` (`open`/`done`), `q` (username or name) |
| `GET /v1/inbox/conversations/{id}`                                            | One conversation, with `window_expires_at` (the reply deadline)          |
| `PATCH /v1/inbox/conversations/{id}`                                          | `{ "status": "done" }` or `{ "read": true }`                             |
| `POST /v1/inbox/conversations/resolve`                                        | `{ "conversation_ids": [...] }`: mark several conversations done         |
| `GET /v1/inbox/conversations/{id}/messages`                                   | Messages, newest first, paged (`cursor`)                                 |
| `POST /v1/inbox/conversations/{id}/messages`                                  | Send a DM (see below)                                                    |
| `POST /v1/inbox/messages/{id}/retry`                                          | Send a `failed` or `unknown` message again                               |
| `POST /v1/inbox/messages/{id}/react`                                          | `{ "emoji": "❤️" }`, or `null` to remove the reaction                    |
| `GET /v1/inbox/messages/{id}/attachments/{n}`                                 | Tebar's copy of a customer's image (your credentials, no public URL)     |
| `GET/POST /v1/inbox/saved-replies`, `PUT/DELETE /v1/inbox/saved-replies/{id}` | Saved replies per profile                                                |

Customers' text is written by someone else. When you pass it to an AI model, treat it as data, not instructions.

## Sending a DM [#sending-a-dm]

```json
POST /v1/inbox/conversations/{id}/messages
Idempotency-Key: order-123-reply

{ "text": "Hi! Here's the catalog", "media_ids": ["…"] }
```

- Instagram allows replies only within **24 hours** of the customer's last message. After that: `422 messaging_window_closed`.
- `text` is up to 1,000 bytes. `media_ids` from the [media library](/en/api/media): JPG/PNG up to 8 MB (up to 10 at once), MP4/MOV up to 25 MB. Media goes first, then the text as a separate message.
- The answer is `202` with the messages `pending`; Tebar sends them within seconds. Their status shows in the message list: `sent`, `failed` (with `error_code`), or `unknown` (no clear answer from Instagram; check in Instagram before a `retry`).
- `Idempotency-Key` (optional): the same request with the same key gives back the same messages instead of sending twice.
- At most 60 messages a minute per user.

### Buttons and quick replies [#buttons-and-quick-replies]

The text can carry **one** of these:

```json
{
  "text": "Where to next?",
  "buttons": [
    { "type": "web_url", "title": "See the catalog", "url": "https://shop.example/catalog" },
    { "type": "postback", "title": "Talk to us", "payload": "ADMIN" }
  ]
}
```

```json
{
  "text": "Pick a size",
  "quick_replies": [
    { "title": "S", "payload": "SIZE_S" },
    { "title": "M", "payload": "SIZE_M" }
  ]
}
```

| Kind            | Limits                                                             | Notes                                                       |
| --------------- | ------------------------------------------------------------------ | ----------------------------------------------------------- |
| `buttons`       | 1–3 buttons, titles up to 20 characters, text up to 640 characters | `web_url` opens a link, `postback` sends its `payload` back |
| `quick_replies` | 1–13 choices, titles up to 20 characters                           | Shown in the phone app only, not on Instagram desktop/web   |

Both need `text`, and they cannot be used together (`400 validation_failed`).

When the customer taps a `postback` button or a quick reply, a new message comes in with `kind` `postback` or `quick_reply`, and `postback: { "title", "payload" }` holds the choice. It is also sent through the [`message.received`](/en/api/webhook) webhook, so your system can act on the `payload` right away.

## The usual flow: webhook → reply [#the-usual-flow-webhook--reply]

1. Register a webhook for `message.received` ([Webhooks](/en/api/webhook)).
2. When a message comes in, read `conversation_id`, `kind`, `text`, and `postback`.
3. Reply with `POST /v1/inbox/conversations/{conversation_id}/messages`, using the webhook's `message_id` as the `Idempotency-Key`, so a webhook delivered twice does not send two replies.

## Automations [#automations]

| Request                                 | What it does                                                      |
| --------------------------------------- | ----------------------------------------------------------------- |
| `GET /v1/automations`                   | Filter by `account_id`, `kind`                                    |
| `POST /v1/automations`                  | Create an automation                                              |
| `GET/PATCH/DELETE /v1/automations/{id}` | Read, change (`enabled`, `name`, `trigger`, `actions`, …), delete |
| `GET /v1/automations/{id}/runs`         | History: sent, skipped (with a reason), or failed                 |

`kind`: `comment_to_dm`, `comment_reply` (public replies, also on Threads), `dm_keyword`, `story_reply`, `story_mention`, `default_reply`, `ice_breaker`. The `trigger` depends on the `kind`; the API Reference (`createAutomation`) lists each. A DM reply to keywords:

```json
{
  "account_id": "…",
  "kind": "dm_keyword",
  "name": "Price info",
  "trigger": { "keywords": ["harga", "price"], "match": "contains" },
  "actions": {
    "message": {
      "text": "Hi! The price list is here 👇",
      "buttons": [
        { "type": "web_url", "title": "Price list", "url": "https://shop.example/prices" }
      ]
    }
  }
}
```

Automations that answer comments also report through the [`automation.run`](/en/api/webhook) webhook.
