Zernio
Zernio
Overview

Social Posting

XInstagramFacebookLinkedInTikTokYouTubePinterestRedditBlueskyThreadsGoogle Business ProfileSnapchat

Messaging

WhatsAppTelegramDiscordSlack

Telephony

Phone NumbersVoice & CallsSMS

Advertising

Meta AdsGoogle AdsLinkedIn AdsTikTok AdsPinterest AdsX AdsOpenAI Ads

Commerce

Shopify
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources

Facebook

Publish feed posts, multi-image posts, link carousels, Stories and Reels to a Facebook Page with the Zernio API, with drafts, first comments and country targeting.


Publish feed posts, multi-image posts, link carousels, Stories and Reels to a Facebook Page with POST /v1/posts and platform: "facebook". The same account also serves analytics, Messenger DMs, comments, Page reviews and comment-to-DM automations.

Quick reference

PropertyValue
Character limit63,206 (truncated at about 480 with "See more")
Images per post10
Videos per post1
Image formatsJPEG, PNG, GIF (WebP converted to JPEG)
Image max size4 MB (Facebook rejects larger files in practice)
Video formatsMP4, MOV
Video max size4 GB
Video max duration240 minutes (feed), 60 seconds (Reel), 120 seconds (Stories)
Post typesFeed (text, image, video, multi-image, link carousel), Story, Reel
SchedulingYes
Inbox (DMs)Yes
Inbox (comments)Yes
Inbox (reviews)Yes
Comment-to-DM automationsYes
AnalyticsYes

Before you start

Facebook requires a Page; personal profiles cannot post through the API, and the user must be an Admin or Editor of the Page. One connected account can manage several Pages (Post to several Pages). Facebook tokens expire frequently, so subscribe to the account.disconnected webhook.

Connect

Call GET /v1/connect/facebook with profileId on Get OAuth connect URL. After OAuth the user picks which Page to connect, in standard or headless mode; see platforms requiring secondary selection. The connecting accounts guide covers the OAuth flow and scopes in general; Account health reports what a connected account can do with the scopes the user granted.

OAuth scopes

ScopeWhat it enables
pages_show_listList the Pages the user manages during connection
pages_manage_postsCreate, edit and delete Page posts
pages_read_engagementRead Page content and engagement (also used for analytics)
read_insightsPage and post analytics (views, clicks, reach)
pages_manage_engagementManage comments on Page posts
pages_read_user_contentRead user-generated content (comments) on the Page
pages_messagingMessenger conversations in the inbox
pages_manage_metadataPage webhook subscriptions and settings
business_managementDiscover Pages owned through a Meta Business Manager

If your team has ads enabled, the consent screen also requests ads_management, ads_read, pages_manage_ads and leads_retrieval, so the same token can drive Meta Ads and lead forms. Accounts connected before ads were enabled need a reconnect to pick these up.

Publish

A plain post becomes a feed post: text on its own, up to 10 images, or 1 video. Fields in platformSpecificData on the Facebook entry select Stories and Reels; facebookSettings holds drafts, link carousels and text backgrounds and can also be sent at the request root.

Feed post

Text with an optional image. Facebook is one of the few platforms that accepts a post with no media, so mediaItems can be omitted.

import Zernio from '@zernio/node';

const zernio = new Zernio();

const { data: published } = await zernio.posts.createPost({
  body: {
    content: 'New collection in store from Monday',
    mediaItems: [
      { type: 'image', url: 'https://cdn.example.com/collection.jpg' }
    ],
    platforms: [
      { platform: 'facebook', accountId: '66b2e19d8c3f5a7e9d0b1c2d' }
    ],
    publishNow: true
  }
});

console.log(published.post.platforms[0].platformPostUrl);

Response (201):

{
  "post": {
    "_id": "65f1c0a9e2b5af0012ab34cd",
    "status": "published",
    "platforms": [
      {
        "platform": "facebook",
        "status": "published",
        "platformPostUrl": "https://www.facebook.com/..."
      }
    ]
  }
}

