Twitter API error codes and fixes
An X (Twitter) API error has two parts: an HTTP status from 400 to 504 that names the kind of failure, and a code or type in the JSON body that names the cause. Only 429 and the 5xx statuses clear if you wait.
Short answer: Retry only 429 and 5xx errors, at the x-rate-limit-reset time or after a growing pause. Every other error repeats until you fix the request (400), keys (401), prepaid balance (402), app access (403, 453) or ID (404). To read X data with one key and no OAuth, use Sorsa API: posts from $0.014 per 1,000, 100 free requests on signup.
- Endpoint
POST /tweet-info-bulk- Page size
- 100 posts per request
- Price
- from $0.014 per 1,000
#How to read an X API error
Every failed call to the official X API hands back three things: the HTTP status, a JSON body and, on most endpoints, rate-limit headers. The status says what kind of failure it is, the body says which cause inside that kind you hit, and the headers say when a rate limit resets.
X API v2 bodies share one shape: a title, a detail and a type, a URI under https://api.x.com/2/problems/, sometimes with a reason such as client-not-enrolled. Older v1.1 endpoints, and the rate-limit response in X's own v2 docs, use an errors array with a numbered code and a message instead: {"errors": [{"code": 88, "message": "Rate limit exceeded"}]}. Write your code to branch on type, reason or code, because X can reword the human text at any time.
A 200 can carry errors too. When one request asks for several posts or users and some are deleted or protected, X returns the ones it found in data and lists the rest in an errors array with the type resource-not-found or not-authorized-for-resource. Check for errors on every response, successful ones included.
Print the body before you raise an exception. In Python, raise_for_status() shows only the status line, and X's own staff ask developers on its forum to print response.text instead, because the body names the parameter or the setting at fault.
#X API status codes and how to fix each
The official X API answers with eleven error statuses: five of them (429, 500, 502, 503 and 504) clear if you wait and retry, and the other six fail again until you change the request, the keys, the balance or the access. X's response codes reference (opens in a new tab) lists ten of them; 402 is the one it leaves out.
| Status | What it means on the official X API | Fix | Retry? |
|---|---|---|---|
| 400 Bad Request | A parameter is missing, malformed or out of range; the body's errors array names it | Fix the parameter the body names | No |
| 401 Unauthorized | X can't verify the caller: wrong or revoked keys, the wrong auth method, a bad OAuth 1.0a signature | Regenerate the keys, use the auth the endpoint lists, sync the clock | No |
| 402 Payment Required | The prepaid pay-per-use balance is empty: type credits-depleted | Add credits, or use the keys of the funded app | No |
| 403 Forbidden | The keys work, but this app, token or account may not do this | Read the reason or code: enrollment, permissions, access level | No |
| 404 Not Found | The post, user or URL doesn't exist, or the post was deleted | Check the ID and the endpoint path | No |
| 409 Conflict | A filtered stream has no rules | Add a rule, then connect | No |
| 429 Too Many Requests | A rate-limit window ran out (code 88), or the monthly usage cap was reached (usage-capped) | Wait for x-rate-limit-reset; a usage cap waits for the next billing cycle | At the reset |
| 500 Internal Server Error | A failure inside X (code 131) | Retry with a growing pause | Yes |
| 502 Bad Gateway | X's front servers got no answer from the service behind them | Retry with a growing pause | Yes |
| 503 Service Unavailable | X is over capacity (code 130) | Retry with a growing pause | Yes |
| 504 Gateway Timeout | X's servers timed out on the request | Retry with a growing pause, ask for less per call | Yes |
400 Bad Request
- What it means on the official X API
- A parameter is missing, malformed or out of range; the body's
errorsarray names it - Fix
- Fix the parameter the body names
- Retry?
- No
401 Unauthorized
- What it means on the official X API
- X can't verify the caller: wrong or revoked keys, the wrong auth method, a bad OAuth 1.0a signature
- Fix
- Regenerate the keys, use the auth the endpoint lists, sync the clock
- Retry?
- No
402 Payment Required
- What it means on the official X API
- The prepaid pay-per-use balance is empty: type
credits-depleted - Fix
- Add credits, or use the keys of the funded app
- Retry?
- No
403 Forbidden
- What it means on the official X API
- The keys work, but this app, token or account may not do this
- Fix
- Read the
reasonorcode: enrollment, permissions, access level - Retry?
- No
404 Not Found
- What it means on the official X API
- The post, user or URL doesn't exist, or the post was deleted
- Fix
- Check the ID and the endpoint path
- Retry?
- No
409 Conflict
- What it means on the official X API
- A filtered stream has no rules
- Fix
- Add a rule, then connect
- Retry?
- No
429 Too Many Requests
- What it means on the official X API
- A rate-limit window ran out (code 88), or the monthly usage cap was reached (
usage-capped) - Fix
- Wait for
x-rate-limit-reset; a usage cap waits for the next billing cycle - Retry?
- At the reset
500 Internal Server Error
- What it means on the official X API
- A failure inside X (code 131)
- Fix
- Retry with a growing pause
- Retry?
- Yes
502 Bad Gateway
- What it means on the official X API
- X's front servers got no answer from the service behind them
- Fix
- Retry with a growing pause
- Retry?
- Yes
503 Service Unavailable
- What it means on the official X API
- X is over capacity (code 130)
- Fix
- Retry with a growing pause
- Retry?
- Yes
504 Gateway Timeout
- What it means on the official X API
- X's servers timed out on the request
- Fix
- Retry with a growing pause, ask for less per call
- Retry?
- Yes
#402 Payment Required: X API credits depleted
A 402 from the official X API means the prepaid balance behind your app has nothing left to spend, so X refuses every billable call until credits arrive. X's pay-per-use model charges each read up front, $0.005 per post and $0.010 per user on X's price list (opens in a new tab), and new developers have had no other way in since February 6, 2026.
This is the body, as a developer posted it on X's forum in October 2026:
{
"title": "Payment Required",
"detail": "credits depleted",
"type": "https://api.x.com/2/problems/credits-depleted"
}
The type link leads nowhere useful: X's error reference has no entry for 402, a gap a developer reported on X's forum (opens in a new tab) in July 2026. The causes, from the most common:
- The balance is at zero or just below it. A request can leave a tiny negative remainder, and X blocks calls until new credits cover it. Buy credits in the Developer Console; auto-recharge doesn't run while the balance is zero or negative.
- The spending limit for the cycle is used up. A limit you set in the console is the most your account will spend in a billing cycle. Raise it, or wait for the next cycle.
- The keys belong to a different app. If the Client ID, secret or Bearer token come from an app in another Project or an older developer account, every billable call fails while the console shows money. One developer's 402 with a $20 balance (opens in a new tab) ended exactly there in October 2026. Copy the funded app's keys and authorize again. A working
GET /2/users/meproves only that authentication passes. - Bursts drain the balance faster than auto-recharge refills it. X's pricing page warns that usage able to empty a top-up within 5 minutes can still run out of credits. Raise the recharge amount.
Good to know
A 402 and a 429 of type
usage-cappedboth stop paid reads, for different reasons. The 402 is money: add credits and the next call works. The usage cap is volume: pay-per-use stops at 3M post reads per billing cycle, and past it only the next cycle or an Enterprise contract, from about $42K a month, brings reads back.
#403 Forbidden, 453 and other access errors
A 403 means X accepted your keys and refused the action, and the reason or numbered code in the body tells you which gate is closed; a retry never opens it. The six you meet most:
client-not-enrolled(typeclient-forbidden): the keys come from an app that isn't attached to a Project, or isn't enrolled in the access the endpoint needs. In the Developer Console, put the app inside a pay-per-use Project and use that app's keys, as X staff advised in an October 2026 thread (opens in a new tab).- 453: "You currently have access to a subset of X API v2 endpoints and limited v1.1 endpoints (e.g. media post, oauth) only." The call went to a v1.1 endpoint other than media upload or OAuth, which is what
tweepy.APIand other older clients do. Call the v2 endpoint instead:tweepy.Clientin Python, thetwitter-api-v2package in Node.js. - 261, "Your App cannot perform write actions": the app is set to Read only. Switch it to Read and Write, then regenerate the access tokens, because old tokens keep the permission they were made with.
- Protected or suspended accounts: code 179 or the type
not-authorized-for-resourcefor a protected post, 63 for a suspended user. Nothing on your side opens them; skip the item. - 326, temporarily locked: the account behind the token tripped X's spam checks. Log in on x.com and complete the check X shows.
- 226 and 187 on writes: X's spam filter or a duplicate post. The 226 message has its own fixes in our guide to why X says a request looks automated.
Likes, follows and quote posts also left self-serve access on April 20, 2026, so those writes now end in a 403 on a pay-per-use app. Every 403 text, with the console steps for each, is in our guide to X API 403 Forbidden.
#429 and 5xx: the errors you fix by waiting
A 429 or a 5xx is the only kind of X API error that a retry can fix, and only at the right moment: the reset time for a 429, a growing pause for a 5xx.
A 429 with code 88 means one endpoint's window has no requests left. Three headers on every response show where you stand, x-rate-limit-limit, x-rate-limit-remaining and x-rate-limit-reset, a Unix time in seconds; most windows last 15 minutes. A 429 of type usage-capped is the monthly 3M post-read cap, and the reset header doesn't lift it. How long each limit lasts, in the X app and the API, is covered in our guide to Twitter rate limit exceeded.
A 5xx is X's side failing: 500 and code 131 are internal errors, 503 and code 130 mean over capacity, 502 and 504 are timeouts between X's servers. Wait 1, 2, 4 and 8 seconds between tries, then stop and log the body.
This handler retries only what can succeed and stops on everything else, with the body in the message:
import time
import requests
RETRY = {500, 502, 503, 504}
def call_x(url, headers, params=None, tries=5):
for attempt in range(tries):
r = requests.get(url, headers=headers, params=params, timeout=30)
if r.ok:
body = r.json()
for err in body.get("errors", []): # partial errors in a 200
print("skipped:", err.get("detail"))
return body
if r.status_code == 429 and "usage-capped" not in r.text:
reset = int(r.headers.get("x-rate-limit-reset", time.time() + 60))
time.sleep(max(reset - time.time(), 1) + 1)
elif r.status_code in RETRY:
time.sleep(2 ** attempt)
else: # 400-409 and a capped 429: fix the cause first
raise RuntimeError(f"X API {r.status_code}: {r.text}")
raise RuntimeError(f"X API still failing after {tries} tries")
#X API error codes by number
Numbered codes come from the v1.1 API and still arrive today: in v1.1 responses, in Tweepy tracebacks and in some v2 bodies, such as code 88 on a rate-limited call. The messages and statuses below are X's own, from its last published code table (archived in May 2023 (opens in a new tab)); 453 comes from developers' reports on X's forum. A code missing here falls back to its status in the table above.
| Code | X's message | Status | Cause and fix |
|---|---|---|---|
| 32 | Could not authenticate you. | 401 | Keys, token or OAuth signature wrong: regenerate and sign again |
| 34 | Sorry, that page does not exist. | 404 | Wrong endpoint URL or ID |
| 50 | User not found. | 404 | The account was deleted or renamed: look it up by user ID |
| 63 | User has been suspended. | 403 | The account you asked about is suspended: skip it |
| 64 | Your account is suspended and is not permitted to access this feature. | 403 | The token's own account is suspended: appeal to X |
| 87 | Client is not permitted to perform this action. | 403 | The endpoint isn't open to this app |
| 88 | Rate limit exceeded. | 429 | Wait for x-rate-limit-reset |
| 89 | Invalid or expired token. | 401 or 403 | Token revoked or expired: authorize again, store the new token |
| 92 | SSL is required. | 403 | Call over HTTPS with TLS 1.2 |
| 99 | Unable to verify your credentials. | 403 | Wrong consumer or token secret |
| 130 | Over capacity. | 503 | Retry with a growing pause |
| 131 | Internal error. | 500 | Retry with a growing pause |
| 135 | Could not authenticate you. | 401 | Clock drift broke the OAuth timestamp: sync the clock |
| 144 | No status found with that ID. | 404 | The post was deleted or the ID is wrong |
| 179 | Sorry, you are not authorized to see this status. | 403 | The author protects their posts |
| 185 | User is over daily status update limit. | 403 | The account's posting cap is used: wait a few hours |
| 186 | Tweet needs to be a bit shorter. | 403 | The text is over the length limit |
| 187 | Status is a duplicate. | 403 | The same text was already posted: change it |
| 215 | Bad authentication data. | 400 | No Authorization header, or a malformed one |
| 220 | Your credentials do not allow access to this resource. | 403 | The token is restricted: use one with the needed scope |
| 226 | This request looks like it might be automated. | 403 | X's spam filter stopped a write: slow down |
| 261 | Your App cannot perform write actions. | 403 | Read-only app: set Read and Write, regenerate tokens |
| 326 | ...this account is temporarily locked. | 403 | Log in on x.com and clear the lock |
| 327 | You have already retweeted this Tweet. | 403 | Already done: treat it as success |
| 349 | You cannot send messages to this user. | 403 | The recipient doesn't accept your messages |
| 415 | Callback URL not approved for this client App. | 403 | Add the exact callback URL to the app's settings |
| 453 | You currently have access to a subset of X API v2 endpoints... | 403 | A v1.1 call or a missing access level: call the v2 endpoint |
32
- X's message
- Could not authenticate you.
- Status
- 401
- Cause and fix
- Keys, token or OAuth signature wrong: regenerate and sign again
34
- X's message
- Sorry, that page does not exist.
- Status
- 404
- Cause and fix
- Wrong endpoint URL or ID
50
- X's message
- User not found.
- Status
- 404
- Cause and fix
- The account was deleted or renamed: look it up by user ID
63
- X's message
- User has been suspended.
- Status
- 403
- Cause and fix
- The account you asked about is suspended: skip it
64
- X's message
- Your account is suspended and is not permitted to access this feature.
- Status
- 403
- Cause and fix
- The token's own account is suspended: appeal to X
87
- X's message
- Client is not permitted to perform this action.
- Status
- 403
- Cause and fix
- The endpoint isn't open to this app
88
- X's message
- Rate limit exceeded.
- Status
- 429
- Cause and fix
- Wait for
x-rate-limit-reset
89
- X's message
- Invalid or expired token.
- Status
- 401 or 403
- Cause and fix
- Token revoked or expired: authorize again, store the new token
92
- X's message
- SSL is required.
- Status
- 403
- Cause and fix
- Call over HTTPS with TLS 1.2
99
- X's message
- Unable to verify your credentials.
- Status
- 403
- Cause and fix
- Wrong consumer or token secret
130
- X's message
- Over capacity.
- Status
- 503
- Cause and fix
- Retry with a growing pause
131
- X's message
- Internal error.
- Status
- 500
- Cause and fix
- Retry with a growing pause
135
- X's message
- Could not authenticate you.
- Status
- 401
- Cause and fix
- Clock drift broke the OAuth timestamp: sync the clock
144
- X's message
- No status found with that ID.
- Status
- 404
- Cause and fix
- The post was deleted or the ID is wrong
179
- X's message
- Sorry, you are not authorized to see this status.
- Status
- 403
- Cause and fix
- The author protects their posts
185
- X's message
- User is over daily status update limit.
- Status
- 403
- Cause and fix
- The account's posting cap is used: wait a few hours
186
- X's message
- Tweet needs to be a bit shorter.
- Status
- 403
- Cause and fix
- The text is over the length limit
187
- X's message
- Status is a duplicate.
- Status
- 403
- Cause and fix
- The same text was already posted: change it
215
- X's message
- Bad authentication data.
- Status
- 400
- Cause and fix
- No Authorization header, or a malformed one
220
- X's message
- Your credentials do not allow access to this resource.
- Status
- 403
- Cause and fix
- The token is restricted: use one with the needed scope
226
- X's message
- This request looks like it might be automated.
- Status
- 403
- Cause and fix
- X's spam filter stopped a write: slow down
261
- X's message
- Your App cannot perform write actions.
- Status
- 403
- Cause and fix
- Read-only app: set Read and Write, regenerate tokens
326
- X's message
- ...this account is temporarily locked.
- Status
- 403
- Cause and fix
- Log in on x.com and clear the lock
327
- X's message
- You have already retweeted this Tweet.
- Status
- 403
- Cause and fix
- Already done: treat it as success
349
- X's message
- You cannot send messages to this user.
- Status
- 403
- Cause and fix
- The recipient doesn't accept your messages
415
- X's message
- Callback URL not approved for this client App.
- Status
- 403
- Cause and fix
- Add the exact callback URL to the app's settings
453
- X's message
- You currently have access to a subset of X API v2 endpoints...
- Status
- 403
- Cause and fix
- A v1.1 call or a missing access level: call the v2 endpoint
#X API v2 problem types
In v2 responses the type field carries the cause: one of the eleven types X documents, plus credits-depleted, which it doesn't. The URIs all start with https://api.x.com/2/problems/.
| Type | What it means | Fix |
|---|---|---|
invalid-request | A 400: a parameter is wrong, listed in errors | Fix that parameter |
resource-not-found | The post or user doesn't exist, often inside a 200 | Skip it or check the ID |
not-authorized-for-resource | Protected or private content | Skip it |
client-forbidden | A 403 with a reason, usually client-not-enrolled | Move the app into a Project |
credits-depleted | A 402: the prepaid balance is empty | Add credits |
usage-capped | A 429: the monthly usage cap | Wait for the next billing cycle |
rate-limit-exceeded | A 429: a rate-limit window | Wait for x-rate-limit-reset |
streaming-connection | A stream connection problem | Reconnect with a growing pause |
rule-cap, invalid-rules, duplicate-rules | Filtered stream rules: too many, bad syntax, already there | Delete, fix or skip the rule |
about:blank | A generic error | Read the status |
invalid-request- What it means
- A 400: a parameter is wrong, listed in
errors - Fix
- Fix that parameter
resource-not-found- What it means
- The post or user doesn't exist, often inside a 200
- Fix
- Skip it or check the ID
not-authorized-for-resource- What it means
- Protected or private content
- Fix
- Skip it
client-forbidden- What it means
- A 403 with a
reason, usuallyclient-not-enrolled - Fix
- Move the app into a Project
credits-depleted- What it means
- A 402: the prepaid balance is empty
- Fix
- Add credits
usage-capped- What it means
- A 429: the monthly usage cap
- Fix
- Wait for the next billing cycle
rate-limit-exceeded- What it means
- A 429: a rate-limit window
- Fix
- Wait for
x-rate-limit-reset
streaming-connection- What it means
- A stream connection problem
- Fix
- Reconnect with a growing pause
rule-cap,invalid-rules,duplicate-rules- What it means
- Filtered stream rules: too many, bad syntax, already there
- Fix
- Delete, fix or skip the rule
about:blank- What it means
- A generic error
- Fix
- Read the status
The errors array of a 400 names the exact value X rejected. In this October 2026 case from X's forum, full-archive search refused an end_time set to the moment of the request:
{
"title": "Invalid Request",
"detail": "One or more parameters to your request was invalid.",
"type": "https://api.x.com/2/problems/invalid-request",
"errors": [
{
"message": "Invalid 'end_time':'2026-10-20T08:04Z'. 'end_time' must be a minimum of 10 seconds prior to the request time.",
"parameters": { "end_time": ["2026-10-20T08:04Z"] }
}
]
}
The fix X staff gave: set end_time at least 10 seconds in the past, or leave it out.
#Read public X data with one API key: Sorsa API
If your failing calls only read public data, Sorsa API, a Twitter (X) API and scraper, takes most of this page off your desk. It needs one API key in an ApiKey header and no X developer account, app, Project or OAuth, so 401 signature errors, client-not-enrolled, 453 and 402 never apply to it. Your own X account never touches it either.
Sorsa API returns every error in one body shape, {"message": "..."}, and these are the statuses you will see:
| Status | On Sorsa API | Fix |
|---|---|---|
| 400 | A parameter is missing or malformed | Fix the parameter |
| 401 | invalid api key | Copy the key from the dashboard again |
| 403 | missing key in request header, or the key's requests ran out | Send the ApiKey header; top up or upgrade |
| 404 | The post or account doesn't exist or is protected | Check the ID |
| 429 | More than 20 requests in one second | Wait one second |
| 500 | A failure on our side | Retry after 1 to 2 seconds |
400
- On Sorsa API
- A parameter is missing or malformed
- Fix
- Fix the parameter
401
- On Sorsa API
invalid api key- Fix
- Copy the key from the dashboard again
403
- On Sorsa API
missing key in request header, or the key's requests ran out- Fix
- Send the
ApiKeyheader; top up or upgrade
404
- On Sorsa API
- The post or account doesn't exist or is protected
- Fix
- Check the ID
429
- On Sorsa API
- More than 20 requests in one second
- Fix
- Wait one second
500
- On Sorsa API
- A failure on our side
- Fix
- Retry after 1 to 2 seconds
We sent the key errors to the live API on November 2, 2026. A header spelled Api-Key instead of ApiKey counts as no key at all, and the call returns 403:
curl "https://api.sorsa.io/v3/info?username=error_codes_demo_acct" \
-H "Api-Key: YOUR_API_KEY"
{"message": "missing key in request header"}
With the right header and a wrong key, the same call returns 401 and {"message": "invalid api key"}. Failed requests are never charged, and the Sorsa API error codes (opens in a new tab) page in the docs lists each status with its causes.
-
Get a key. Sign up and copy your API key from the dashboard. The first 100 requests are free.
-
Read up to 100 posts in one request.
POST /tweet-info-bulk(opens in a new tab) takes post links or IDs and returns each post with its full author profile.Terminal curl -X POST "https://api.sorsa.io/v3/tweet-info-bulk" \ -H "ApiKey: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"tweet_links": ["2117203385470271488", "2117199027635167232"]}'Response200 OK { "tweets": [ { "id": "2117203385470271488", "full_text": "Two layers in every error: status, then cause.", "created_at": "2026-11-02T09:12:44Z", "lang": "en", "likes_count": 41, "retweet_count": 6, "reply_count": 3, "view_count": 5210, "user": { "id": "1592041833471827968", "username": "error_codes_demo_acct", "display_name": "Error Codes Demo", "followers_count": 1840 } }, { "id": "2117199027635167232", "full_text": "Retry 429 and 5xx. Fix everything else first.", "created_at": "2026-11-02T08:55:20Z", "lang": "en", "likes_count": 27, "retweet_count": 4, "reply_count": 2, "view_count": 3380, "user": { "id": "1592041833471827968", "username": "error_codes_demo_acct", "display_name": "Error Codes Demo", "followers_count": 1840 } } ] } -
Look up profiles the same way.
GET /info(opens in a new tab) returns one profile byusername,user_idoruser_link, and a 404 means the account is gone or protected. -
Watch the balance.
GET /key-usage-info(opens in a new tab) returns the requests left and the date they renew; the check itself is free. Retry a 429 after one second, and treat a 403 with a valid key as the signal to top up.
Reading posts by ID costs from $0.014 per 1,000 on Sorsa API, 100 posts per request, against $5.00 per 1,000 on the official X API, whose pay-per-use plan also stops at 3M post reads a month:
Official X API
$5,000
for 1M posts
$0.005 per post
Sorsa API
from$14
for 1M posts
from $0.014 per 1,000
From November 22, 2026, the official X API also bills the author profile that comes back with each post, $0.010 per user (X's notice (opens in a new tab)); every Sorsa API post carries its author's full profile in the same request. Sorsa API reads only: to post, like or send messages, keep the official X API for those calls.
#Fix the error in front of you, then move your reads
Almost every X API error resolves one of two ways: wait for a 429 or a 5xx, or change the request, keys, balance or app access for anything else. If your errors come from reading public posts, profiles or followers, switch those reads to Sorsa API: one API key, plain error messages, 20 requests per second on every plan and posts from $0.014 per 1,000, with 100 free requests to test it today.
#FAQ
Is there a full list of Twitter API error codes?
X no longer publishes one. Its current reference lists ten error statuses, without 402, and eleven problem types, while its numbered code table, last published in 2023, survives only in web archives and copies on GitHub. The tables on this page join both and add the codes developers report today, such as 453 and credits-depleted, each with its cause and fix.
What does "Could not authenticate you" (error 32) mean?
Error 32 means X couldn't verify the signature or credentials on the request, so it rejected the caller before reading the request itself. The usual causes are keys regenerated in the console but not in your code, an access token from another app, or an OAuth 1.0a signature built wrong. Code 135 carries the same message when your server's clock has drifted.
Why does Tweepy raise "403 Forbidden"?
Tweepy raises tweepy.errors.Forbidden for any 403 and puts X's codes in e.api_codes and the body in e.response.text. Code 453 means you called a v1.1 method through tweepy.API: use tweepy.Client instead. A client-not-enrolled reason means the app sits outside a Project, and code 261 means the app is set to Read only.
401 vs 403: what is the difference?
A 401 means X couldn't identify the caller: the keys, the token or the signature are wrong, and fixing the credentials fixes it. A 403 means X knows who you are and refuses the action: the app's access, enrollment, permissions or the target account block it. New keys won't fix a 403; the console setting or the request has to change.
Which API should I use to read X data without these errors?
For reading public X data, use Sorsa API: one API key in a header, no developer account, Project or OAuth, so the 401, 402, 403 enrollment and 453 errors of the official X API don't arise. It returns 100 posts per request from $0.014 per 1,000, at 20 requests per second on every plan, and failed requests are never charged.
#How we checked
On November 2, 2026, we read X's developer reference for response codes, rate limits and pay-per-use pricing, X's archived 2023 error code table, and the X Developers forum threads linked above, where X staff explain the 402, client-not-enrolled and 400 cases. We sent requests without a key and with a wrong key to the live Sorsa API and recorded both responses. The bulk response above is a trimmed example with a demo account, written from the live API reference.
Sources
- Response codes and errors, X developer docs (opens in a new tab)
- X API rate limits, X developer docs (opens in a new tab)
- X API pay-per-usage pricing, X developer docs (opens in a new tab)
- Twitter API error codes, X developer docs archived May 2023 (opens in a new tab)
- X API docs missing HTTP status code 402, X Developers forum (opens in a new tab)
- 402 credits-depleted despite a $20 balance, X Developers forum (opens in a new tab)
- Archive-level API access (client-not-enrolled and a 400), X Developers forum (opens in a new tab)
- X API expansions billing update, X Developers forum (opens in a new tab)
- Error codes, Sorsa API docs (opens in a new tab)