Getting started
Connect an Instagram account, a Facebook Page or an X account with messaging permissions, receive an inbound DM, and send your first reply.
This guide uses an Outstand API key and either an Instagram Business or Creator account, a Facebook Page, or an X account. Keep your API key on your backend; see Authentication.
Reading messages and sending replies work the same way on all three networks: the same endpoints, the same webhooks, the same message objects. What differs is the connection step, because each network names its messaging permission differently, and the reply window - Instagram and Facebook give you 24 hours from the contact's last inbound message, while X has none.
1. Connect with messaging access
Create a connection using the authentication URL endpoint and pass the scopes field in the JSON body. It is a comma-separated list, and it replaces the network's default scopes rather than adding to them, so include the defaults as well as the messaging permissions.
Messaging is not requested by default on any of the three networks, so an account connected without the scopes below - including every account connected from the Outstand dashboard - stays silent.
Include the four default scopes as well as instagram_business_manage_messages:
curl -X POST https://api.outstand.so/v1/social-networks/instagram/auth-url \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"redirect_uri": "https://your-app.example.com/social/callback",
"scopes": "instagram_business_basic,instagram_business_content_publish,instagram_business_manage_comments,instagram_business_manage_insights,instagram_business_manage_messages"
}'A list with only instagram_business_basic,instagram_business_manage_messages produces a messaging-only connection: publishing, comments and insights stop working for that account.
| Scope | Needed for |
|---|---|
instagram_business_basic | Profile access. Always required. |
instagram_business_content_publish | Publishing posts, Reels, carousels and Stories |
instagram_business_manage_comments | Reading and replying to comments |
instagram_business_manage_insights | Post and account analytics |
instagram_business_manage_messages | Direct Messages. Not requested by default. |
The account owner must approve access to messages on the Instagram consent screen. The account also has to be a Business or Creator account with Allow access to messages turned on, see Instagram account requirements.
Facebook Pages
Include the seven default Page scopes as well as pages_messaging and pages_manage_metadata:
curl -X POST https://api.outstand.so/v1/social-networks/facebook/auth-url \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"redirect_uri": "https://your-app.example.com/social/callback",
"scopes": "pages_read_user_content,business_management,pages_show_list,pages_manage_posts,pages_read_engagement,pages_manage_engagement,read_insights,pages_messaging,pages_manage_metadata"
}'| Scope | Needed for |
|---|---|
pages_messaging | Direct Messages: sending a reply, and receiving the contact's messages. Not requested by default. |
pages_manage_metadata | Subscribing the Page to Outstand, which is what delivers its messages and its comments. Not requested by default. |
The seven scopes ahead of them are Facebook's defaults, covering Page listing, publishing, engagement and insights; see Quick Information for what each one does. Leaving one out removes that capability from the connection, the same way it does on Instagram.
A Facebook connection ends with the user choosing which of their Pages to connect, so it finishes through the pending-connection flow: read the pending connection, show a picker, then finalize. Outstand subscribes the Pages handed to that final call, so a Page the user does not select stays unsubscribed even though the permissions were granted.
X
Include the default scopes as well as dm.read:
curl -X POST https://api.outstand.so/v1/social-networks/x/auth-url \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"redirect_uri": "https://your-app.example.com/social/callback",
"scopes": "tweet.read,tweet.write,users.read,follows.read,dm.read,dm.write,media.write,offline.access"
}'| Scope | Needed for |
|---|---|
dm.read | Receiving the contact's direct messages. Not requested by default. |
dm.write | Sending a reply. A default. |
X delivers inbound DMs through the X Activity API to a webhook on your own X app, so register Outstand's webhook URL on that app before you connect the account: see X comment webhooks and Direct Messages. Outstand subscribes an account only as it connects, so an account connected before the webhook was registered receives nothing until it is reconnected.
Which credentials each network needs
The three networks do not share an availability model, because inbound messages do not reach Outstand the same way.
On Instagram and Facebook, Direct Messages work on both Managed Keys and your own Meta app (BYOK). With Managed Keys, Outstand owns the Meta app and its webhook subscription, so there is nothing to configure at the app level. On your own Meta app, subscribe it once to the messages webhook field on its per-app callback and Outstand verifies each delivery against your own app secret: see BYOK direct message setup, and Availability for Instagram and Facebook.
On X it is the other way round: X is BYOK-only. Outstand ships no managed X app, so Direct Messages run on your own X credentials and the webhook you register on your own app. See X configuration.
When messaging permission is granted, Outstand subscribes the account to messaging webhooks as the connection completes: on Instagram in the OAuth callback, on a Facebook Page when the selected Pages are finalized, and on X when the account connects, provided the webhook is already registered on your app. This platform subscription brings DMs into Outstand. Your own Outstand webhook endpoint is a separate subscription that forwards events to your application.
Existing accounts
An account connected without the messaging scopes must be reconnected with the request above for its network before it can receive or send DMs. Reconnecting updates the existing social account in place, so its ID, scheduled posts and history are kept.
Until it is reconnected, Outstand is not subscribed to the account's messages: no conversations are created for it, GET /v1/conversations returns nothing for it, and no conversation.started or message.received webhooks fire. There is no error; the account simply stays silent.
The dashboard requests the default scopes only, so reconnecting there does not enable messaging, and reconnecting a messaging-enabled account there (or with a scopes list that omits the messaging scopes) removes it.
If a reply is sent from an account whose token lacks the permission, the request is still accepted with 202, and delivery then fails: the message's status becomes failed, a message.failed webhook fires, and its error field carries the network's rejection. On a Meta network that takes the form Instagram send failed: <HTTP status> <error body>, or Facebook send failed: <HTTP status> <error body> on a Page; on X it carries X's own error code and message.
2. Receive an inbound message
Send a DM to the connected account: from another Instagram account, from a personal Facebook account to the Page, or from another X account. Neither Meta network lets a business message someone first, so on Instagram and Facebook conversations are created from incoming platform events, or when you start one by answering a comment privately. X has no such limit, so on X you can also start one by addressing the contact directly.
List the connected account's conversations:
curl 'https://api.outstand.so/v1/conversations?social_account_id=YOUR_SOCIAL_ACCOUNT_ID&limit=25' \
-H "Authorization: Bearer YOUR_API_KEY"Use an id from the response's data array as CONVERSATION_ID below. An empty list means no matching conversations have been ingested yet. Check that the account was connected with its messaging scopes in scopes (see Existing accounts) and send a fresh inbound DM.
3. Read the messages
curl 'https://api.outstand.so/v1/conversations/CONVERSATION_ID/messages?limit=50' \
-H "Authorization: Bearer YOUR_API_KEY"The response's data array contains messages, newest first. Each message includes its direction and status. Follow pagination.nextCursor while pagination.hasMore is true to fetch additional pages.
4. Send a reply
On Instagram and Facebook, reply within 24 hours of the contact's last inbound message. On X there is no window, as long as the contact's DM settings accept messages from the account:
curl -X POST https://api.outstand.so/v1/conversations/CONVERSATION_ID/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Hello! How can I help you today?"}'A successful request returns 202 Accepted, with a message object whose status is pending. Store its id to correlate delivery updates. Acceptance does not mean the recipient has received the reply.
Subscribe to message.sent and message.failed in webhook settings, or poll the message list and find the stored message ID. See Message lifecycle and webhooks for scheduling, media attachments, and error handling.
5. Mark the conversation as read
When the account owner reads the conversation in your inbox, call:
curl -X POST https://api.outstand.so/v1/conversations/CONVERSATION_ID/read \
-H "Authorization: Bearer YOUR_API_KEY"This marks inbound messages as read, resets unreadCount to zero, and sends a read receipt on the network. Fetching the message list alone does not mark it as read.
Keep your inbox updated
Subscribe to conversation.started, message.received, message.sent, and message.failed. Use the event's conversation and message IDs to refresh the relevant thread. Follow the shared webhook setup and signature verification guide and the messaging event reference.