The X API failure that stops B2B automation mid-month is not posting. It is reading. A 10-account team running mention checks, follower lookups, and engagement analytics drains the project-level read ceiling weeks before it touches the write cap. Engagement endpoints cap at 75 requests per 15 minutes per app.
Legacy Basic tier: monthly reads ran out at one-third the rate of writes
App-level monthly cap
X API Basic Tier Rate Limits Hit B2B Accounts on Reads First, Not Writes
The short version
X API basic tier rate limits cap monthly reads at roughly 15,000 per app while allowing 50,000 monthly posts. For B2B teams running social listening and engagement analytics alongside publishing, reads drain first. Engagement endpoints cap at 75 requests per 15 minutes per app, and the project-level read ceiling hits long before posting volumes come close to the write limit.
The legacy Basic tier, priced at $200 per month, capped app-level monthly post reads at roughly 15,000 and monthly writes at 50,000 posts. It closed to new signups in February 2026 and surviving projects were force-migrated in June 2026, so most teams reading this are on pay-per-use now. The ratio that tier encoded is the part that outlived it: reads ran out at roughly one-third the rate of writes, on the same plan, at the same price, inside the same billing month. Any B2B team running social listening next to publishing was structurally guaranteed to lose the read side first, and the tier's own numbers said so before anyone wrote a line of code against it.
Run the write math for a real B2B operation and the asymmetry stops being abstract. Ten managed accounts posting three times per week is roughly 120 posts per month. Against a 50,000-post app-level monthly cap, that is less than 0.4 percent of the budget. Against the 3,000-posts-per-month per-user cap, it is about 4 percent. The per-window write limits are just as slack: POST /2/tweets allows 100 posts per 15 minutes per user and 10,000 per 24 hours per app. A team would have to publish at a cadence no compliance department would approve before either write counter became relevant to anything. Write quota is not a constraint for B2B publishing. It is a rounding error.
The read side of the same account set behaves nothing like that. Mention pulls, follower lookups, engagement analytics, timeline reads, and list reads all decrement the same project-level read ceiling, and they run on schedules rather than on editorial calendars. Publishing volume is bounded by how much a human team can write and approve. Read volume is bounded by how many polling loops someone configured, across how many accounts, at what interval, which is a number most teams never count. That is the whole asymmetry in one sentence: the write side has a human bottleneck and the read side has a cron bottleneck.
We call this the read-write inversion, and it predicts which B2B teams will open a support ticket before their billing cycle ends better than any other signal we track. Teams size their API plan on publishing volume because publishing is the visible output, the thing the client sees, the thing on the content calendar. The invisible half of the workload, the reads that feed dashboards and alerting and prospecting lists, is what sets the ceiling that stops the operation. The plan gets chosen against the wrong workload, and the mismatch does not surface until quota runs out in the middle of a month.
Pay-per-use has been the default since February 6, 2026, and it caps at 3 million post reads per monthly billing cycle. That figure is on the official docs.x.com pricing page. Third-party write-ups citing 2 million are quoting a stale beta-period number, and it has propagated far enough that we regularly see pipelines sized against it, which means those pipelines are budgeting against a ceiling that no longer exists in either direction. Above 3 million post reads in a cycle there is no higher self-serve option. Enterprise is the only remaining door, and it is a procurement conversation rather than a checkout page.
Per-operation pricing makes the trap read backwards. A post read costs $0.005. Creating a post costs $0.015 without a URL and $0.20 with one. Reads are the cheap operation by a wide margin, so the natural instinct is to read freely and be careful about writes, especially writes carrying links. Cost per operation and quota consumption per operation are two different meters, though, and only one of them terminates in a hard ceiling that stops the account. The cheap operation is the one that runs out. Optimizing for per-call cost while ignoring per-cycle consumption is how teams end up with a small bill and a dead pipeline.
In a typical 10-account B2B automation pattern running on a single X Developer Project, the failure arrives in a specific order. Individual per-user 15-minute read windows saturate first, on whichever accounts run the heaviest mention polling or engagement lookups. The shared per-app Bearer Token pool depletes next, as background social listening consolidates under app-only auth. Then the project-level monthly read ceiling cuts every read across the Project at once, frequently mid-month, while the aggregate write cap sits largely untouched because typical B2B publishing volumes of three to five posts per account per week consume a fraction of the write budget. The question that determines whether automation survives the billing cycle is not how many posts per month the team needs. It is how many read requests the listening, prospecting, and analytics loops will generate, and that one requires sitting down with the endpoint table.
Three Rate Limit Counters Running Simultaneously: The Architecture Behind the 429
Every read request against the X API v2 decrements three separate counters at once: the 15-minute per-endpoint window, the 24-hour per-endpoint cap, and the monthly billing cap tracked at the Project level. Each has its own reset schedule. Each independently returns HTTP 429 when it runs out. Nothing in the response tells you which of the three fired. That last point is the entire problem, and it is worth stating plainly before anything else, because almost every persistent 429 story we have worked through traces back to code that assumed there was only one counter and that the headers described it.
Only the 15-minute counter surfaces in the response headers. The x-rate-limit-limit, x-rate-limit-remaining, and x-rate-limit-reset trio describes that window and nothing else. The 24-hour endpoint cap and the monthly project-level cap are invisible at request time. You can watch x-rate-limit-remaining sit comfortably above zero and still receive a 429 on the very next call, because the counter that blocked the request was never represented in the headers to begin with. Instrumentation built entirely on those three headers is measuring one third of the system and reporting it as the whole.
When the daily cap is what fired, x-rate-limit-reset still points to the next 15-minute boundary. The header is not lying so much as answering a different question than the one being asked of it: it reports when the window resets, not when the request will succeed. A team that hits the 24-hour endpoint ceiling sees a reset timestamp a few minutes out, waits for it, retries, and hits the same wall, because the daily counter has not moved and will not move for hours. The retry succeeds at obeying the header and fails at accomplishing anything.
The monthly billing cap produces the same behavior with a far worse blast radius. Exhaust the project-level monthly read ceiling and the 429 you get back carries an x-rate-limit-reset pointing at the next 15-minute boundary, not at the start of the next billing cycle. Automation that reads the header, sleeps until the timestamp, and retries will keep doing exactly that until the cycle turns over. The header cannot tell you whether to wait 14 minutes or 14 days. That is the sentence to put in the code comment above your retry logic.
This is the most operationally dangerous failure mode on the platform, and it is dangerous precisely because it is quiet. A monthly-cap 429 and a window 429 are indistinguishable in the response. No error code separates them. The status is identical, the header shape is identical, and the retry policy that handles one correctly handles the other catastrophically. A team looking at logs sees the same status code they have seen a thousand times before during ordinary window collisions, and their monitoring, if it alerts on 429 rate at all, has almost certainly been tuned to ignore it.
The only way out is keeping your own ledger. SocialNexis runs a real-browser local agent, and that architecture has to track cumulative project-level read consumption independently of the API response, because the API response cannot supply it. In practice that means counting every read the system issues, attributing it to the endpoint, the auth mode, the user token, and the Project, and comparing that running total against the monthly ceiling being paid for. It is unglamorous bookkeeping. It is also the difference between a pipeline that degrades in a way a human can see and one that spins in place for weeks producing empty dashboards.
The common remediation makes things worse. A team sees repeated 429s, assumes contention, and adds jitter or widens the backoff in the retry policy. Both are correct responses to a 15-minute window collision and both are useless against a daily or monthly counter. Widening the backoff only changes how often the pipeline confirms that it is still blocked. We have watched teams spend days tuning retry parameters against a counter that resets only when the billing cycle does. Three fields are worth persisting per request to avoid that: which endpoint was called, which counter scope the call charged, and the cumulative project total for the current cycle. With those, a 429 becomes diagnosable immediately. Without them, every 429 looks like the same transient blip.
Rather not do this by hand? SocialNexis drafts posts and comments in your own voice and schedules them across LinkedIn and X.
Start freeDoes the X API Have a Monthly Read Cap Separate from Write Limits?
Yes. The X API v2 tracks post reads at the Project level on a monthly billing cycle, entirely separately from write limits. Reads and writes do not share a quota pool, in either direction. Exhausting the monthly read ceiling leaves write capacity completely intact, which is why teams in this state can still publish normally while every dashboard they own goes blank at the same moment. The client-facing symptom is confusing enough that it often gets misdiagnosed as an analytics vendor outage rather than a quota event.
The monthly read cap is a project-level ceiling, not a per-user one. Every app inside a Project, and every user token inside those apps, draws from the same monthly read pool. That is the structural fact underneath nearly every multi-account drain story we hear. One app running heavy analytics does not merely exhaust its own quota. It exhausts the Project's, and every other app and every other user in that Project begins receiving 429s on reads simultaneously, including apps whose own consumption has been modest all month and whose owners have no visibility into what the noisy app was doing.
The specific ceiling has changed but the structure has not. The legacy Basic tier capped monthly reads at roughly 15,000 post reads per project. Pay-per-use caps at 3 million post reads per monthly billing cycle. In both cases the shape is the same: one shared ceiling, drawn down by every app and every user in the Project, with no per-user carve-out and no mechanism for reserving a slice for a workload you consider critical. There is no priority tier inside a Project. The alerting pipeline and the exploratory prospecting script compete for the same pool on equal terms.
Write limits are built on a different frame entirely. POST /2/tweets is capped per app on a 24-hour window at 10,000 posts, and per user on a 15-minute window at 100 posts. Those counters do not interact with the read side at all. There is no conversion, no shared budget, and no way to trade unused write capacity for read capacity. A team sitting on an almost entirely untouched write budget cannot spend one unit of it on a follower lookup. This kills the workaround teams reach for most often once they understand the ratio, which is worth knowing before you spend an afternoon looking for the setting.
What gets metered on the read side is post consumption, not request count, and the X API v2 Tweet caps documentation is explicit that this consumption is tracked at the Project level. That distinction matters for modeling. GET /2/tweets returns many posts per call. Timeline and list reads return pages of results. A request that comes back with a full page is not equivalent, for quota purposes, to a request that returns a single post. Any team estimating monthly consumption from request counts alone will underestimate, and the size of the underestimate scales with how well their pagination is tuned.
That is also why the read ceiling can arrive without any change in the code. Pagination depth is a function of the data, not the configuration. A prospecting run against accounts with larger follower lists consumes more than the identical run against smaller ones. A month with an unusually active mention volume consumes more than a quiet month at the same polling interval. Read consumption varies with the world, while write consumption varies only with your calendar. That is why one of the two needs monitoring and the other does not.
If you take one design rule from this section, make it this: model monthly read consumption in posts rather than in requests, and attribute it to a Project rather than to a user or an app. That is the unit the meter uses, and matching your model to the meter is what turns quota from a recurring surprise into a number on a dashboard. Everything else in this guide, the endpoint tiers, the auth-mode routing, the connected-app audit, is a way of moving that one number.
Per-User, Per-App, Project Level: Which X API Rate Limit Counter Fires First
The three scopes run independently, and knowing which one you hit changes the fix entirely. Per-user limits are tied to a specific OAuth user access token. If account A exhausts its per-user read window on mentions, account A gets 429s and account B, holding its own token, keeps working normally. The damage is contained to one token and one account, which makes per-user exhaustion the least painful of the three failures and also the easiest to misread as a problem with that one account's credentials.
Per-app limits are shared across every user on that app. One high-volume account pulling batches through a shared Bearer Token pipeline can drain the app-level pool and cause 429s for every other account on that app at the same instant. There is no fairness mechanism, no per-user reservation inside the app pool, no throttling that protects the quiet consumers from the loud one. The pool is first-come, and a single aggressive job wins the race against every well-behaved one running beside it.
This is the failure mode B2B teams hit first, and the uncomfortable part is that they usually build it deliberately. Consolidating social listening under a single app-only auth pipeline is good engineering by most measures: one credential to rotate, one code path to maintain, one place to add caching and instrumentation. It also converts a set of independent per-user budgets into a single shared pool with a single shared blast radius. The moment one managed account needs a heavier listening cadence, every other account on that app inherits the consequence, and nothing in the architecture makes that tradeoff visible at the time you make it.
Across the 10-account patterns we see most often, the sequence is consistent. Per-user 15-minute read windows saturate first, on the accounts running the heaviest mention polling or engagement lookups. The shared per-app Bearer Token pool depletes second, as background social listening consolidates under app-only auth. The project-level monthly read ceiling fires last and cuts every read across the Project simultaneously, usually mid-month, while the aggregate write cap remains largely untouched. Each stage produces the same 429 to the caller. Only the scope of the outage differs: one account, then one app, then everything.
Scope is not readable from the 429 response either. The error is identical whether the per-user counter, the per-app counter, or the project ceiling blocked the call. The one signal available at request time is correlation across your own fleet. If a single account is failing and the rest are fine, you are per-user. If every account on one app fails at once while accounts on a second app keep working, you are per-app. If reads fail everywhere across the Project while writes continue succeeding, you are at the monthly ceiling. That correlation table is the closest thing to a diagnostic the API gives you, and it only works if you are running more than one account through more than one app.
Which is an argument against putting every managed account on a single app if you can avoid it. Splitting accounts across separate apps within a Project contains the per-app blast radius without changing the monthly ceiling, since the ceiling is tracked at the Project level regardless of how many apps sit under it. It converts a total outage into a partial one. That is a smaller win than it sounds, and it is still worth having, because a partial outage is diagnosable by comparison while a total one looks indistinguishable from the API being down.
Attribution has to be built at the call site or it does not exist. Every read the system issues should carry a tag for the auth mode used, the token identity, the app, and the Project before it goes out the door. Retrofitting that after the first outage is painful in a specific way: the logs you need to diagnose what happened are exactly the ones you did not write, and the incident is over by the time you have them. This is cheap to add on day one and expensive to add on the day you need it.
Rather not do this by hand? SocialNexis drafts posts and comments in your own voice and schedules them across LinkedIn and X.
Start freeEngagement Lookups and Mention Polling: Where B2B Read Quota Disappears
Engagement read endpoints are the tightest limits on the platform and the first specific thing to break in a B2B analytics pass. GET liking_users, GET liked_tweets, GET retweeted_by, and GET quote_tweets each cap at 75 requests per 15 minutes per app and 75 per 15 minutes per user. A 10-account operation fetching engagement data for each published post exhausts the shared app pool in a single analytics run, well before the mention-polling or follower-lookup quotas have been touched at all. If you are looking for the endpoint category that fails first, it is this one, and it is not close.
Seventy-five requests is not seventy-five posts worth of engagement data across ten accounts. It is seventy-five calls total, per window, shared across everything on that app. Any engagement report that iterates over recent posts per account and requests likers and retweeters for each one will exceed it, and it will exceed it early in the loop rather than near the end. This is the endpoint category that turns a nightly analytics job into a 429 storm, and it does so quietly, because analytics jobs fail into empty charts rather than into anything a user complains about the same day.
GET /2/users/:id/mentions caps at 450 requests per 15 minutes per app and 300 per 15 minutes per user. Spread across 10 managed accounts each polling every 15 minutes, the per-app pool works out to 45 calls per account per window. That sounds workable until one account with heavy mention volume starts paginating through results. Every extra page that account consumes comes out of the pool every other account shares, and the per-app ceiling gets reached before any single account approaches its own per-user cap of 300. The account that is doing well is the account that breaks everyone else's monitoring.
GET /2/users/:id/followers and its following counterpart cap at 300 per 15 minutes per app and 300 per user. With a default max_results of 100, building follower lists for 1,000 ICP targets requires at minimum 10 requests per target, or 10,000 requests in total. At 300 per window per app, that campaign spans a great many windows, and it competes with mention polling and engagement pulls on the same app for every one of them. Follower prospecting is the read workload teams most consistently underestimate, because the request count is a function of follower counts nobody has looked up yet.
GET /2/tweets, the batch lookup endpoint, is comparatively roomy at 3,500 requests per 15 minutes per app and 5,000 per 15 minutes per user. Both counters run at the same time and either can raise a 429 on its own. Even that headroom disappears once multiple accounts funnel batch lookups through one shared app pool, and batch lookup is precisely the endpoint that hydration steps hammer. Pull mention IDs, hydrate them. Pull list timelines, hydrate them. Every read pipeline that separates discovery from hydration doubles its touch count on this endpoint by design.
Set all of that against post creation. POST /2/tweets allows 10,000 posts per 24 hours per app, and a 10-account team publishing three times a week is nowhere near that ceiling on any day of any month. The endpoint B2B teams assume is the constraint has the most headroom of anything they call. The framing in most competitor content, which treats posting volume as the thing to manage, has the picture exactly inverted for this workload.
For the engagement endpoints specifically, the mitigation is sequencing and caching rather than backoff. Sequence analytics pulls into off-peak windows so they are not competing with mention polling for the same app pool, and cache engagement counts for at least 15 minutes between refreshes so that a dashboard reload does not reissue the same lookup. Engagement numbers do not move fast enough to justify a fresher read than that, and a 15-minute cache lines up cleanly with the window the counter uses anyway. Those two changes recover more usable throughput on this endpoint category than any retry tuning we have tried.
Why Waiting 15 Minutes Does Not Fix a Persistent X API 429 Error
The x-rate-limit-reset header always points to the next 15-minute window boundary, no matter which of the three counters raised the 429. That one implementation detail is responsible for more broken X API pipelines than anything else on this page. When the 24-hour endpoint cap or the project-level monthly ceiling is the blocking counter, the header hands you a timestamp minutes away for a wall that will not clear for hours or for the remainder of the billing cycle. The header is correct about the window and silent about everything else, and code cannot tell the difference.
The failure pattern deserves a name: the reset-header retry loop. Code reads x-rate-limit-reset, sleeps until that timestamp, retries, receives another 429, reads the header again, sleeps again. It will do this until the daily counter rolls over or the billing cycle resets, whichever one is blocking. From the outside the pipeline looks alive and healthy. It is polling on schedule, logging cleanly, consuming CPU, and producing nothing. There is no crash, no stack trace, and no error text beyond a status code that every X API integration sees routinely and has learned to ignore.
Diagnosing a persistent 429 means checking three things in this order. First, is the 15-minute window exhausted? That one is readable directly: check x-rate-limit-remaining on the failing call. Second, has the 24-hour endpoint cap been hit? That requires your own tracking, because it never appears in any header. Third, has the project-level monthly read ceiling been reached? That requires the X Developer Portal or your own consumption log. Two of the three checks depend on state you have to have been keeping already, which is why the diagnosis usually happens after the outage rather than during it.
The X Developer Community has a documented case matching this exactly: GET /2/lists/:id/tweets and GET /2/tweets both returning 429 usage-capped at the same moment while the per-15-minute counters showed available quota on both. Two different endpoints, healthy window counters, simultaneous failure. That combination has only one explanation, which is a counter sitting above the window level, and the report confirms the monthly cap as the cause. If you ever see multiple unrelated read endpoints fail together while their individual window counters look fine, you can skip straight to checking cycle consumption.
There is no error code that separates a monthly-cap 429 from a window 429. This is a known gap with no workaround at the API response level. Any distinction your system makes has to come from state your system kept, which means the response is not where the answer lives and no amount of parsing it more carefully will change that. Teams that go looking for a subtler signal in the response body spend real time on it and come back with nothing, so it is worth saying flatly rather than leaving them to discover it.
What works is a circuit breaker keyed to your own consumption ledger rather than to the response header. If the cumulative project read total for the cycle is near the ceiling, stop reading and say so loudly, in a log line a human will see, rather than retrying into it. If the ledger says you are well under both the monthly ceiling and the daily cap, then the header is trustworthy and sleeping until reset is the correct move. The header is a reliable source of truth for exactly one of the three counters, and you have to know which case you are in before you trust it.
A second guardrail worth adding is a consecutive-failure ceiling per endpoint. If the same endpoint returns 429 more times in a row than an ordinary window collision would ever produce, treat it as a higher counter and escalate to a human rather than continuing to sleep and retry. Window collisions clear on their own. Daily and monthly caps do not, and that retry loop is the only thing standing between a quiet quota problem and a full month of empty dashboards that nobody noticed until the client asked.
Get the next breakdown in your inbox
Occasional, practical guides on LinkedIn and X growth. No spam, unsubscribe anytime.
Shared App Pools and Third-Party Tools Drain X API Read Quota Faster Than Posting Does
Every OAuth connection made to an X Developer Project draws from that Project's quota, including connections your automation does not control and cannot see. CRM integrations, scheduling dashboards, and analytics platforms all authorize against the same Project and all decrement the same project-level read counter. Read consumption is not proportional to your posting activity. For most B2B teams it is not even proportional to their own primary automation's activity, which is why the ceiling keeps arriving on a schedule nobody can explain from their own logs.
A team that connects three SaaS tools via OAuth to one X Developer Project multiplies read consumption with no corresponding increase in publishing output. This is the pattern sitting behind the complaint that the read cap arrives earlier every month for no visible reason. The primary automation is running normally, generating exactly the traffic it always generated, and its logs show nothing unusual because nothing unusual is happening in it. The drain is occurring in someone else's process, against the same ceiling, on a cadence set by a vendor.
The typical shape is easy to recognize. A scheduling tool handles publishing. A CRM pulls follower data for prospecting. A separate analytics platform reads engagement metrics on a fixed interval. All three draw from one project-level read pool. None of them reports its consumption to the others, and none of them knows the others exist. The analytics platform polling on its interval has no idea that the CRM paginated through a large follower list that morning, and no vendor is going to build that awareness for you.
Dormant connections are worse than active ones, because nobody is watching them at all. An app a team stopped using but never revoked can keep issuing background sync or keep-alive polling against the Project, and that consumption appears in nobody's dashboard because nobody has that dashboard open. The first step in extending read quota is not optimizing your own code. It is opening the X Developer Portal, listing every application attached to the Project, and revoking access for the ones nobody is using.
Audit the connected apps before touching a single retry policy. We have recovered more usable read quota for teams by revoking abandoned integrations than by any change to the primary pipeline's code, and the audit takes a fraction of the time. It is also the only mitigation in this guide that requires no engineering work, which makes it the obvious first move and the one most consistently skipped, because revoking access to a tool somebody once evaluated feels like a conversation and reading endpoint docs feels like progress.
Where the workloads genuinely need to coexist, the structural option is separation. The monthly read ceiling is tracked per Project, so isolating a read-heavy workload in its own Project gives it a ceiling your publishing pipeline cannot drain and cannot be drained by. That carries billing and setup consequences worth weighing carefully, and it is not free in either money or operational overhead. It is also the only lever that changes the ceiling itself rather than the rate at which you approach it, which puts it in a different category from everything else here.
Whatever structure you land on, the consumption number that matters is the Project total, not the per-tool total. Every vendor dashboard will happily show you its own API usage, and every one of those numbers is a fraction of the figure that governs whether your reads keep working tomorrow. Sum them, or track consumption at the Project level directly, or accept that the ceiling will keep arriving as a surprise in the middle of a month with no explanation available in any single tool's logs.
Auth-Mode Pooling: How to Extend Per-Window Throughput Before Hitting the Monthly Ceiling
Requests made with user-context auth, meaning OAuth 1.0a or an OAuth 2.0 user token, count against the per-user rate limit counter. Requests made with app-only auth using a Bearer Token count against the app-level counter. The two counters are independent, which produces a result that surprises people the first time they encounter it: the same endpoint can return a clean response with one auth mode and a 429 with the other, in the same second, for the same query. Nothing is broken. One counter is depleted and the other is not.
For endpoints supporting both modes, running both in parallel effectively doubles per-window throughput. GET /2/tweets allows 3,500 requests per 15 minutes per app under a Bearer Token and 5,000 per 15 minutes per user under an OAuth user token. Run both paths and the effective ceiling on that endpoint is 8,500 requests per 15 minutes. This is not a loophole or an undocumented trick. It is how the counters are documented to work, and it is the main throughput lever available to a multi-account B2B operator who has already tuned their polling intervals.
Implementing it means a router at the call site rather than one global auth choice made at startup. Each read picks its credential based on which counter currently has headroom, falls back to the other when one is depleted, and records which counter it charged. Endpoints requiring user context get pinned to that path permanently. Endpoints that work either way become the flexible pool. The bookkeeping is the hard part, and it is the same bookkeeping the monthly ceiling already demands, so most of the implementation cost is shared between the two problems rather than doubled.
The caveat matters more than the optimization does. Auth-mode pooling only touches the per-window counters. It does not raise the project-level monthly read ceiling by a single post. A team running this optimization exhausts the monthly ceiling at exactly the same absolute number of reads as a team that does not, and they arrive there sooner, because they are processing more reads per window. Pooling buys throughput, not capacity. Every team that discovers the technique needs to hear that sentence before they build it, because the discovery feels like finding extra quota and it is not.
That distinction decides where the optimization belongs. If the constraint is a burst, a backfill, a launch-day monitoring window, or a one-time prospecting pull that needs to finish today, pooling is the right tool and it will get the job done inside the window available. If the constraint is that the monthly ceiling arrives mid-cycle every single cycle, pooling makes it arrive earlier and solves nothing. The fix in that case is reading less: caching engagement counts, lengthening polling intervals, narrowing target lists, and cutting connected tools that nobody is using.
Some endpoints have no app-only path at all. GET /2/dm_events and the related DM read endpoints require user-context auth and cap at 15 requests per 15 minutes per user, with no Bearer Token access permitted. There is no pooling available there. The per-user bucket is the entire supply, and it is multiplied by the number of managed accounts rather than shared across them, which is the one place in this system where running many accounts works in your favor. Fifteen requests per window per account is still tight enough that DM monitoring needs its own cadence plan rather than being folded into a general listening loop.
The through-line here is that X API capacity planning for B2B is a read problem wearing a write problem's clothing. The tier you pick, the endpoints you call, the tools you connect, and the auth modes you route through all resolve to one number: how many post reads your Project consumes in a billing cycle. Writes are not the binding constraint and have not been at any B2B publishing volume we have measured. Build the ledger, audit the connected apps, cache the engagement counts, and treat x-rate-limit-reset as advice about one counter out of three.
Frequently asked questions
Are X API rate limits enforced per user, per app, or at the project level, and which one hits first for multi-account teams?
All three scopes apply simultaneously. Per-user limits, tied to individual OAuth tokens, saturate first for accounts doing heavy mention polling or engagement lookups. The shared per-app pool depletes next as multiple accounts consolidate reads under app-only Bearer Token auth. The project-level monthly read ceiling fires last, cutting all reads across the project simultaneously, typically mid-month for active B2B teams.
Why does a 429 error on the X API persist even after waiting 15 minutes?
The x-rate-limit-reset header always points to the next 15-minute boundary, even when a daily or monthly cap is the actual cause. If the 24-hour endpoint cap or the project-level monthly read ceiling has been exhausted, the counter that fired does not reset in 15 minutes. Code that reads the header, sleeps, and retries wakes up to the same 429 and loops indefinitely until the daily or monthly reset clears the actual blocking counter.
What is the monthly read cap on the X API pay-per-use plan, and how fast does a B2B team exhaust it?
The monthly cap is 3 million post reads per project, confirmed on the official docs.x.com pricing page. Third-party sources citing 2 million reflect a stale beta figure. A 10-account team running daily mention checks, follower lookups, and engagement analytics can exhaust a lower-tier ceiling in under a week. Above 3 million post reads per month, Enterprise is the only option.
Does the X API track read limits and write limits separately, or do reads and writes share the same quota pool?
Reads and writes are tracked separately and do not share a quota pool. Exhausting the monthly project-level read ceiling leaves write capacity fully intact. POST /2/tweets caps at 10,000 per 24 hours per app and 100 per 15 minutes per user. A 10-account team posting three times per week generates roughly 120 posts per month, less than 0.4 percent of the available app-level write budget. The read side is the binding constraint.
Which X API read endpoints drain quota the fastest for B2B teams doing social listening?
Engagement endpoints (liking_users, liked_tweets, retweeted_by, quote_tweets) cap at 75 requests per 15 minutes per app and are the tightest limits on the platform. Mention polling via GET /2/users/:id/mentions caps at 450 per 15 minutes per app, shared across all accounts. Follower lookup caps at 300 per 15 minutes per app. These three categories drain the shared per-app pool long before any write endpoint comes close to its limit.
How does using a Bearer Token versus an OAuth user token affect which rate limit counter gets decremented?
Bearer Token (app-only auth) decrements the per-app counter. OAuth user tokens (user-context auth) decrement the per-user counter for the specific account. For endpoints supporting both auth modes, using both in parallel runs two independent counters simultaneously. GET /2/tweets allows 3,500 per 15 minutes per app and 5,000 per user, yielding an effective 8,500 per 15 minutes when both auth modes operate in parallel.
Can a single high-volume account in a multi-user app exhaust the shared rate limit pool and cause 429s for all other users?
Yes, but only for per-app limits. If one account runs a large batch read under the shared Bearer Token pool and exhausts the per-app counter, every other account on the same app gets 429s for the remainder of that 15-minute window. Per-user limits are scoped to individual OAuth tokens, so one user exhausting their per-user counter does not affect other users on the same app.
What is the difference between the 15-minute window rate limit, the 24-hour cap, and the monthly billing cap on the X API?
The 15-minute window resets every 15 minutes and is the only counter surfaced in x-rate-limit-reset response headers. The 24-hour cap is a harder daily ceiling per endpoint that resets once per day; it is not visible in headers. The monthly billing cap is tracked at the Project level across all apps and users and resets at the start of each billing cycle. All three run simultaneously and each independently triggers a 429.
Why does the x-rate-limit-reset header point to the wrong time when I hit a monthly or daily X API cap?
The header is always populated with the next 15-minute window boundary regardless of which counter fired. X does not return a different reset timestamp for daily or monthly cap 429s. The header is accurate only when the 15-minute window is the blocking counter. For daily and monthly caps, the header underreports the true reset time by hours or weeks. Independent consumption tracking outside the API is the only reliable way to identify which counter is the actual cause.
Is the X API monthly post read cap applied per user account or shared across all accounts in a project?
The monthly read cap is applied at the Project level, shared across all apps and all users within the project. There is no per-user carve-out. Every read request from every app in the project, regardless of which user token or auth mode was used, decrements the same project-level monthly counter. One app running heavy analytics drains the monthly ceiling for all other apps and users in the same project.
Sources and further reading
- X API v2 rate limits: per-endpoint, per-user, and per-app limits in the official documentation
- X API pay-per-use pricing and the 3 million monthly read ceiling
- X API v2 Tweet caps: how project-level monthly read consumption is tracked
Put this guide into practice
SocialNexis writes posts and comments in your voice, then runs them across LinkedIn and X on a schedule you set.
Not ready? Score your next post free and see what's holding your reach back.