Invalid API key (401): the fix.
A 401 from the CS2 API means the request had no usable key. MISSING_API_KEY: the x-api-key header was not sent. INVALID_API_KEY: the key is malformed, unknown, revoked or expired. Send the full cito_ key, trimmed, in the x-api-key header.
- HTTP 401
- x-api-key header
- 500 free requests / month
{ "success": false, "error": { "code": "INVALID_API_KEY", "message": "Invalid API key format", "status": 401, "docs": "https://citoapi.com/docs/authentication" }}The error
HTTP/1.1 401 Unauthorized
{"success":false,"error":{"code":"INVALID_API_KEY","message":"Invalid API key format","status":401}}What does a 401 from the CS2 API mean?
The API could not match the request to an active key, so it refused before running the query. The error code says which check failed. A 401 never counts against your monthly requests.
| error.message | Cause |
|---|---|
| API key is required. Include your key in the x-api-key header. | No x-api-key header (code MISSING_API_KEY). |
| Invalid API key format | The value does not start with cito_ or is not 69 characters long. |
| Invalid API key | Well-formed, but no such key exists (a typo, or a key from another account). |
| API key has been revoked | The key was deleted or rotated in the dashboard. |
| API key has expired | The key had an expiry date and it has passed. |
Why does it happen when the key looks right?
Almost always the value sent is not the value you think. Environment files keep quotes, a trailing newline or a space; a key copied from a terminal can lose characters; a framework can drop custom headers on redirects.
- Quotes or whitespace from .env: CITO_API_KEY="cito_..." read by a loader that keeps the quotes.
- A trailing \n from echo or a secrets manager, which makes the length 70.
- The header name misspelled (x-apikey, api-key) or put in the query string on REST calls.
- A redirect from http:// to https:// that strips custom headers. Call https://api.citoapi.com directly.
- The key rotated in the dashboard while an old deploy still uses the previous one.
How do I fix it?
Read the key from the environment, strip whitespace and quotes, check the cito_ prefix and the 69-character length before sending, and put it in the x-api-key header. Authorization: Bearer <key> also works.
import os, requests
key = os.environ["CITO_API_KEY"].strip().strip('"').strip("'")
assert key.startswith("cito_") and len(key) == 69, f"bad key: length {len(key)}"
r = requests.get(
"https://api.citoapi.com/api/v1/cs2/matches/live",
headers={"x-api-key": key},
timeout=10,
)
if r.status_code == 401:
print(r.json()["error"]) # code + message say which check failed
r.raise_for_status()
print(r.json()["data"])const key = (process.env.CITO_API_KEY ?? "").trim().replace(/^["']|["']$/g, "")
if (!key.startsWith("cito_") || key.length !== 69) throw new Error(`bad key: length ${key.length}`)
const res = await fetch("https://api.citoapi.com/api/v1/cs2/matches/live", {
headers: { "x-api-key": key },
})
const body = await res.json()
if (res.status === 401) console.error(body.error) // { code, message, status, docs }
console.log(body.data)curl -s https://api.citoapi.com/api/v1/cs2/matches/live \
-H "x-api-key: $CITO_API_KEY"What if it still fails?
Create a new key in the dashboard and try it with curl from your own machine. If curl works and your app does not, the app is sending something different; log the key's length and first 9 characters, never the whole key.
How does the CS2 API keep this from happening?
Every 401 names the exact check that failed (missing, malformed, unknown, revoked or expired), so you fix it once instead of guessing. Keys have one fixed format, cito_ plus 69 characters in total, which you can validate in code before the first request, and a new key works the moment the dashboard shows it.
Frequently asked questions
Something missing? Email support@citoapi.com.
What does INVALID_API_KEY mean?
The CS2 API received a key but could not accept it: it is malformed (not cito_ plus the right length), unknown, revoked or expired. The error message names which one.
Which header does the CS2 API use for the key?
x-api-key. The API also accepts Authorization: Bearer followed by the key.
Does a 401 use up my monthly requests?
No. A request rejected for a missing or invalid key is refused before it is counted.
Can I put the API key in the URL?
Not for REST calls: send it in the x-api-key header. Only the WebSocket upgrade also accepts an apiKey query parameter, because browsers cannot set headers on WebSockets.
Next steps
- CS2 API in PythonLive scores, results and player stats with requests.
- CS2 API documentationAuth, the response envelope, errors, rate limits and every endpoint.
- CS2 API pricingFree, Starter, Pro and Scale: requests, live delay and history per plan.
- CS2 API in Node.jsFetch CS2 data from JavaScript and TypeScript.
- How to get CS2 match dataResults, maps and player lines for any pro match in three requests.
- CORS error on browser requestsWhy the browser blocks the call, and the small proxy that fixes it.
Build CS2 live score apps
Free is for building and testing. Paid plans add commercial use, real-time live data and the full archive.