Every sample below changes only the mediaItems, the platforms entry or facebookSettings of this request.

Multi-image post

Up to 10 images in one post. Images and videos cannot be mixed:

"mediaItems": [
  { "type": "image", "url": "https://cdn.example.com/photo1.jpg" },
  { "type": "image", "url": "https://cdn.example.com/photo2.jpg" },
  { "type": "image", "url": "https://cdn.example.com/photo3.jpg" }
]

Link carousel

facebookSettings.carouselCards renders a post as a carousel of 2 to 10 cards, each image with its own click-through link and headline. Cards are layered onto mediaItems in order, one card per image, so both arrays must have the same length and every item must be an image. carouselLink sets the "See more" destination on the end card and defaults to the first card's link. Facebook displays about 35 characters of name and 30 of description; the API accepts up to 255 of each and truncates on render.

{
  "content": "This week's inventory",
  "mediaItems": [
    { "type": "image", "url": "https://cdn.example.com/car-1.jpg" },
    { "type": "image", "url": "https://cdn.example.com/car-2.jpg" },
    { "type": "image", "url": "https://cdn.example.com/car-3.jpg" }
  ],
  "platforms": [
    { "platform": "facebook", "accountId": "66b2e19d8c3f5a7e9d0b1c2d" }
  ],
  "publishNow": true,
  "facebookSettings": {
    "carouselLink": "https://example.com/inventory",
    "carouselCards": [
      { "link": "https://example.com/inventory/car-1", "name": "2027 Sedan", "description": "Low miles" },
      { "link": "https://example.com/inventory/car-2", "name": "2026 SUV", "description": "Certified pre-owned" },
      { "link": "https://example.com/inventory/car-3", "name": "2027 Truck", "description": "Loaded" }
    ]
  }
}

Video and GIF

One video per post. Send a GIF as type: "video": Facebook treats it as a video that auto-plays and loops.

"mediaItems": [
  { "type": "video", "url": "https://cdn.example.com/launch.mp4" }
]

Large text background

facebookSettings.textFormatPresetId renders a text-only feed post as large text on a coloured background, using Facebook's text_format_preset_id. Pass the raw numeric id from Meta; Zernio publishes no catalog of presets and Facebook may change the set.

{
  "platform": "facebook",
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "platformSpecificData": {
    "facebookSettings": { "textFormatPresetId": "123" }
  }
}

Pages and text-only feed posts only. Zernio rejects the request with a 400 when mediaItems or carouselCards are present, when contentType is story or reel, or when content is empty, because an attachment makes Facebook drop the background silently. Length is not rejected: Facebook's composer stops offering a background at around 130 characters, but Meta documents no API limit, so longer content publishes and returns a warning. While a preset is set, a URL in content is not attached as a link preview, for the same reason.

Story

contentType: "story" publishes a Page Story. Media is required, Stories disappear after 24 hours, captions are not displayed, and interactive stickers are not available through the API:

{
  "platform": "facebook",
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "platformSpecificData": { "contentType": "story" }
}

Reel

contentType: "reel" publishes a Reel from a single vertical (9:16) video of 3 to 60 seconds. content is the caption; title sets a separate Reel title:

{
  "platform": "facebook",
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "platformSpecificData": { "contentType": "reel", "title": "Studio day" }
}

Draft in Publishing Tools

facebookSettings.draft: true creates an unpublished draft in Facebook Publishing Tools instead of publishing, for review and approval workflows. Drafts work for feed posts (text, link, image, video) and Reels, not Stories, and expire after about 30 days. firstComment is skipped on a draft.

{
  "platform": "facebook",
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "platformSpecificData": {
    "facebookSettings": { "draft": true }
  }
}

First comment

firstComment is posted as the first comment right after publishing. Feed posts and Reels, not Stories, and skipped when facebookSettings.draft is true:

