DM inbox & automations
Read and answer Instagram DMs, send buttons and quick replies, and manage automations through the API.
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 and DM automations. Every field is in the API Reference (tags Inbox and Automations).
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
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. textis up to 1,000 bytes.media_idsfrom the media library: 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
202with the messagespending; Tebar sends them within seconds. Their status shows in the message list:sent,failed(witherror_code), orunknown(no clear answer from Instagram; check in Instagram before aretry). 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
The text can carry one of these:
{
"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" }
]
}{
"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 webhook, so your system can act on the payload right away.
The usual flow: webhook → reply
- Register a webhook for
message.received(Webhooks). - When a message comes in, read
conversation_id,kind,text, andpostback. - Reply with
POST /v1/inbox/conversations/{conversation_id}/messages, using the webhook'smessage_idas theIdempotency-Key, so a webhook delivered twice does not send two replies.
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:
{
"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 webhook.