X API reference
What a post read costs on the X API
A post read is X’s billable unit for retrieving one post from the API — $0.005 per post object returned, charged per resource in the response rather than per request you send.
Per resource, not per request
This is the sentence that decides how an application built on the X API is shaped. You are not billed for calling an endpoint; you are billed for what comes back. One request that returns 100 posts is 100 post reads and costs $0.50. One hundred requests that each return a single post are 100 post reads and cost $0.50 as well. Requests, within the rate limits, are free.
The immediate consequence is that page size is the cost unit. A developer used to per-call quotas reaches for the largest page available, because fewer calls used to mean less quota consumed. Under per-resource billing that instinct is exactly inverted: the largest page is the most expensive way to discover that nothing has changed.
| Resource | Unit cost | Notes |
|---|---|---|
| Posts: Read | $0.005 | Per post object returned. The number that matters for anything bookmark-shaped. |
| User: Read | $0.010 | Twice a post. Every user object in a response, including ones you asked for by expansion. |
| Following / Followers: Read | $0.010 | Per user object returned. |
| List: Read | $0.005 | Per list object. |
| Like / Mute / Block: Read | $0.001 | The cheap end of the table. |
| Owned Read | $0.001 | Conditional, and the condition is stricter than it looks. |
A worked example: the $0.005 probe
The bookmarks endpoint returns newest-first. So the cheapest possible question you can ask about someone’s bookmarks is “what is the most recent one?” — one result, one post read, half a cent.
GET /2/users/:id/bookmarks?max_results=1
→ 1 post object = 1 post read = $0.005
if newest_id == stored_high_water_mark:
stop # nothing new. Total cost today: $0.005
else:
walk pages until the first known ID| Daily strategy for a user who saved nothing | Per day | Per 30 days |
|---|---|---|
| One-result probe, then stop | $0.005 | $0.15 |
| max_results=100 refetch | $0.50 | $15.00 |
The same arithmetic governs the pages after the probe. If k new posts are waiting and you walk in pages of p, stopping at the first ID you already have, you are billed for (floor(k/p) + 1) × p posts and the waste is p − (k mod p). Waste is bounded by page size and is independent of how much is waiting — which is why small pages are strictly cheaper and the only thing large pages buy is fewer requests, a resource that is not billed. There is more on how the cursor behaves in the note on pagination tokens.
Three things people get wrong
“Paginating will cost me a fortune.” It costs nothing. Requests are free inside the rate limits, and the limit on the bookmarks endpoint is 180 requests per 15 minutes per user. Twenty small requests and one large one that return the same posts cost the same; the small ones return fewer posts you did not need.
“Expansions are just a convenience parameter.” Adding expansions=author_id&user.fields=username returns user objects, and a user object is a User: Read at $0.010 — twice the price of the post it describes. Fetching 100 bookmarks with roughly 70 distinct authors costs $0.50 in posts plus $0.70 in authors: $1.20, not $0.50. The fix is to take the author_id that comes back for free, keep a cache of authors shared across all your users, and look up only the IDs you have never seen.
“The monthly cap is a spending cap.” It is a volume cap: pay-per-use accounts are capped at 3 million post reads per monthly billing cycle, above which X expects an Enterprise contract. At $0.005 that ceiling is $15,000 of spend a month, so it is not a growth constraint — it is the point at which you are large enough to negotiate. The control you actually want is the spending limit in the Developer Console, described in the pay-per-use overview.
What makes it survivable
Two rules do most of the work. The first is that a resource is only charged once per UTC day, which is why re-reading the same overlap page twice in an afternoon is free and why syncing more than once a day buys nothing. The second is that a stored post never needs fetching again: post content does not change, so the only reason to ask X about a post you already have is to find out whether it still exists — and that endpoint is not billable at all.
We built the thing this describes
Sift reads your bookmarks once, sorts them into categories, and emails you what you saved. The rules on this page are the reason it costs what it costs — a one-result probe instead of a full page, one paid pass per UTC day, and never an expansion parameter.
Connect X