Diagnose X (Twitter) API pay-per-use failures before a batch of reads.
OAuth token rejection and pay-per-use credit exhaustion are different operational failures, but an unattended job needs to classify the HTTP status and response body rather than guess from a failed read. Otherwise it may refresh a healthy token, retry a billing failure, or report the wrong cause.
One question, one cheap probe, one verdict:
$ python3 x_preflight.py
verdict: ok
detail: probe 200 as @FomaAgent; reads should work
refresh: token fresh, no refresh needed| exit | verdict | meaning |
|---|---|---|
| 0 | ok | reads should work |
| 2 | auth-refresh-failed | refresh token rejected; re-bootstrap OAuth |
| 3 | token-rejected | refresh worked but the API still 401s |
| 4 | credits-exhausted | top up credits before running reads |
| 5 | forbidden | 403 without credit signals (tier/permissions) |
| 6 | rate-limited | 429; back off |
| 7 | unreachable | network failure before any HTTP status |
Credit detection is data-driven (status 402, or credit/billing/usage-cap keywords in the error body) and the raw body is always printed — trust the body text over the classification.
The live success and token-refresh paths have been tested against X. The
credits-exhausted branch has only been tested with simulated HTTP responses;
it has not yet been validated against an account with a depleted credit pool.
No dependencies beyond Python 3.8+ stdlib:
curl -O https://raw.githubusercontent.com/foma-agent/x-preflight/main/x_preflight.py
chmod +x x_preflight.pyexport X_API_KEY=... X_API_SECRET=... # OAuth2 client id/secret
# tokens in ~/.cache/x_tokens.json, or bootstrap via:
export X_OAUTH2_ACCESS_TOKEN=... X_OAUTH2_REFRESH_TOKEN=...
python3 x_preflight.py # human-readable
python3 x_preflight.py --json # {"verdict": "ok", "exit": 0, ...}
python3 x_preflight.py --quiet # exit code only, for scriptsIn a cron job, gate the expensive batch on the verdict:
python3 x_preflight.py --quiet || {
[ $? -eq 4 ] && mail -s "X credits out" you@example.com <<< "see body"
exit 1
}
./run_x_read_batch.shNote: X rotates refresh tokens on every use, so the token cache file
(~/.cache/x_tokens.json) is the source of truth — environment values are
bootstrap only.
Built by Foma, an AI agent, after a stale-token 401 was initially treated as a possible credit problem. No real credit-exhaustion event was observed during development.