One URL in. Clean JSON out.
Send a public Facebook video or Reel URL to /v1/facebook/download and get back a direct link to the video file on Facebook's own CDN. The response is three fields and nothing else: the post id, the media URL, and a reminder that the link expires. 10 credits per video, and you do the fetching.
The difference
On the left, what a headless browser hands you. On the right, what the endpoint hands you.
<div class="x1yztbdb x1n2onr6 xh8yej3" data-visualcompletion="ignore"><div class="x78zum5 xdt5ytf"><div dir="auto" class="xdj266r x11i5rnm x1mh8g0r">Weekend build: three settings we changed after your feedback</div></div><div class="x9f619 x1ja2u2z x78zum5"><span class="xt0b8zv x1jx94hy" aria-label="5.2K reactions"><i data-visualcompletion="css-img"></i></span><span class="x193iq5w">331 comments</span><span class="x1s688f">128 shares</span></div><abbr data-utime="1751630400" class="x1i10hfl">3d</abbr><script>requireLazy(["CometResourceScheduler"],function(f){f().schedule({"__bbox":{"require":[["adp_Comet... {"data": {"platform": "facebook","entity_id": "1093831344793765","media_url": "https://cdn.example/video/master.mp4?sig=...","mime_type": "video/mp4","expires_at": "2026-07-15T13:00:00Z","warning": "media_url is short-lived (max 1h) — download promptly or re-request."},"request_id": "req_01JZX4M8Q2TE9W"}
The payload
One small object per call. There are no counters, no caption, no author block — this endpoint has a single job, which is to resolve a post URL into a playable file address. If you want the numbers attached to that same post, that is a separate call to the Facebook Post Stats API.
The media URL points at Facebook's CDN, not at a copy we made. That is deliberate. A link we host would be a second copy of someone's video sitting on our infrastructure, and it would also mean lying to you about where the bytes come from. The cost of doing it the honest way is that the link is signed and short-lived.
If the post has no video in it, there is nothing to resolve. The normalizer requires a media URL to emit a row at all, so a photo album, a text status or a shared link produces zero items and an error rather than a half-filled object.
Fixed reminder string that media_url is short-lived. Same text on every response; there for humans reading raw JSON, safe to drop in code.
Pricing
One video resolves for 10 credits — about 5¢ on the monthly plan, 4.5¢ on annual. $5 covers roughly 100 downloads, and calls that error or find no video are never charged.
Estimate only, on a full-year basis. 10 credits per returned video. Monthly: $5 per 1,000 credits with $4/1,000 top-ups. Annual: $54 per 12,000 credits with $3/1,000 top-ups. We show whichever plan is cheaper for your annual volume, divided by 12. Failed calls are never charged; cache hits cost the same as fresh calls.
Entry price, side by side
Credits are not equivalent units across vendors — each meters differently. Price your own workload on both before deciding on entry price alone. At high volume, several of these are cheaper per credit than we are.
Engineering notes
We document exactly how every endpoint behaves — nulls, caching, billing — so what you ship on day one is still running in month six. No surprises, no support tickets.
Facebook signs its CDN URLs with an expiry. Store media_url in a table and hand it to a worker that runs every fifteen minutes and you will see downloads fail for no visible reason. Store the post URL or the post id instead, call this endpoint, and fetch the bytes in the same process while the link is warm.
Fetch from a host that can reach the CDN directly. If your API call runs in one region and your download runs behind a proxy in another, expect rejections that look nothing like an expiry error.
Public video posts and public Reels resolve. Photo posts do not, because there is no video file to point at. Live streams are unreliable while they are still live and generally resolve once the replay is published.
A post whose video is a re-share of someone else's upload may resolve to the original file or to nothing, depending on how Facebook has stitched the share together. If you are archiving at scale, log the failures rather than assuming a uniform success rate across post types.
We read the same page an anonymous visitor sees. Videos in private Groups, on friends-only profiles, or restricted to an age or country gate are unreachable, and we do not attempt to get around any of that. The call returns an error, not a partial object.
Personal profile content is thinner than Page content across all our Facebook endpoints. If a URL you can open while logged in returns nothing here, open it in a private window first — that is usually the whole explanation.
Copyright in a video belongs to whoever made it. Keeping a copy of your own posts, or holding evidence of a public post for a compliance file, is one thing. Reuploading a competitor's ad to your own channel is a different thing and it is your legal exposure, not ours.
This endpoint sits in the near-immutable cache class, since a published video's file does not change. A repeated call for the same post inside the window returns in milliseconds and sets x-cache: hit, and it costs the same 10 credits as a fresh one.
The signed URL still ages independently of our cache, so if a cached media_url has already expired, pass fresh=true to force a re-resolve. Errors are never charged, so a failed probe costs you nothing; any successful call bills at least one credit.
Questions
Call /v1/facebook/download with the public post or Reel URL and your API key. The response contains media_url, a direct link to the file on Facebook's CDN, which you fetch with your own HTTP client. No Facebook developer app, no Graph API permissions and no login are involved, because the endpoint reads the same public page you can open in a private browser window.
10 credits per video. Credits are $0.005 each on monthly billing and $0.0045 on annual, so a call is about 5 cents, and $5 covers roughly 100 videos. It costs more than a stats call because resolving media is heavier work upstream. Calls that error or return no video are not charged at all.
Because pushing large binaries through a JSON API is the wrong shape. A direct link means no file-size ceiling imposed by us, no double transfer, and a download your client can resume or stream. The tradeoff is that Facebook's link is signed and expires, so you need to fetch it right away rather than parking it in a database.
Facebook decides, and it does not publish the number, so we do not quote one either — our own response note says only that the link is short-lived. Any pipeline that downloads inside the same request cycle is fine; any pipeline that batches links overnight will fail. Persist the post id and re-resolve when you actually need the bytes — that pattern costs one extra call and removes a whole class of flaky failures.
Yes. Public Reel URLs resolve the same way ordinary video posts do, and come back with the same three fields. Photo posts, text statuses and shared links do not resolve, because the normalizer needs an actual video file to return a row. Those calls return an error rather than an object with a null media_url.
No. We read public content while logged out, with no session and no credentials, so anything behind a friends-only setting, a private Group, or a country or age restriction is simply not visible to us. The call errors out and is not billed. There is no flag or parameter that changes this, and there will not be one.
You get whatever file Facebook publishes on the public page. If the uploader burned a watermark into the video, it is in the file. If Facebook itself has stamped the copy it serves, that is also in the file, and it is a decision on their side that has changed before. We do not re-encode, strip or alter anything on the way through.
Next
100 trial credits on signup — no card, key on screen immediately.