{
  "platform": "facebook",
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "platformSpecificData": {
    "firstComment": "Order here: https://shop.example.com"
  }
}

Geo-restriction

geoRestriction.countries limits who can see the post to up to 25 countries, as uppercase ISO 3166-1 alpha-2 codes. It is a hard visibility restriction: people outside those countries cannot see the post at all. Feed posts, videos and Reels; not Stories.

{
  "platform": "facebook",
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "platformSpecificData": {
    "geoRestriction": { "countries": ["US", "ES"] }
  }
}

Post to several Pages

When the connected account manages more than one Page, list them with List Facebook pages:

curl "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/facebook-page" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Response (200):

{
  "pages": [
    { "id": "123456789012345", "name": "My Brand Page", "username": "mybrand", "category": "Brand", "fan_count": 5000 },
    { "id": "234567890123456", "name": "My Other Page", "username": "myotherpage", "category": "Business", "fan_count": 1200 }
  ],
  "selectedPageId": "123456789012345",
  "cached": true
}

refresh=true bypasses the cache and fetches the Pages from Meta again, at most once per 60 seconds. To post to two Pages in one request, repeat the same accountId with a different pageId in each entry:

"platforms": [
  {
    "platform": "facebook",
    "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
    "platformSpecificData": { "pageId": "123456789012345" }
  },
  {
    "platform": "facebook",
    "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
    "platformSpecificData": { "pageId": "234567890123456" }
  }
]

To change the default Page instead, so pageId can be omitted, call PUT /v1/accounts/{accountId}/facebook-page with selectedPageId (Update Facebook page).

Platform fields

All fields go in platformSpecificData on the Facebook entry. facebookSettings can also be sent at the request root, where it applies to every Facebook entry in the request; a per-entry value wins.

