Authentication: one header, one key
The Supply API has exactly one credential and one way to present it. There is no login call, no token exchange and no refresh cycle — a key you were issued at onboarding is the whole of it.
The header
Send X-Api-Key on every request under /b2b/:
GET /b2b/catalog/games HTTP/1.1 Host: api.gamecore-api.tech X-Api-Key: gc_live_…
Authorization: Bearer … is not read anywhere on this API — a request that carries only a bearer token is an unauthenticated request. There is no query-parameter form either, deliberately: keys in URLs end up in proxy logs, browser history and Referer headers.
What a key looks like
A key is a prefix plus 48 hexadecimal characters:
| Prefix | Meaning |
|---|---|
gc_live_ | Issued as a live key. |
gc_test_ | Issued as a test key. |
Two properties of that string are worth knowing before you build tooling around it:
- We never parse the prefix. A key is looked up by a hash of the whole string. The live/test distinction is a property of the account record, not of the characters — so do not infer behaviour by matching on
gc_live_. - The key is a bearer secret in the literal sense. Anyone holding it can spend your balance. Keep it in your server-side secret store, never in a frontend bundle, never in a repository, never in a support ticket. If one leaks, tell us and we will rotate it; rotation keeps the same prefix.
Keys can also carry an expiry date and a domain allowlist. If either is set on your key, a request outside it fails as an ordinary 401 — see below.
Live and test keys
There is no sandbox on /b2b/*. A test key on these endpoints reads the real catalog, spends your real balance and sends real orders to real suppliers. Nothing in the B2B code path so much as looks at which kind of key you used.
This is the single most expensive misunderstanding available on this page, so it is stated first. The test/live distinction does exist on the platform, but it gates a different surface — a separate set of simulation endpoints outside /b2b/ that supply partners do not use.
The practical consequence for your integration: there is no free way to exercise the order path. What you can do without spending anything:
- Run the whole catalog side against your key. Reads are free and unlimited within the rate limit.
- Exercise your order code against a cheap SKU, then keep the order — it will be delivered.
- Ask us before a load test. We would rather widen a limit for you than watch a burst turn into 429s.
When you get 401
{ "error": "Unauthorized", "message": "Invalid or missing API key" }
One body for five different causes, on purpose — an attacker probing keys learns nothing from the difference:
- No
X-Api-Keyheader at all. - A key that does not exist, or has been deactivated.
- A key past its expiry date.
- The account behind the key is inactive.
- The request carried an
Originoutside the domain allowlist configured on that key.
Note the envelope: { error, message }, with no success field. Business errors use { success: false, error } instead, so a client that branches on response.success sees undefined on exactly the failure it will hit first. Branch on the HTTP status.
When you get 403
Two distinct bodies, two distinct fixes:
{ "error": "Forbidden", "message": "This endpoint is only available for B2B API partners" }
The key is valid, but the account behind it is a storefront account rather than a supply account. Nothing you can do from your side — tell us and we will switch it.
{ "error": "Forbidden", "message": "This API key is not authorized for this endpoint" }
The key is scoped for public reads only. Supply keys are always issued full-scope, so if you see this you have picked up the wrong key from your own configuration.
Rate-limit headers
Almost every response — successful ones included — carries your remaining budget:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current window. |
X-RateLimit-Remaining | How many are left. |
X-RateLimit-Reset | Seconds until the window rolls over. |
"Almost" has one known exception, and it is structural rather than accidental: the CSRF origin check runs before the rate limiter, so a write request rejected with 403 Forbidden: Origin not allowed never reaches the code that sets these headers and arrives without them. Treat the headers as absent-able and branch on the status first — a missing X-RateLimit-Remaining does not mean zero budget.
The default budget is 500 requests per minute, counted per client IP rather than per key. Over it you get a 429 carrying Retry-After and a body with code: "RATE_LIMITED" and retryAfter in seconds. If your traffic legitimately needs more than that — a nightly full catalog sync, for instance — talk to us rather than sharding across IPs. Idempotency and errors has the details and the backoff advice.
Never call this API from a browser
Not a style preference — two mechanisms enforce it. Any key shipped to a browser is a published key, and a write request that arrives with an Origin header outside the allowlist is rejected with {"success": false, "error": "Forbidden: Origin not allowed"}. Call /b2b/ from your backend and expose your own endpoints to your frontend.
Why not OAuth
A reasonable question if you have integrated other wholesale APIs, so here is the honest answer rather than a shrug.
OAuth solves delegated access: a user authorises an application to act on their behalf, with scopes and short-lived tokens so the application never holds the user's password. This API has no user to delegate from. There is your company, your balance and your server. The only party that could authorise anything is you, to yourself.
Bolting a token exchange on top of that would add a round trip, a token cache, a refresh failure mode and a clock-skew failure mode, and would buy exactly one real property: shorter credential lifetime. We provide that differently — keys can be expired, scoped to a domain allowlist and rotated on request, and every call is over TLS to a single host. If your security review needs a specific control (IP allowlisting, scheduled rotation, a second key for staging traffic), ask us; those are account settings, not protocol changes.
The interactive reference
These pages are the documentation. As a partner convenience there is also a generated, browsable OpenAPI reference at api.gamecore-api.tech/reference?key=…, which renders the machine-readable spec of the whole API and lets you fire requests from the browser.
Two caveats, both real:
- It needs a valid key in the URL. That puts a live secret into browser history and any intercepting proxy. Use it from a machine you control, and prefer a key you are willing to rotate.
- It documents the entire platform, not just the supply surface, so it will show endpoints your key cannot reach. Where it and these pages disagree, these pages were verified against the code more recently.
The plain api.gamecore-api.tech/docs URL is gated for the same reason and is not a public page.
Before you go live
- The key lives in a server-side secret store and appears in no client bundle.
- Your client branches on the HTTP status, not on a
successfield that is absent from auth errors. 401and403are alerted on separately: one is a credential problem, the other is an account problem.X-RateLimit-Remainingis logged, so you learn about the ceiling before you hit it.- Nobody on the team believes a
gc_test_key is safe to point at/b2b/orders.
Updated August 18, 2026
See also: Supply API overview · Pricing and tiers
Need an API key?
Tell us which games and regions you sell and we will issue a key, then walk the integration with you. Integration questions are answered by the same people who run the API.