# Facebook

Publish feed posts, multi-image posts, link carousels, Stories and Reels to Facebook Pages, and run Messenger DMs, comments and Page reviews.

Connect a Facebook Page and you can publish text, photos, videos, link carousels, Stories and Reels, save drafts to Facebook's own Publishing Tools, and post to several Pages from one connection. The same account runs Messenger conversations, comments, Page reviews and comment-to-DM automations, and reads Page insights. The platform id is `facebook`.

## What you can do

| Capability | Supported | Where |
| --- | --- | --- |
| Publish | Text, up to 10 images, one video or GIF, link carousels, Stories, Reels, text on a colour background | [Create a post](https://pozy.ai/docs/publishing) |
| Schedule | Yes | [Scheduling](https://pozy.ai/docs/publishing/scheduling) |
| Edit after publishing | Text, or remove the post with [Unpublish](https://pozy.ai/docs/api/unpublishPost) | [Edit published posts](https://pozy.ai/docs/publishing/editing) |
| Analytics | Post metrics, Page insights, demographics, reactions by type, post earnings | [Platform insights](https://pozy.ai/docs/analytics/platform-insights) |
| DMs (Messenger) | Read and reply, attachments, quick replies, buttons, cards, reactions, message requests | [Messages](https://pozy.ai/docs/inbox/messages) |
| Comments | List, reply, like, hide, delete, private reply | [Comments](https://pozy.ai/docs/inbox/comments) |
| Reviews | List and reply to Page recommendations | [Reviews](https://pozy.ai/docs/inbox/reviews) |
| Automations | Comment to DM, welcome screen, persistent menu | [Automations](https://pozy.ai/docs/automations) |
| Ads | Same connection can run Meta Ads and lead forms | [Meta Ads](https://pozy.ai/docs/ads/meta-ads) |

## Connect

Facebook posts as a **Page**. Personal profiles cannot publish through the API, and the person connecting must be an admin or editor of the Page.

Start with [`GET /v1/connect/facebook`](https://pozy.ai/docs/api/getConnectUrl) and a `profileId`. After Facebook's consent screen the user picks which Page to connect. Pozy hosts that picker by default; to build it into your own UI, use headless mode with [List Facebook pages](https://pozy.ai/docs/api/listFacebookPages) and [Select Facebook page](https://pozy.ai/docs/api/selectFacebookPage). See [Headless connect](https://pozy.ai/docs/connect/headless).

The consent screen also asks for ads permissions, so the same connection can drive [Meta Ads](https://pozy.ai/docs/ads/meta-ads) and lead forms. Pass `scopes` to ask for fewer areas. A connection limited to analytics is read-only: it cannot change the Page, and the Page receives no webhooks, so inbox events stop.

> **Facebook sessions expire often:**
> 
> Facebook ends sessions more often than most platforms (password changes, security checks, removed Page roles). Subscribe to [`account.disconnected`](https://pozy.ai/docs/webhooks/events#account-disconnected) and send the user a reconnect link when it fires.

### Several Pages on one connection

One connection can manage every Page the user administers. List them with [List Facebook pages](https://pozy.ai/docs/api/getFacebookPages) (add `refresh=true` to re-read from Facebook, at most once a minute). Then either:

- set `pageId` in `platformSpecificData` on each entry, repeating the same `accountId` once per Page, or
- change the default Page with [Update Facebook page](https://pozy.ai/docs/api/updateFacebookPage) so entries without `pageId` go there.

```json
"platforms": [
  { "platform": "facebook", "accountId": "6720c1a94f3b2e0018d4a7f4", "platformSpecificData": { "pageId": "108236514520117" } },
  { "platform": "facebook", "accountId": "6720c1a94f3b2e0018d4a7f4", "platformSpecificData": { "pageId": "214590882231054" } }
]
```

## Post types

A plain request makes a feed post. Facebook is one of the few platforms that accepts text with no media at all.

```bash cURL
curl -X POST https://api.pozy.ai/v1/posts \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Doors open at 9 this Saturday. First 50 visitors get a free tote.",
    "mediaItems": [{ "type": "image", "url": "https://cdn.example.com/open-day.jpg" }],
    "platforms": [{
      "platform": "facebook",
      "accountId": "6720c1a94f3b2e0018d4a7f4",
      "platformSpecificData": { "firstComment": "Directions: https://example.com/visit" }
    }],
    "publishNow": true
  }'
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/posts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.POZY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    content: "Doors open at 9 this Saturday. First 50 visitors get a free tote.",
    mediaItems: [{ type: "image", url: "https://cdn.example.com/open-day.jpg" }],
    platforms: [{
      platform: "facebook",
      accountId: "6720c1a94f3b2e0018d4a7f4",
      platformSpecificData: { firstComment: "Directions: https://example.com/visit" },
    }],
    publishNow: true,
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);

console.log(data.post.platforms[0].platformPostUrl);
```
```python Python
import os, requests

resp = requests.post(
    "https://api.pozy.ai/v1/posts",
    headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
    json={
        "content": "Doors open at 9 this Saturday. First 50 visitors get a free tote.",
        "mediaItems": [{"type": "image", "url": "https://cdn.example.com/open-day.jpg"}],
        "platforms": [{
            "platform": "facebook",
            "accountId": "6720c1a94f3b2e0018d4a7f4",
            "platformSpecificData": {"firstComment": "Directions: https://example.com/visit"},
        }],
        "publishNow": True,
    },
)
print(resp.json()["post"]["platforms"][0]["platformPostUrl"])
```

| Post type | How to send it |
| --- | --- |
| Text | `content` only |
| Photo or multi-photo | Up to 10 images in `mediaItems`. Images and videos cannot be mixed. |
| Video or GIF | One item. Send a GIF as `type: "video"` and Facebook loops it. |
| Link carousel | Images plus `facebookSettings.carouselCards` |
| Text on a colour background | `facebookSettings.textFormatPresetId` on a text-only post |
| Story | `contentType: "story"` with one image or video |
| Reel | `contentType: "reel"` with one vertical video, optional `title` |
| Draft in Facebook | `facebookSettings.draft: true` |

### Link carousel

Each card is one image with its own link and headline. `carouselCards` must have one entry per image in `mediaItems` (2 to 10, images only). `carouselLink` sets the "See more" card at the end and defaults to the first card's link. Facebook shows about 35 characters of `name` and 30 of `description`; the API accepts up to 255 and truncates on display.

```json
{
  "content": "New arrivals this week",
  "mediaItems": [
    { "type": "image", "url": "https://cdn.example.com/chair.jpg" },
    { "type": "image", "url": "https://cdn.example.com/lamp.jpg" }
  ],
  "platforms": [{ "platform": "facebook", "accountId": "6720c1a94f3b2e0018d4a7f4" }],
  "facebookSettings": {
    "carouselLink": "https://shop.example.com/new",
    "carouselCards": [
      { "link": "https://shop.example.com/chair", "name": "Oak lounge chair", "description": "Ships in 3 days" },
      { "link": "https://shop.example.com/lamp", "name": "Brass floor lamp", "description": "Back in stock" }
    ]
  },
  "publishNow": true
}
```

`facebookSettings` can sit at the top level of the request (applies to every Facebook entry) or in an entry's `platformSpecificData` (wins for that entry).

### Stories and Reels

- **Story** (`contentType: "story"`): media is required, the caption is not shown, it disappears after 24 hours, and interactive stickers are not available.
- **Reel** (`contentType: "reel"`): one 9:16 video of 3 to 60 seconds. `content` is the caption and `title` is a separate Reel title.

### Drafts in Facebook Publishing Tools

`facebookSettings.draft: true` saves an unpublished draft in the Page's Publishing Tools, for teams who approve inside Facebook. It works for feed posts and Reels, not Stories. Facebook deletes drafts after about 30 days, and `firstComment` is skipped on drafts. For approvals inside Pozy, see [Drafts and approvals](https://pozy.ai/docs/publishing/drafts-approvals).

### Platform fields

Schema: `FacebookPlatformData`, plus `FacebookSettings`.

| Field | Notes |
| --- | --- |
| `contentType` | `story` or `reel`. Leave out for feed posts. |
| `title` | Reel title. Reels only. |
| `firstComment` | Posted right after publishing. Feed posts and Reels. |
| `pageId` | Target Page when the connection manages several. |
| `geoRestriction.countries` | Up to 25 uppercase ISO country codes. Only people in those countries can see the post. Feed posts, videos and Reels. |
| `facebookSettings.draft` | Save as a Publishing Tools draft. |
| `facebookSettings.carouselCards`, `carouselLink` | Link carousel. Cannot be combined with `contentType`. |
| `facebookSettings.textFormatPresetId` | Facebook's numeric preset id for a colour background. Text-only feed posts; rejected with `400` when media, cards or `contentType` are present or `content` is empty. Facebook's own composer stops offering backgrounds around 130 characters, so longer text publishes with a warning. |

## Media requirements

Pozy converts WebP images to JPEG before upload. Media URLs must be public HTTPS with no login and no redirects; cloud-drive sharing links usually fail.

**Images**

| | Feed | Story |
| --- | --- | --- |
| Formats | JPEG, PNG, GIF | JPEG, PNG |
| Max size | 4 MB | 4 MB |
| Count | Up to 10 | 1 |
| Recommended | 1200 x 630 | 1080 x 1920 |

**Videos**

| | Feed video | Reel | Story |
| --- | --- | --- | --- |
| Formats | MP4, MOV (H.264) | MP4, MOV | MP4, MOV |
| Max size | 4 GB | 4 GB | 4 GB |
| Duration | 1 second to 240 minutes | 3 to 60 seconds | 1 to 120 seconds |
| Shape | 1280 x 720 minimum | 9:16, required | 1080 x 1920 |

**Custom video covers.** Set `thumbnail` on the video item (an image URL up to 10 MB). It works for feed videos and Reels. It is best effort: if Facebook refuses it, the video publishes with Facebook's automatic cover and no error.

## Limits

| Limit | Value |
| --- | --- |
| Post text | 63,206 characters. About 480 show before "See more". |
| Images per post | 10 |
| Videos per post | 1 |
| Geo-restriction | 25 countries |
| Carousel cards | 2 to 10 |

The API cannot post to personal profiles or Groups, create Events, go live, add Story stickers, or target organic posts by age, gender or interest (country restriction is supported).

## Analytics

[`GET /v1/analytics?platform=facebook`](https://pozy.ai/docs/api/getAnalytics) returns `impressions`, `likes`, `comments`, `shares`, `clicks` and `views` per post, plus `engagementRate`. `likes` is the total of all reactions.

| Endpoint | What you get |
| --- | --- |
| [Page insights](https://pozy.ai/docs/api/getFacebookPageInsights) | Page-level media views, engagements, video metrics and followers over up to 89 days (default 30). `followers_gained` and `followers_lost` come from daily snapshots. |
| [Page demographics](https://pozy.ai/docs/api/getFacebookDemographics) | Follower breakdowns for the Page. |
| [Post reactions](https://pozy.ai/docs/api/getFacebookPostReactions) | A count per reaction type for one post. |
| [Post earnings](https://pozy.ai/docs/api/getFacebookPostEarnings) | Lifetime monetization earnings for one post, read live. There is no date range, so never add up totals across dates. Pages without monetization return `0`. |
| [Visitor posts](https://pozy.ai/docs/api/listFacebookVisitorPosts) and [tagged posts](https://pozy.ai/docs/api/listFacebookTaggedPosts) | Posts other people made on or about the Page. |

Image URLs in analytics responses are served from Pozy storage and do not expire.

## Inbox

**Messenger DMs.** Read conversations and reply with [Send message](https://pozy.ai/docs/api/sendInboxMessage): text, images, video, audio, files, up to 13 quick replies, up to 3 buttons (text 640 characters or less) and carousels of up to 10 cards (`imageAspectRatio: "square"` for 1:1 card images). React to messages, archive conversations, and list and accept message requests (`folder=requests`).

> **The 24-hour window:**
> 
> Messenger lets you message someone freely for 24 hours after their last message. After that, a reply typed by a person can still go out for up to 7 days with `messagingType: "MESSAGE_TAG"` and `messageTag: "HUMAN_AGENT"`. Automated messages cannot use the tag, so workflows and broadcasts reject it. The other message tags were retired by Facebook in April 2026 and fail.

When another app (such as Facebook's Page Inbox) owns a thread, inbound messages arrive with `metadata.standby: true`, Pozy automations stay quiet and sends return `409` `not_thread_owner`. Hand the thread over with [thread control](https://pozy.ai/docs/api/setConversationThreadControl).

On connect, Pozy imports the Page's existing Messenger history (up to 500 conversations, newest 500 messages each), in the background, already read, with no webhooks.

**Welcome screen and menu.** Set the greeting text (160 characters, per locale), the Get Started button, up to 4 ice breakers per locale and a persistent menu (3 top-level items, 5 nested). Facebook only shows the menu on Pages with a Get Started button. A tap sends a postback that arrives as `message.received` with `metadata.postbackPayload`; a payload of `pozy:workflow:<workflowId>` starts that workflow. See [Conversation starters](https://pozy.ai/docs/automations/conversation-starters).

**Comments.** List, reply, like, hide, unhide and delete, and send one private reply per comment within 7 days. Comment-to-DM automations can like or hide the matched comment and send a product card.

**Reviews.** List the Page's recommendations and reply to them with the [Reviews](https://pozy.ai/docs/inbox/reviews) endpoints.

**Page info.** Read and update the Page's public details (about, description, website, phone, emails, hours) with [Get](https://pozy.ai/docs/api/getFacebookPageInfo) and [Update a Facebook Page's public info](https://pozy.ai/docs/api/updateFacebookPageInfo). Only the fields you send change.

## Errors you may see

| Message | Cause | Fix |
| --- | --- | --- |
| Photos should be smaller than 4MB and saved as JPG or PNG | Image over 4 MB or unsupported format | Resize to under 4 MB as JPEG or PNG. |
| Missing or invalid image file | Facebook could not read the image | Open the URL in a private window; use JPEG or PNG. |
| Unable to fetch video file from URL | Facebook could not download the video | Use a direct public URL or [upload the file](https://pozy.ai/docs/publishing/media). |
| Facebook tokens expired. Please reconnect. | The session ended | Reconnect the account. |
| Confirm your identity before you can publish as this Page | Facebook's security check on the Page | Open the Page in the Facebook app and complete the check. |
| `not_thread_owner` (`409`) | Another app owns the conversation | Take or request thread control. |

A rejected `publishNow: true` post returns `207` with `post.status: "failed"`; `platforms[].errorMessage`, `errorCategory` and `errorSource` explain why.

## Endpoints

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/connect/facebook/select-page`](https://pozy.ai/docs/api/listFacebookPages) | List Facebook pages |
| [`POST /v1/connect/facebook/select-page`](https://pozy.ai/docs/api/selectFacebookPage) | Select Facebook page |
| [`GET /v1/accounts/{accountId}/facebook-page`](https://pozy.ai/docs/api/getFacebookPages) | List Facebook pages |
| [`PUT /v1/accounts/{accountId}/facebook-page`](https://pozy.ai/docs/api/updateFacebookPage) | Update Facebook page |
| [`GET /v1/accounts/{accountId}/facebook-page-info`](https://pozy.ai/docs/api/getFacebookPageInfo) | Get a Facebook Page's public info |
| [`PATCH /v1/accounts/{accountId}/facebook-page-info`](https://pozy.ai/docs/api/updateFacebookPageInfo) | Update a Facebook Page's public info |
| [`GET /v1/analytics/facebook/page-insights`](https://pozy.ai/docs/api/getFacebookPageInsights) | Get Facebook Page insights |
| [`GET /v1/analytics/facebook/demographics`](https://pozy.ai/docs/api/getFacebookDemographics) | Get Facebook Page demographics |
| [`GET /v1/accounts/{accountId}/facebook-post-reactions`](https://pozy.ai/docs/api/getFacebookPostReactions) | Get Facebook post reactions |
| [`GET /v1/analytics/facebook/post-earnings`](https://pozy.ai/docs/api/getFacebookPostEarnings) | Get Facebook post monetization earnings |
| [`GET /v1/accounts/{accountId}/facebook-visitor-posts`](https://pozy.ai/docs/api/listFacebookVisitorPosts) | List visitor posts on a Facebook Page |
| [`GET /v1/accounts/{accountId}/facebook-tagged-posts`](https://pozy.ai/docs/api/listFacebookTaggedPosts) | List the posts a Facebook Page is tagged in |
| [`GET /v1/accounts/{accountId}/messenger-menu`](https://pozy.ai/docs/api/getMessengerMenu) | Get persistent menu |
| [`PUT /v1/accounts/{accountId}/messenger-menu`](https://pozy.ai/docs/api/setMessengerMenu) | Set persistent menu |
| [`GET /v1/accounts/{accountId}/messenger-greeting`](https://pozy.ai/docs/api/getMessengerGreeting) | Get FB greeting text |
| [`PUT /v1/accounts/{accountId}/messenger-greeting`](https://pozy.ai/docs/api/setMessengerGreeting) | Set FB greeting text |
| [`GET /v1/accounts/{accountId}/messenger-get-started`](https://pozy.ai/docs/api/getMessengerGetStarted) | Get FB Get Started button |
| [`PUT /v1/accounts/{accountId}/messenger-get-started`](https://pozy.ai/docs/api/setMessengerGetStarted) | Set FB Get Started button |
| [`GET /v1/accounts/{accountId}/messenger-ice-breakers`](https://pozy.ai/docs/api/getMessengerIceBreakers) | Get FB ice breakers |
| [`PUT /v1/accounts/{accountId}/messenger-ice-breakers`](https://pozy.ai/docs/api/setMessengerIceBreakers) | Set FB ice breakers |
| [`GET /v1/accounts/{accountId}/webhook-subscription`](https://pozy.ai/docs/api/getPageWebhookSubscription) | Read a Facebook Page's webhook subscription |
| [`POST /v1/accounts/{accountId}/webhook-subscription`](https://pozy.ai/docs/api/resyncPageWebhookSubscription) | Re-subscribe a Facebook Page to Pozy's webhooks |

## Webhook events

| Event | When it fires |
| --- | --- |
| [`post.published`](https://pozy.ai/docs/webhooks/events#post-published) | Post published. |
| [`post.failed`](https://pozy.ai/docs/webhooks/events#post-failed) | Post failed. |
| [`post.platform.published`](https://pozy.ai/docs/webhooks/events#post-platform-published) | Post platform published. |
| [`post.platform.failed`](https://pozy.ai/docs/webhooks/events#post-platform-failed) | Post platform failed. |
| [`post.platform.deleted`](https://pozy.ai/docs/webhooks/events#post-platform-deleted) | Post platform deleted. |
| [`account.disconnected`](https://pozy.ai/docs/webhooks/events#account-disconnected) | Account disconnected. |
| [`message.received`](https://pozy.ai/docs/webhooks/events#message-received) | Message received. |
| [`conversation.control_changed`](https://pozy.ai/docs/webhooks/events#conversation-control-changed) | Conversation control changed. |
| [`conversation.started`](https://pozy.ai/docs/webhooks/events#conversation-started) | Conversation started. |
| [`message.sent`](https://pozy.ai/docs/webhooks/events#message-sent) | Message sent. |
| [`message.edited`](https://pozy.ai/docs/webhooks/events#message-edited) | Message edited. |
| [`message.deleted`](https://pozy.ai/docs/webhooks/events#message-deleted) | Message deleted. |
| [`message.delivered`](https://pozy.ai/docs/webhooks/events#message-delivered) | Message delivered. |
| [`message.read`](https://pozy.ai/docs/webhooks/events#message-read) | Message read. |
| [`message.played`](https://pozy.ai/docs/webhooks/events#message-played) | Message played. |
| [`message.failed`](https://pozy.ai/docs/webhooks/events#message-failed) | Message delivery failed. |
| [`reaction.received`](https://pozy.ai/docs/webhooks/events#reaction-received) | Reaction received. |
| [`comment.received`](https://pozy.ai/docs/webhooks/events#comment-received) | Comment received. |
| [`review.new`](https://pozy.ai/docs/webhooks/events#review-new) | Review new. |
| [`review.updated`](https://pozy.ai/docs/webhooks/events#review-updated) | Review updated. |
| [`review.deleted`](https://pozy.ai/docs/webhooks/events#review-deleted) | Review deleted. |
| [`review.restored`](https://pozy.ai/docs/webhooks/events#review-restored) | Review restored. |
| [`lead.received`](https://pozy.ai/docs/webhooks/events#lead-received) | Lead received. |