FieldTypeDefaultDescription
contentType"story" | "reel"(feed)"story" for a Page Story (24 hours, no caption), "reel" for a Reel (single vertical video). Omit for a feed post.
titlestringReel title, separate from the content caption. contentType: "reel" only.
firstCommentstringPosted as the first comment after publishing. Feed posts and Reels, not Stories. Skipped when facebookSettings.draft is true.
pageIdstring(default Page)Target Page when the account manages several. List them with GET /v1/accounts/{accountId}/facebook-page.
geoRestriction{countries}Up to 25 uppercase ISO 3166-1 alpha-2 codes. Feed posts, videos and Reels; not Stories. See Geo-restriction.
facebookSettings.draftbooleanfalseCreate an unpublished draft in Facebook Publishing Tools. Feed posts and Reels, not Stories. Drafts expire after about 30 days.
facebookSettings.carouselCardsArray<{link, name?, description?}>2 to 10 cards, one per image in mediaItems (same length, images only). Mutually exclusive with contentType. name and description take up to 255 characters; Facebook displays about 35 and 30.
facebookSettings.carouselLinkstring (URL)(first card's link)"See more" destination on the carousel end card. Only with carouselCards.
facebookSettings.textFormatPresetIdstring (digits)Facebook preset id for a large-text background. Text-only feed posts on Pages; 400 when media or cards are present, contentType is set, or content is empty.

Media requirements

Facebook rejects images above 4 MB and videos above 4 GB. Zernio converts WebP images to JPEG before upload.

Images

PropertyFeed postStory
Max images101
FormatsJPEG, PNG, GIF (WebP converted)JPEG, PNG
Max file size4 MB4 MB
Recommended1200 x 630 px1080 x 1920 px

Videos

PropertyFeed videoReelStory
Max videos111
FormatsMP4, MOVMP4, MOVMP4, MOV
Max file size4 GB4 GB4 GB
Max duration240 minutes60 seconds120 seconds
Min duration1 second3 seconds1 second
Recommended resolution1280 x 720 px minimum9:16 vertical, required1080 x 1920 px
Frame rate30 fps recommended30 fps recommended30 fps
CodecH.264H.264H.264

Media URLs

A media URL must be publicly accessible over HTTPS with no authentication and no redirects. Cloud storage sharing links (Google Drive, Dropbox) may not work; use a direct download URL or upload through the media endpoint.

Analytics

Call GET /v1/analytics?platform=facebook (Analytics API).

MetricAvailable
Impressions
Likes
Comments
Shares
Clicks
Views
const { data: analytics } = await zernio.analytics.getAnalytics({
  query: { platform: 'facebook', fromDate: '2026-08-01', toDate: '2026-08-31' }
});

console.log(analytics.posts);

Response (200), one entry per post:

{
  "posts": [
    {
      "_id": "65f1c0a9e2b5af0012ab34cd",
      "platform": "facebook",
      "status": "published",
      "publishedAt": "2026-08-14T10:00:05Z",
      "platformPostUrl": "https://www.facebook.com/123456789012345/posts/987654321",
      "analytics": {
        "impressions": 15420,
        "likes": 342,
        "comments": 28,
        "shares": 45,
        "clicks": 189,
        "views": 0,
        "engagementRate": 2.78
      }
    }
  ]
}

Three Facebook-only endpoints go deeper:

  • Page insights: page-level aggregates (media views, post engagements, video metrics, follower counts) over at most 89 days, defaulting to the last 30. Metric names follow the current Meta Graph API; the legacy page_impressions, page_fans, page_fan_adds and page_fan_removes metrics were deprecated by Meta on November 15, 2025 and are rejected. followers_gained and followers_lost come from Zernio's daily follower snapshotter.
  • Post reactions: a count per reaction type for one post. The post analytics above report only the aggregate, as likes.
  • Post earnings: lifetime monetization earnings for one post, read live from Meta. There is no date range, so never sum the totals across dates. A Page not enrolled in monetization returns total: 0.

Inbox

Facebook supports DMs, comments and Page reviews.

Direct messages

FeatureSupported
List conversations
Fetch messages
Send text messages
Send attachments (images, videos, audio, files)
Quick replies (up to 13, Meta quick_replies)
Buttons (up to 3, generic template)
Carousels (generic template, up to 10 elements; imageAspectRatio: "square" for 1:1 card images, default 1.91:1)
React to a message (any emoji) via Add message reaction and Remove message reaction
Message tags (4 types)
Archive and unarchive

Reactions a customer adds or removes arrive on the reaction.received webhook. Pages connected before August 2026 need their webhook subscription refreshed before inbound reactions arrive; sending is unaffected.

To message outside the 24-hour window, send messagingType: "MESSAGE_TAG" with messageTag set to CONFIRMED_EVENT_UPDATE, POST_PURCHASE_UPDATE, ACCOUNT_UPDATE or HUMAN_AGENT.

Persistent menu

The persistent menu shown in Messenger conversations takes at most 3 top-level items and 5 nested items. Manage it with GET, PUT and DELETE /v1/accounts/{accountId}/messenger-menu (Account settings).

Comments

FeatureSupported
List comments on posts
Reply to comments
Delete comments
Like comments
Hide and unhide comments
Send a private reply (DM after a comment) (text plus up to 13 quick replies or 1 to 3 inline buttons, 7-day window, one per comment)

Comment-to-DM automations

Keyword-triggered auto-DMs, created with Create comment automation. A template sends a product card instead of the plain dmMessage: an image, a title, a subtitle for the description or price, and up to 3 url or postback buttons, with up to 10 elements rendering as a carousel. Phone buttons are not supported inside a card, and the card and dmMessage plus buttons are mutually exclusive. imageAspectRatio: "square" renders the card images at 1:1 instead of Messenger's default 1.91:1, and it is Facebook only: Instagram rejects it with a 400. The Instagram page has the full field shape; audience rules are Instagram only.

Reviews

FeatureSupported
List reviews
Reply to reviews

Webhooks

Messenger emits every message lifecycle event except unsend:

EventWhen it fires
message.receivedNew incoming DM
message.sentOutgoing DM is sent
message.editedThe sender edits a sent message (up to 5 edits per Meta)
message.deliveredAn outgoing DM is delivered
message.readThe recipient reads an outgoing DM

Messenger does not expose an incoming-message unsend, so message.deleted never fires for Facebook.

Messages are stored locally: live messages arrive through webhooks, and on connect Zernio replays the DM history the account already has on Meta. The webhooks page has the payloads.

The replay covers conversations that began before the account was connected, up to 500 conversations per account and the newest 500 messages per conversation. It runs in the background, so it can take a while to appear, and it fires no webhooks; read it from List inbox conversations. Replayed messages arrive already read, so they never affect unread counts.

What you cannot do

Facebook's API does not expose:

  • Posting to personal profiles (Pages only)
  • Events
  • Posting to Groups (deprecated by Facebook)
  • Going live (the separate Facebook Live API)
  • Interactive Story stickers
  • Demographic targeting (age, gender, interests) for organic posts; country-level geo-restriction is supported

Common errors

ErrorCauseFix
"Photos should be smaller than 4MB and saved as JPG or PNG."The image is above Facebook's real size limit or in an unsupported formatReduce it to under 4 MB as JPEG or PNG.
"Missing or invalid image file"Facebook could not process the image: corrupt, wrong format or an inaccessible URLOpen the URL in an incognito window. Use JPEG or PNG under 4 MB.
"Unable to fetch video file from URL."Facebook's servers could not download the videoUse a direct, public URL, not a cloud storage sharing link.
"Facebook tokens expired. Please reconnect."The OAuth token expired; Facebook tokens are short-livedReconnect the account. Subscribe to the account.disconnected webhook to catch this early.
"Confirm your identity before you can publish as this Page."Facebook triggered a security check on the PageLog into Facebook, open the Page and complete identity verification.
"Publishing failed due to max retries reached"All 3 retry attempts failedUsually temporary. Retry, or wait and try again.

A publishNow: true post that Facebook rejects returns 207 with post.status: "failed" and the message in platforms[].errorMessage:

{
  "message": "Post created but publishing failed",
  "error": "All platforms failed",
  "post": {
    "_id": "65f1c0a9e2b5af0012ab34cd",
    "status": "failed",
    "platforms": [
      {
        "platform": "facebook",
        "status": "failed",
        "errorMessage": "Facebook needs you to confirm your identity before you can publish as this Page. Open the Facebook mobile app, go to this Page, and complete the identity confirmation, then try again.",
        "errorCategory": "platform_rejected",
        "errorSource": "platform"
      }
    ]
  }
}

207 is a 2xx status, so fetch(...).ok is true; branch on the status code and on post.status. Error handling covers the envelope.

Related

  • Connecting accounts: the OAuth flow and the Page selection step.
  • Create post: every field of the request.
  • Media uploads: upload images and videos instead of hosting them.
  • Messages, Comments and Reviews: the inbox API.
  • Meta Ads: run ads from the same connection.
  • Pricing: what analytics, the inbox and outbound messages cost.
Was this page helpful?

Instagram

Publish feed posts, carousels, Stories and Reels to Instagram with the Zernio API, with collaborators, user tags, catalog audio, paid partnership labels and location tags.

LinkedIn

Publish text, image, video, document and poll posts to LinkedIn personal profiles and organization pages with the Zernio API, with reposts, geo-restriction, multi-organization posting and text edits.

On this page

Quick referenceBefore you startConnectOAuth scopesPublishFeed postMulti-image postLink carouselVideo and GIFLarge text backgroundStoryReelDraft in Publishing ToolsFirst commentGeo-restrictionPost to several PagesPlatform fieldsMedia requirementsImagesVideosMedia URLsAnalyticsInboxDirect messagesPersistent menuCommentsComment-to-DM automationsReviewsWebhooksWhat you cannot doCommon errorsRelated