> ## Documentation Index
> Fetch the complete documentation index at: https://docs.social-api.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Base URL: https://api.social-api.ai/v1. Send your API key in the Authorization header: Authorization: Bearer <your API key>.
> Every error response from /v1 is JSON: { "error": { "code", "message", "meta" (optional) }, "request_id" }. Branch on error.code; use error.message only for logs.
> A 429 response carries a Retry-After header, in seconds, when the limit has a known wait.
> Paginated list endpoints return next_cursor, at the top level or inside pagination (see /guides/pagination). Pass it as the cursor query parameter to get the next page. An absent or empty next_cursor means you have the last page.
> Treat every ID as an opaque string: do not parse it or assume a format.
> Support differs by platform and by operation. Check /platforms/overview before assuming an operation works on a platform. An unsupported operation returns 501 with error.code resource.not_supported.

# Facebook API

> Connect Facebook Pages to publish posts and Reels, moderate comments, send private replies and Messenger DMs, and read mentions through one API.

The Facebook API in SocialAPI connects Facebook Pages. It publishes text, link, photo, video, album, Reel, and Story posts, reads and moderates comments, sends private replies and Messenger direct messages (DMs), and reads mentions. SocialAPI's own Meta app connects the Pages, so you register nothing: see [Platform apps](/guides/platform-credentials). A Facebook profile is not supported: only Pages.

## At a glance

| Field | Value |
| - | - |
| Platform slug | `facebook` |
| Auth | OAuth 2.0 (Meta), one login for every Page the person manages |
| Platform API | Meta Graph API (Facebook Pages and Messenger) |
| Status | Available |

## Capabilities

An unsupported call returns `501 resource.not_supported`.

