Skip to content
curl-x
apicurldeveloperagentsautomation

Use curl-x as an API: No Key, No Login, No Watermark

curl-x has no signup and no API key. Fetch a post URL with curl for a direct file, or POST to /api/extract for structured JSON — here's the real request/response shape, error codes, and rate limits.

Share:

Want to try it now? Paste a post link from any supported platform to download its media instantly.

Open Downloader

curl-x has no signup, no API key, and no watermark. There are two ways to use it programmatically: fetch a public post URL with a CLI client (curl -L -o video.mp4 https://www.curl-x.com/<user>/status/<id>) and get the media file back directly, or POST a URL to /api/extract for structured JSON with every available media variant. Both are free, unauthenticated, and rate-limited per IP rather than per key.

Table of contents

The zero-key pattern: fetch a post URL, get the file

curl-x doesn't front a "download API" behind an API key. Instead, every supported post has a normal HTML page and a sibling route that streams the raw media. Middleware inspects the request's User-Agent; if it matches a known CLI download client, the request gets rewritten to that sibling route instead of the HTML page — no separate endpoint to learn, no auth header to attach:

curl -L -o video.mp4 https://www.curl-x.com/NASA/status/1234567890123456789

That's a complete, working download command. -o video.mp4 names the saved file explicitly; if you'd rather curl-x name it for you from the response headers (recommended — the suggested name embeds the post ID), use -OJ instead, as covered in how to download a Twitter video with curl. The CLI rewrite happens on an internal path match, not an HTTP redirect, so -L is harmless but not required here.

The trick only fires for clients whose User-Agent contains one of a small allowlisted set: curl, wget, httpie, aria2, axel, lftp. A browser or an HTTP library that doesn't identify as one of these gets the normal HTML page instead — set your client's User-Agent explicitly if you're wrapping curl-x in something else.

Which platforms and paths support it

The CLI rewrite is wired up on one bare "detail" path per platform, each with its own /download sibling route:

PlatformPath pattern
Twitter / X/<username>/status/<tweetId>
Instagram post/instagram/<shortcode>
Instagram reel/instagram/reel/<shortcode>
Threads/threads/<code>
Facebook video/video/<id>
Facebook photo/photo/<id>
Facebook reel/reel/<id>
Reddit post/r/<subreddit>/comments/<postId>
Reddit gallery/gallery/<postId>
TikTok/tiktok/<id>
Bluesky/bluesky/<actor>/<rkey>

Every one of these resolves to the post's primary media item — the first photo or video on a multi-item post — as a single file with a proper Content-Disposition: attachment filename. There's no path for pulling every item off a multi-photo or multi-image post through the CLI shortcut; for that, use the structured JSON endpoint below, or the web UI's picker, and see batch-downloading tweet videos with a shell script for scripting a list of posts.

POST /api/extract for structured JSON

When you need every available media variant — not just the one file the CLI shortcut streams — call the extraction API directly:

curl -X POST https://www.curl-x.com/api/extract \
  -H "Content-Type: application/json" \
  -d '{"url": "https://x.com/NASA/status/1234567890123456789"}'

url accepts a public post link from any supported platform (Twitter/X, Facebook, Instagram, Threads, Reddit, TikTok, Bluesky) — curl-x detects which platform it is from the URL shape itself, so there's no separate endpoint or platform parameter. A successful response looks like:

{
  "tweetUrl": "https://x.com/NASA/status/1234567890123456789",
  "author": "NASA",
  "text": "Some caption text from the post",
  "media": [
    {
      "type": "video",
      "thumbnailUrl": "https://pbs.twimg.com/ext_tw_video_thumb/…/img/thumb.jpg",
      "variants": [
        {
          "url": "https://video.twimg.com/ext_tw_video/…/vid/avc1/1280x720/clip.mp4",
          "bitrate": 2176000,
          "contentType": "video/mp4",
          "width": 1280,
          "height": 720
        }
      ],
      "aspectRatio": 1.7777
    }
  ],
  "platform": "twitter"
}

media is an array of items (a multi-photo or multi-video post returns more than one), and each item's variants array lists every downloadable rendition of that item with its own url, contentType, and (when known) bitrate, width, and height — pick whichever variant fits your use case, or just take the first (curl-x already orders them best-first). A Twitter/X response also includes an article field when the tweet links an X Article; other platforms omit it. A Twitter GIF comes back as "type": "gif" with a video/mp4 variant — X converts uploaded GIFs to looping video internally, so that's the file you'll fetch even though the post reads as a GIF.

Each variant's url is a real CDN link (video.twimg.com, pbs.twimg.com, fbcdn.net, cdninstagram.com, and similar per platform) that you can fetch yourself, or hand to curl-x's own generic proxy (GET /api/download?url=<variant-url>) if you want the same attachment headers and suggested filename the per-post download routes produce.

Error codes

A failed request returns a JSON body shaped { "error": "<message>", "code": "<CODE>" } with one of these HTTP statuses:

codeHTTP statusMeaning
INVALID_INPUT400Request body missing a string url field
INVALID_URL400URL doesn't match any supported platform/post pattern
PARSE_ERROR400URL matched a platform but couldn't be parsed into a post reference
NOT_FOUND404Post doesn't exist, was deleted, or is private/suspended
RATE_LIMITED429Upstream platform rate-limited curl-x's extraction (may include a retryAfter field and Retry-After header)
NETWORK_ERROR502Upstream fetch failed (timeout, connection error)
EXTRACTION_FAILED422Post loaded but no supported media could be extracted from it
UNKNOWN500Unclassified server error

Branch on code, not the human-readable error string — the message text is localized to the caller's Accept-Language/curlx-locale cookie and can change wording, but the code values are stable.

Rate limits and being a good citizen

curl-x runs a per-IP, fail-open rate limiter at the edge with two buckets:

  • 60 requests/minute across every /api/* path and every /download-suffixed route (the global bucket)
  • 20 requests/minute specifically for /api/extract (a stricter sub-bucket — those requests also count against the global 60)

Go over either bucket and you get 429 Too Many Requests with a Retry-After: 60 header instead of a result. There's no per-key quota to negotiate for more headroom — the limiter is IP-based and the same for every caller, key or no key. For scripted or agentic use, space out requests (a couple of seconds between calls comfortably clears both buckets) and treat a batch of URLs as a personal-scale job — tens of posts, not an unattended crawl of an entire account's history. The same etiquette from batch-downloading tweet videos with a shell script applies whether you're driving curl-x from a shell loop or an agent's tool-call loop.

For AI agents

If you're building or operating an agent that needs to fetch social media, curl-x's llms.txt is a machine-readable summary of what the site supports — platforms, URL formats, and the /api/extract and /api/download endpoints — meant to be fetched directly instead of scraped from the HTML site. For a ready-to-use operating pattern (when to call curl-x, how to convert a post URL, how to handle private/deleted posts), see how to use an agentic SKILL.md with curl-x. Both are free to fetch and require no registration, matching everything else described here.

FAQ

Does curl-x have an API?

Yes, in two forms: fetching a post's bare URL (e.g. /username/status/tweetId) with a CLI client like curl or wget streams the media file directly, and POST /api/extract with {"url": "..."} returns structured JSON listing every media item and variant for that post.

Do I need an API key?

No. curl-x has no signup, no account, and no API key for either the CLI download path or /api/extract. Requests are identified and rate-limited by IP address only.

What are the rate limits?

60 requests per minute per IP across all /api/* and /download-suffixed routes, with a stricter 20 requests per minute specifically on /api/extract. Exceeding either returns 429 with a Retry-After: 60 header.

Does curl-x add watermarks?

No. curl-x streams the platform's original media file as-is — no overlay, no branding, no watermark added — and it's free to use for public posts.

How do I get a Twitter GIF from a URL?

Use the same /api/extract call or the CLI download path as for a video. Twitter/X converts uploaded GIFs into looping MP4 video internally, so the response's media item comes back with "type": "gif" but a video/mp4 variant — that's the actual file you'll receive, and it plays like a normal video file.

Can I call /api/extract for platforms other than Twitter/X?

Yes. The same endpoint accepts public post URLs from Facebook, Instagram, Threads, Reddit, TikTok, and Bluesky — curl-x detects the platform from the URL itself, so there's no separate endpoint per platform.

Bottom line

curl-x's "API" is deliberately unglamorous: no key to request, no dashboard, no quota tier to upgrade. Fetch a post's bare URL with curl/wget for the file directly, or POST /api/extract when you need every variant's URL, dimensions, and bitrate as JSON. Stay under 20 requests/minute on /api/extract and 60/minute overall, branch on the code field for errors, and — whether you're scripting this by hand or wiring it into an agent via llms.txt — you get the same free, no-login, no-watermark result either way.

Ready to download from any platform?

Try curl-x — free, fast, and no login required.

Download Now
Share: