How to get Facebook profile posts
GET request to /v1/facebook/profile-posts with your input. You get clean JSON back in seconds for 2 credits per call — no OAuth, scraping or platform SDKs. Latest posts and Reels from a Facebook page — listingHits / timings.phase; 60s deadline, failures 0 credits.How to get Facebook profile posts (step by step)
- 1
Get a free API key
Create a free Captapi account (100 credits, no card) and generate an API key from the dashboard.
- 2
Call the Facebook Profile Posts API
Send an authenticated GET request to /v1/facebook/profile-posts with your input. No OAuth, no scraping setup.
- 3
Read the JSON response
Parse the clean JSON response. Pass cache=true for a free 24h cache hit; default is always fresh.
Code example
curl "https://api.captapi.com/v1/facebook/profile-posts?url=https%3A%2F%2Fwww.facebook.com%2FNASA" \
-H "Authorization: Bearer capt_live_..."
# or: -H "x-api-key: capt_live_..."What the response looks like
{
"success": true,
"data": {
"url": "https://www.facebook.com/NASA",
"requested": 4,
"totalReturned": 1,
"listingHits": 1,
"hydrateFailures": 0,
"hydrateSkipped": 0,
"hasMore": false,
"posts": [
{
"platform": "facebook",
"url": "https://www.facebook.com/NASA/posts/pfbid02p2BANvDUJHNq3Mf5iwz1ryQY1Rwvz3LoZibL5LdZxoJXbwHC8Jpi8t4HjAbNkUjBl",
"id": "1658876782274358",
"caption": "Float into the weekend... 🪼\n\nLike a space jellyfish! This fuzzy, glowing \"jellyfish\" shape in the sky was created when the exhaust plumes from our SpaceX CRS-35 cargo mission caught the Sun's bright rays.",
"description": "Float into the weekend... 🪼\n\nLike a space jellyfish! This fuzzy, glowing \"jellyfish\" shape in the sky was created when the exhaust plumes from our SpaceX CRS-35 cargo mission caught the Sun's bright rays.",
"publishedAt": "2026-10-16T20:05:02.000Z",
"author": {
"id": "100044561550831",
"username": "NASA",
"displayName": "NASA - National Aeronautics and Space Administration",
"url": "https://www.facebook.com/NASA"
},
"engagement": {
"likes": 231839,
"comments": 2512,
"likesIsApproximate": false,
"commentsIsApproximate": false,
"sharesIsApproximate": null,
"views": null,
"shares": null
},
"isVideo": false,
"feedbackId": "ZmVlZGJhY2s6MTY1ODg3Njc4MjI3NDM1OA=="
}
],
"truncatedReason": "listing-window"
}
}Billing metadata (credits charged, cache hit/miss) is returned in the X-Captapi-Credits and X-Captapi-Cache response headers.
Request parameters
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | Facebook profile/page URL, @handle, or page name. The URL platform must match this endpoint's platform. Do not pass cross-platform URLs, e.g. YouTube to TikTok, Instagram to Facebook, LinkedIn to X/Twitter, or Pinterest to Rumble. |
| limit | integer | No | Max items to return (default 4, max 4). The logged-out listing hop is ~23–29s typical, hard-capped at 40s. Each hydrate is typically 6–10s (can be ~100ms when listing already carried the post) and is capped at 12s. The next-item fit check uses that 12s cap, not the typical 6–10s, so a call cannot exceed 60s. The loop stops when the next item would miss the 60s deadline and returns what it has (truncatedReason=hydrate-budget | deadline). Asking for 20 cannot return 20 inside that ceiling. Flat 2 credits per call. |
| cache | boolean | No | Set true to serve from the 24h response cache (0 credits on hit). Default false — always fetch fresh. |
Frequently asked questions
What does the Facebook Profile Posts API do?
The Facebook Profile Posts API lets you list items in bulk with metadata from a public Facebook post using one GET request to /v1/facebook/profile-posts. It returns clean JSON — no OAuth or infrastructure setup required.
How many credits does the Facebook Profile Posts API cost?
Each successful call costs 2 credits. Pass cache=true to serve from the 24h cache (0 credits on hit); default is always fresh. Selected profile endpoints also accept cacheMaxAge=1d|3d|7d|14d|30d. Failed or empty results are never charged.
Do I need a Facebook API key or OAuth?
No. A single Captapi key works across every platform Captapi supports — YouTube, TikTok, Instagram, Facebook, Twitter/X, Reddit, Threads, Bluesky, Pinterest, LinkedIn, Rumble, Spotify, Kwai, and more. We handle access, rate limits, retries, and authentication for you.
Why did I get 1 post when I asked for 20?
limit max is 4 — 20 is a 422. requested is a cap, not a promise. truncatedReason is always keyed (listing-window | hydrate-budget | deadline | null). When hasMore is false: listingHits − hydrateFailures − hydrateSkipped = totalReturned. When hasMore is true: min(listingHits, requested) − hydrateFailures − hydrateSkipped = totalReturned. listingHits is how many distinct posts the logged-out HTML window held — on a large page that is often 1–3. hydrateSkipped were found but not hydrated because the next item would have missed the 60s deadline (NASA: 3 of 4, hydrate-budget). That thin window is expected from logged-out Facebook, not a silent miss.
What is the deadline, and why did retries take another 42 seconds?
Hard ceiling 60s (503 on hang with no posts, 502 when a live page yields nothing). Failures are 0 credits. A failed page is remembered for 60s so the next retry is an instant 502/503 with the same timings — the failure is cached, never data. The listing hop is ~23–29s typical and hard-capped at 40s — a 40 001 ms 503 is that cap, not a 53 s listing the docs used to quote from a failed call. Hydrates are typically 6–10s (sometimes ~100ms when listing already carried the post), sequential, and capped at 12s; the loop returns what fits (hydrate-budget) and finished posts still ship if the deadline fires (deadline).
Why did I get a 503 with no posts?
Read timings.phase. phase=listing means every listing hop missed (first-paint, optional scroll, light /posts tab) — hydrateMs is 0 on that path. A shop-heavy page (nike) used to die at the 40s scroll cap and skip /posts; that tab now still runs. phase=hydrate means listing finished and a detail fetch overran. listingMs + hydrateMs is never greater than totalMs. If a 6h last-good page exists, a miss is a stale 200 (0 credits) instead of a 503. If posts had already finished when the deadline fired, they ship as a 200 with truncatedReason=deadline.
Where is scrapedAt?
Removed. Use envelope fetchedAt. There is no scrapedAt twin — same as group-posts. Do not compare profile-posts to profile-reels by a shared scrapedAt; the two pages fetch independently.
Why is limit max 4?
A hydrate is typically 6–10s (sometimes ~100ms when listing already carried the post) and the listing hop is ~23–29s typical, hard-capped at 40s. The fit check uses the 12s cap, not the typical, so listing-at-40 plus one hydrate finishes by 52s and a second is not started. limit stays at 4 because the loop is a clock: it hydrates while elapsed + 12s still fits, then returns what it has (hydrate-budget). If the deadline fires after posts finished, those posts still ship (deadline). limit=20 cannot return 20 inside that ceiling. Asking above 4 is a 422 that names the field.
Is the Facebook Profile Posts API suitable for production use?
Yes. It is a stable REST endpoint with predictable JSON and automatic retries. Pass cache=true to serve from the 24h cache (0 credits on hit); default is always fresh. Selected profile endpoints also accept cacheMaxAge=1d|3d|7d|14d|30d. Use it for analytics, monitoring, and content automation.
Ready to get Facebook profile posts?
Start free with 100 credits — no credit card required.
Get your free API key