Skip to content

meta-pages

Use when managing Facebook Pages via Graph API — organic posts, page information, page insights, reviews, and page management. This is organic publishing only, NOT ads.

ModelSource
sonnetpack: social
Full Reference

Facebook Pages Graph API — organic content publishing, page management, and insights. Not for paid ads (use meta-ads).

Mandatory Announcement — FIRST OUTPUT before anything else:

┏━ 📄 meta-pages ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ [one-line: what page management task] ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

In scope: Organic Facebook Page posts, page info retrieval, page insights (organic reach, engagement), review management, page photos/videos, page events, scheduled posts.

Out of scope: Paid ad campaigns → meta-ads. CAPI/server-side events → meta-conversions. Custom audiences → meta-audiences.

Pages API requires a Page Access Token (not a User token):

Terminal window
# Exchange user token for page token
GET /v21.0/me/accounts?access_token={USER_TOKEN}
# Returns array of pages with their access_token

Required permissions: pages_manage_posts, pages_read_engagement, pages_read_user_content (for reviews)

Token type: Page Access Token — long-lived (never expires unless permissions revoked)

Terminal window
# Text post
POST /v21.0/{page-id}/feed
{
"message": "Post content here",
"access_token": "{PAGE_ACCESS_TOKEN}"
}
# Post with link
POST /v21.0/{page-id}/feed
{
"message": "Check this out",
"link": "https://example.com",
"access_token": "{PAGE_ACCESS_TOKEN}"
}
# Scheduled post (Unix timestamp, must be 10min–6mo in future)
POST /v21.0/{page-id}/feed
{
"message": "Scheduled post",
"scheduled_publish_time": 1735689600,
"published": false,
"access_token": "{PAGE_ACCESS_TOKEN}"
}
Terminal window
# Upload photo and post simultaneously
POST /v21.0/{page-id}/photos
{
"url": "https://example.com/photo.jpg",
"message": "Caption here",
"access_token": "{PAGE_ACCESS_TOKEN}"
}
# Or upload as unpublished, then attach to feed post
POST /v21.0/{page-id}/photos
{
"url": "https://example.com/photo.jpg",
"published": false,
"access_token": "{PAGE_ACCESS_TOKEN}"
}
# Returns: { "id": "photo_id" }
POST /v21.0/{page-id}/feed
{
"message": "Post with photo",
"attached_media": [{"media_fbid": "{photo_id}"}],
"access_token": "{PAGE_ACCESS_TOKEN}"
}
Terminal window
GET /v21.0/{page-id}?fields=id,name,fan_count,followers_count,category,website,phone,location&access_token={PAGE_ACCESS_TOKEN}
Terminal window
GET /v21.0/{page-id}/posts?fields=message,created_time,likes.summary(true),comments.summary(true)&limit=25&access_token={PAGE_ACCESS_TOKEN}
Terminal window
DELETE /v21.0/{post-id}?access_token={PAGE_ACCESS_TOKEN}
Terminal window
# Page-level metrics
GET /v21.0/{page-id}/insights?metric=page_impressions,page_reach,page_engaged_users&period=day&access_token={PAGE_ACCESS_TOKEN}
# Post-level metrics
GET /v21.0/{post-id}/insights?metric=post_impressions,post_reach,post_engaged_users&access_token={PAGE_ACCESS_TOKEN}

Available metrics (organic only):

  • page_impressions — total times page content was seen
  • page_reach — unique accounts that saw page content
  • page_engaged_users — unique accounts that engaged
  • post_impressions — times a specific post was seen
  • post_reactions_by_type_total — breakdown of reactions

Periods: day, week, days_28, month

Terminal window
# List reviews
GET /v21.0/{page-id}/ratings?fields=reviewer,review_text,rating,created_time&access_token={PAGE_ACCESS_TOKEN}
# Reply to review
POST /v21.0/{review-id}/comments
{
"message": "Thank you for your feedback!",
"access_token": "{PAGE_ACCESS_TOKEN}"
}

Note: Reviews API requires pages_read_user_content permission. Rating scale is 1-5. You can reply but cannot delete reviews.

const PAGE_ID = process.env.FB_PAGE_ID;
const PAGE_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;
const API_VERSION = 'v21.0';
const BASE = `https://graph.facebook.com/${API_VERSION}`;
async function publishPost(message, link = null) {
const body = { message, access_token: PAGE_TOKEN };
if (link) body.link = link;
const res = await fetch(`${BASE}/${PAGE_ID}/feed`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const data = await res.json();
if (data.error) throw new Error(`FB API: ${data.error.message}`);
return data.id; // post_id
}
async function getPageInsights(metric = 'page_impressions', period = 'day') {
const params = new URLSearchParams({ metric, period, access_token: PAGE_TOKEN });
const res = await fetch(`${BASE}/${PAGE_ID}/insights?${params}`);
const data = await res.json();
if (data.error) throw new Error(`FB API: ${data.error.message}`);
return data.data;
}
Terminal window
FB_PAGE_ID=your_page_id
FB_PAGE_ACCESS_TOKEN=your_page_access_token

Get page ID and token: GET /v21.0/me/accounts?access_token={USER_TOKEN}

  • 200 calls/hour per access token by default
  • Page publishing: no separate sub-limit, counts toward the 200/hr
  • Insights: same 200/hr limit
  • Throttled responses: { "error": { "code": 32, "type": "OAuthException" } } → back off with exponential retry
CodeMeaningFix
190Token expired or invalidRe-authenticate, get new page token
200Permission missingRe-request required permission
32Rate limit hitExponential backoff
100Invalid parameterCheck field names and required params
368Temporarily blockedWait 24h, check for policy violations

Current stable: v21.0 (valid through February 2026). Next: v22.0.

Always pin the version in the URL — never use /me/feed without a version prefix.