Get a key

Error codes

Download .md

Check the code field first. It puts the failure in one of two families, and each family has its own fix.

Request IDs

Every response carries an x-request-id header, and every error repeats it in the body as requestId: a 12-character hex string, unique to that request.

a refusal, with its id
HTTP/1.1 401 Unauthorized
x-request-id: 4f9c1ad3e0b7

{"error":"That is not a valid key.","code":"key_unknown","requestId":"4f9c1ad3e0b7"}

Log it, and include it when you contact us, especially about a 5xx. With the id, we can find the exact request in our logs.

Access codes

CodeHTTP statusMeaning
key_required401 The request has no key. Add key=<your key>, or send your secret key from a backend in an x-cs2-key header. A publishable key sent in that header with no Origin is refused with origin_required.
key_unknown401 The key is unrecognized: wrong format, a typo, or a key that does not exist.
key_disabled403 The key has been disabled. If that is unexpected, email hello@inspekt.gg.
tenant_suspended403 The account is suspended, and every request on it is refused. Email hello@inspekt.gg.
plan_required402 The account has no plan: it is new, its free trial has ended, or its subscription has ended. Every request is refused until the account starts a free trial or subscribes in the dashboard. See Terms 5.7 and 5.8.
not_in_plan402 The plan leaves this request out, for example a Lens key on the Inventory API. Move to Hobby or Pro in the dashboard.
origin_not_allowed403 The requesting page's origin is not registered for this key. Add it in the dashboard. Keys and origins explains how the origin is read.
origin_required403 The request carried a key without an Origin or Referer header. Put referrerpolicy="strict-origin" on the <img>, and on the <iframe> if you build it yourself (CS2Embed.mount() sets it), so the browser sends the origin even when the page's Referrer-Policy withholds the referrer. From a server, send an Origin header naming a registered origin. See Keys and origins.
token_required403 The account has Require tokens on, and the request carried the publishable key. Send a token minted by your server with the secret key. See Require tokens.
token_expired401 The token has expired. Mint another with your secret key. The Node example replaces its token a minute before it expires.
token_invalid401 The token is one we did not issue, or the secret key that minted it has been rotated or revoked, or the account's publishable key has been rotated since. Mint another.
secret_key_required403 POST /api/token was called with a publishable key or a token. Only the account's secret key can mint a token. See Minting a token.
quota_exceeded429 The plan's monthly quota for this kind of request is spent. Requests of that kind are refused until the quota resets at the end of the billing period, the time given in the Retry-After header and the error message. Other kinds keep working, and moving up a plan takes effect on the next request. See Limits & SLA.
ip_daily_limit429 One visitor address has reached the account's daily limit for this kind of request on this key. Retry-After points at the next 00:00 UTC. Other visitors are served as usual. Set the limit, or turn it off, in the dashboard; see Daily limit per visitor.
rate_limited429 Requests arrived faster than the plan's requests-per-second allowance, which all three surfaces share. Retry after the number of seconds in Retry-After. See Requests per second.

A refused request does not count toward any quota.

Refusals by surface

SurfaceReported as
/api/still, /api/inventory-lookup JSON: { error, code, requestId } (plus limit/used for quota_exceeded and ip_daily_limit), at the status above. On /api/still, a request for an image, such as an <img>, gets a webp card of the requested w × h with the status and the code drawn on it, at the same status. See Render API.
/embed A refusal card and a postMessage error event. See below.

The embed is a page, so it cannot return JSON. A refused /embed does both of these at once:

  1. Draws a refusal card in place of the viewer, with one sentence and the error code. The card can be framed on any site, so it appears wherever the misconfiguration is.
  2. Fires a postMessage error event: { channel: "cs2embed", type: "error", code, message }, addressed to the origin you set, or * with none. See postMessage API.

Use the card while you integrate, and log the event in production.

The visitor's browser also enforces the origin list. A served /embed sends the key's registered origins in a Content-Security-Policy: frame-ancestors header, so the browser draws the viewer only when every page around it is on that list. The refusal card goes out with frame-ancestors *, so it shows on whichever site used the key.

Fallback codes (embed only)

These occur after access is granted, when the item cannot be shown in the visitor's browser. The frame keeps the still it has already painted and puts the reason in a note over it. A frame with no still shows a 2D card in place of the 3D view. Either way, it fires a postMessage fallback event: { channel: "cs2embed", type: "fallback", code, message, id }.

CodeCard textCause
no-webgpu"The live 3D view needs WebGPU. Open this in Chrome or Edge." The visitor's browser has no WebGPU support.
no-item"No item was specified." Both inspect and s are missing.
bad-inspect"That inspect link could not be read." The inspect value cannot be decoded, for example a Steam Market or inventory link ending in M…A…D… or S…A…D….
not-in-catalog"This finish is not renderable yet." The inspect link names a real item and finish that the catalog does not have yet.
unknown-id"That item is not in the catalog." The s catalog id matches no item.
index-unavailable"The viewer is temporarily unavailable." The catalog index failed to load.
boot-failed"The 3D renderer could not start on this device." WebGPU was available, and the renderer failed to initialize.
load-failed"This item could not be loaded." The item's assets failed to load after the renderer started.

If you build embed URLs from your own data, validate the inspect links and catalog ids first. Invalid ones produce bad-inspect and unknown-id, the two fallback codes an integration produces most often.