| Feature | Status | Condition |
| - | - | - |
| Publish text, link, photo, video, multi-photo album, Reel, Story | Yes | See [Facebook publishing](/platforms/facebook/publishing) |
| Schedule a post | Yes | `scheduled_at` on the post |
| First comment on a post | Yes | Not on a Story |
| Update a published post | No | `PATCH /v1/posts/{pid}` returns `409 post.state_invalid` for a published post. A `draft`, `scheduled`, or `failed` post can be edited before it publishes. To correct it, delete the post with `DELETE /v1/posts/{pid}` and publish a new one |
| Delete a published post | Yes | |
| List posts | Yes | Posts in the Page feed. List posts does not return a Reel, even when `share_to_feed` is `true` |
| List comments and replies | Yes | Comments are read per post |
| Reply to a comment | Yes | |
| Hide, unhide, delete a comment | Yes | |
| Like or unlike a comment | Yes | The Page likes the comment |
| Private reply to a comment | Yes | One per comment, within 7 days of the comment |
| DMs: list, read, send | Yes | Inside the 24-hour messaging window. Text and attachments. A send ignores `quick_replies`, `buttons`, and `cards` |
| React to a DM | Yes | |
| Mentions | Partial | `GET /v1/accounts/{id}/mentions` returns posts that tag the Page. A mention in a comment arrives as a `mention.received` event |
| Reply to a mention | Yes | A public comment on the mention |
| Reviews | No | SocialAPI does not read Facebook reviews: Meta deprecated Page recommendations in Graph API v22.0. `GET /v1/inbox/reviews/{account_id}` returns `422 account.platform_unsupported` |
| Automations | Yes | Comment and DM triggers, buttons on the first private reply, multi-step flows. A `send_dm` action delivers no buttons. No `follows_account` filter and no Follow gate: `400 validation.filter_unsupported` |
| Analytics | Yes | See [Analytics](/guides/analytics) |
| Page insights | Yes | `GET /v1/platforms/facebook/accounts/{id}/summary` (trailing 30 days) and `GET /v1/platforms/facebook/accounts/{id}/insights/daily`. Needs `read_insights`: see [Page insights](#page-insights) |
| Webhook events | Yes | See [Webhook events](#webhook-events) |

The cross-platform matrix is on [Platforms](/platforms/overview).

## Connect an account

Connect with `POST /v1/accounts/connect` and `"platform": "facebook"`. The shared flow, request fields, and result are in [Connect accounts](/guides/connect-accounts), and the redirect parameters are in [Redirect parameters](/guides/connect-accounts#redirect-parameters).

```bash theme={null}
curl -X POST https://api.social-api.ai/v1/accounts/connect \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "facebook",
    "redirect_uri": "https://app.example.com/oauth/callback",
    "state": "session_abc123"
  }'
```

Response (HTTP 202):

```json theme={null}
{
  "auth_url": "https://www.facebook.com/v25.0/dialog/oauth?client_id=...&state=...",
  "state": "4a8f2c1e9b3d7f06a5c2e8b4d1f3a7e2",
  "message": "Open this link to connect your facebook account. Once you've authorized, the account will be connected automatically."
}
```

After the person authorizes, the redirect carries `status=success` and the brand's Facebook account. That account holds every Page the login granted that none of your other brands already holds. A Page that another of your brands holds stays with that brand.

* A login that grants no Page ends with `status=error` and `error=platform.facebook.no_pages` on your `redirect_uri`.
* A login whose every Page belongs to another of your brands ends with `status=error` and `error=platform.facebook.no_assignable_pages`.
* A brand whose Facebook account is connected through a different login ends with `status=error` and `error=account.different_login`. Disconnect the brand's Facebook account first.
* Reconnecting the same login refreshes the access for every brand that uses it, not only the brand you reconnected from.

### Pages of an account

List the Pages of a connected account with `GET /v1/accounts/{id}/pages`. Each Page has at least an `id` (`sapi_page_` prefix), `platform_page_id`, `name`, `is_default`, and `is_active`. A Page also carries `profile_picture_url`, `category`, `followers_count`, `username`, `link`, `verification_status`, `cover_photo_url`, `about`, and `enriched_at`, each omitted when it has no value. Publish to a Page with `page_id` on the post target: see [Delivery](/guides/delivery). `PATCH /v1/accounts/{id}/pages/{pageId}` sets `is_default` or `is_active`.

### One login, many brands

A Facebook login is a shared credential. One login can serve many brands, and each Page belongs to exactly one brand. List the Pages a login can manage, live from Facebook, with the brand that holds each:

```bash theme={null}
curl "https://api.social-api.ai/v1/platforms/facebook/logins/cred_01J8X3Q4R5M6N7P8V2K0W1J/pages" \
  -H "Authorization: Bearer $SOCAPI_KEY"
```

Response (HTTP 200):

```json theme={null}
{
  "login_id": "cred_01J8X3Q4R5M6N7P8V2K0W1J",
  "pages": [
    {
      "platform_page_id": "104857392011223",
      "name": "Acme Bakery",
      "assignable": true
    }
  ],
  "count": 1
}
```

| Field | Description |
| - | - |
| `login_id` | The login you asked about |
| `pages[].platform_page_id`, `name` | Facebook's Page ID and the Page's name |
| `pages[].picture_url`, `category` | The Page's picture and category. Each is omitted when Facebook returns none |
| `pages[].assignable` | `true` when no brand holds the Page. `false` when a brand holds it: `assigned_brand_id`, `assigned_brand_name`, and `assigned_account_id` then name it |
| `count` | The number of Pages in `pages` |

`login_id` is on each connected account. Move a Page to a brand with `POST /v1/platforms/facebook/logins/{loginId}/pages/{pageId}/assign`. A Page that another of your brands holds moves to the target brand. The call needs the `accounts:manage` scope.

```bash theme={null}
curl -X POST "https://api.social-api.ai/v1/platforms/facebook/logins/cred_01J8X3Q4R5M6N7P8V2K0W1J/pages/104857392011223/assign" \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"brand_id": "7d2e4b1a-9c3f-4e5d-8a6b-1f2e3d4c5b6a"}'
```

Response (HTTP 201):

```json theme={null}
{
  "account_id": "acc_01HZ9X3Q4R5M6N7P8V2K0W1J",
  "brand_id": "7d2e4b1a-9c3f-4e5d-8a6b-1f2e3d4c5b6a",
  "platform_page_id": "104857392011223"
}
```

| HTTP | Code | When it occurs |
| - | - | - |
| 400 | `validation.field_required` | The body has no `brand_id` |
| 400 | `validation.page_not_granted` | The Page is not accessible through this login |
| 404 | `resource.not_found` | The login does not exist |
| 404 | `brand.not_found` | The brand does not exist or your key cannot reach it |
| 409 | `account.different_login` | The brand's Facebook account uses a different login |

## Comments

List comments on a post with `GET /v1/inbox/comments/{postId}`, where `postId` is the post's platform ID. Reply, hide, unhide, delete, like, and unlike work as described in [Comments](/guides/comments).

* **Edited comments.** Facebook sends an edited comment again, as another `comment.received` event. Automations ignore edits and answer new comments only.
* **Page admins.** An [Automation](/guides/automations) skips comments and messages from the Page itself. A Page admin who comments from a personal profile is a commenter like any other, so the comment triggers the Automation.

## Private replies

A private reply sends a one-time DM to the person who commented. Send it with `POST /v1/inbox/comments/{postId}/{commentId}/private-reply`. Facebook allows one private reply per comment, within 7 days of the comment. A second reply, or a comment older than 7 days, returns `400 platform.facebook.private_reply_ineligible`.

## Direct messages and the messaging window

A Page can message a person only inside the 24-hour messaging window that the person's last message opened. Outside it, the send returns `400 platform.facebook.window_closed`.

* **Message types.** Text and attachments. A DM send ignores `quick_replies`, `buttons`, and `cards`: it delivers only the text. Buttons work on a [private reply](/guides/comments#send-a-private-reply). Each attachment in `attachments[]` has a `source_type` (`url`, `media_id`, or `platform_attachment_id`) and a `type`. `type` is required for `platform_attachment_id`, or the request returns `400 validation.attachment_type_required`. Field rules are in [Direct messages](/guides/direct-messages).
* **Reactions.** `POST /v1/inbox/conversations/{id}/messages/{messageId}/reaction` reacts to a message, and `DELETE` on the same path removes the reaction.
* **Delivery status.** `dm.status.sent`, `dm.status.delivered`, and `dm.status.read` events follow each DM you send.
* **No message tags.** A `message_tag` on a Facebook DM, including `HUMAN_AGENT`, is not sent: the DM goes out untagged and the 24-hour window applies.

## Mentions

`GET /v1/accounts/{id}/mentions` returns the posts that tag the Page. A mention inside a comment is not in that list: it arrives as a `mention.received` event. Reply to a mention with `POST /v1/accounts/{id}/mentions/reply`, which posts a public comment. Details are in [Mentions](/guides/mentions).

## Page insights

`GET /v1/platforms/facebook/accounts/{id}/summary` returns the Page's followers, views, reach, post engagements, and net follower change over the trailing 30 days.

```bash theme={null}
curl "https://api.social-api.ai/v1/platforms/facebook/accounts/acc_01HZ9X3Q4R5M6N7P8V2K0W1J/summary" \
  -H "Authorization: Bearer $SOCAPI_KEY"
```

Response (HTTP 200):

```json theme={null}
{
  "follower_count": 12840,
  "views": 48210,
  "reach": 31975,
  "interactions": 2216,
  "net_follows": 154,
  "period_start": "2026-09-17T09:00:00Z",
  "period_end": "2026-10-17T09:00:00Z"
}
```

`interactions` counts post engagements, and `net_follows` is new follows minus unfollows over the period.

`GET /v1/platforms/facebook/accounts/{id}/insights/daily` returns one point per day, oldest first. `days` sets how many trailing days, from 1 to 365 (default 365). A day with no data is left out.

```bash theme={null}
curl "https://api.social-api.ai/v1/platforms/facebook/accounts/acc_01HZ9X3Q4R5M6N7P8V2K0W1J/insights/daily?days=2" \
  -H "Authorization: Bearer $SOCAPI_KEY"
```

Response (HTTP 200):

```json theme={null}
{
  "data": [
    {"date": "2026-10-15", "followers": 12831, "views": 1620, "reach": 1104, "interactions": 71},
    {"date": "2026-10-16", "followers": 12840, "views": 1755, "reach": 1187, "interactions": 83}
  ]
}
```

`followers` is the count at the end of the day. `views`, `reach`, and `interactions` are that day's totals.

Both routes take an optional `page_id`, the `id` from `GET /v1/accounts/{id}/pages`. Without it they report on the account's default Page. Both are free, need the `accounts:read` scope on a scoped API key, and have no MCP tool.

Both need the `read_insights` scope, requested since 2026-10-17 with the `analytics.read` permission. Post metrics in [Analytics](/guides/analytics) do not need it.

| HTTP | Code | When it occurs |
| - | - | - |
| 400 | `validation.days_invalid` | `days` is below 1 or above 365 |
| 403 | `platform.facebook.insights_scope_missing` | The Page was connected before 2026-10-17, its login declined `read_insights`, or the person who connected it does not hold the Analyze task on the Page. A reconnect fixes the first two; for the third, grant the Analyze task on Facebook, then reconnect |
| 403 | `account.permission_missing` | The account does not have the `analytics.read` [permission](/guides/permissions) |
| 404 | `account.not_found` | The account does not exist |
| 404 | `resource.not_found` | `page_id` is not an active Page of the account, or the account has no default Page |
| 501 | `resource.not_supported` | `{id}` is not a Facebook account |
| 502 | `platform.facebook.<code>` or `platform.facebook.api_error` | Facebook returned an error, where `<code>` is Meta's error code, or failed with no code: see [Errors](/guides/errors) |

## Reviews

SocialAPI does not read Facebook reviews: Meta deprecated Page recommendations in Graph API v22.0. `GET /v1/inbox/reviews/{account_id}` for a Facebook account returns `422 account.platform_unsupported`, and no other call replaces it.

## Webhook events

Facebook Pages emit these events to your webhook endpoints. Payloads are in [Webhook events](/guides/webhook-events).

| Event | When it fires |
| - | - |
| `comment.received` | A person comments on a Page post, or edits a comment |
| `mention.received` | The Page is tagged in a post or a comment |
| `dm.received` | A person sends a Messenger message |
| `dm.sent` | A message left the Page, including one sent from Meta Business Suite |
| `dm.referral` | A person opened a conversation from an ad or referral link without sending a message |
| `dm.postback` | A person tapped a button on a private reply |
| `dm.status.sent`, `dm.status.delivered`, `dm.status.read` | Facebook accepted, delivered, or showed as read a DM you sent |
| `account.connected` | You finished connecting or reconnecting the account |
| `account.disconnected` | The person revoked access on Facebook, or SocialAPI flagged the account for reconnection (`reconnect_required: true`, see `reason`) |
| `account.updated` | The account lost [permissions](/guides/permissions) you did not remove yourself (`change` is `permissions_reduced`) |
| `page.removed` | A Page was removed from the login |
| `post.published`, `post.partial`, `post.failed` | A post to this account finished: see [Delivery](/guides/delivery) |

Every `post.*` event in [Webhook events](/guides/webhook-events#posts) is emitted for this platform.

## Limits

| Limit | Value |
| - | - |
| Post text | 63,206 characters |
| Photo | 10 MB: JPEG, PNG, GIF, or WebP |
| Video | 4 GB and 240 minutes: MP4, QuickTime, or AVI |
| Multi-photo album | 2 to 10 images |
| Posts | 100 per 24 hours and 25 per hour for each Page: see [Posting velocity caps](/guides/rate-limits#posting-velocity-caps) |
| Private reply | 1 per comment, within 7 days |
| Facebook's own rate limit | `429 platform.facebook.rate_limit`. Credit rules: see [when a credit comes back](/guides/plans#when-a-credit-comes-back) |

A Page access token does not expire on its own. Reconnect only when a call returns `401 platform.facebook.auth`, for example after the person revoked access.

## Scopes

SocialAPI's Meta app requests these scopes at connect. You apply for no app review. Each scope belongs to the account [permissions](/guides/permissions) in the last column, and the consent screen asks for the scopes of the permissions you selected. The scopes marked Every account are always requested.

| Scope | Used for | Permissions |
| - | - | - |
| `pages_show_list` | List the Pages the person manages | Every account |
| `business_management` | List Pages owned through a Business Portfolio | Every account |
| `pages_read_engagement` | Read likes, comments, and shares on Page posts | Every account |
| `pages_read_user_content` | Read posts and comments that people make on the Page | `comments.read`, `comments.write` |
| `pages_manage_engagement` | Reply to, hide, delete, and like comments | `comments.write` |
| `pages_manage_metadata` | Subscribe the Page to webhook events | Every account |
| `pages_messaging` | Send and receive Messenger DMs | `messages.read`, `messages.write` |
| `pages_manage_posts` | Create, edit, and delete Page posts | `posts.write` |
| `read_insights` | [Page insights](#page-insights). A login that declines it keeps `analytics.read` | `analytics.read` |
| `public_profile` | Identify the person who connected | Every account |

Facebook asks for messages as 1 scope, covering both reading and writing, so the consent screen shows the broader scope. The account stays limited to the permissions you selected: an account connected with `messages.read` alone cannot send messages.

## Related

* [Facebook publishing](/platforms/facebook/publishing): fields, media rules, and quirks for publishing
* [Connect accounts](/guides/connect-accounts): the shared connect flow
* [Automations](/guides/automations): comment-to-DM flows
* [Platforms](/platforms/overview): the capability matrix
* [Errors](/guides/errors): every error code


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.