Skip to main content
Every endpoint requires an API key sent as a bearer token:
There is no other authentication method. Cookies, query-string tokens and basic auth are not accepted — a key in a URL ends up in browser history, proxy logs and Referer headers, which is exactly where a credential should never be.

The shape of a key

The prefix is deliberate. Secret scanners — GitHub’s, GitLab’s, your own pre-commit hook — match on recognisable prefixes. A key that looked like an anonymous blob of base64 would sail through every one of them.

Keys are shown once

At creation we show you the full key exactly once. After that we store only its SHA-256 hash, so nobody — including us — can read it back. The dashboard shows a masked form (gpk_live_YOUR…HERE) which is enough to tell two keys apart and useless to anyone who steals it.
If you lose a key, you cannot recover it. Create a new one, move your integration over, then revoke the old one. There is no “show key again” and no support path that produces one, because there is no copy to produce.

Live and test keys

A test key is for wiring up and demonstrating an integration: it authenticates exactly like a live key and reads exactly the same real catalog, so your parsing, pagination and error handling get exercised for real. What it cannot do is create a rental. There is no sandbox substrate behind this API — a “test” rental would be an actual machine on actual hardware costing actual money. Rather than pretend otherwise, we reject the write and tell you why:
Every response to a test key carries a header:
Live responses do not. It is worth asserting on in CI — it catches the accident where a live key finds its way into a test environment, which is otherwise invisible right up until something bills.

Checking a key

GET /me is the cheapest way to confirm a key works and see what it may do. Use it as the health check in your integration’s setup step, not a catalog call.
string
Identifies the key in your dashboard and in support conversations. Not a secret.
string[]
What this key may do. See Scopes.
'live' | 'test'
Whether this key can spend money.
integer | null
A per-key override. null means the account default applies.

Authentication failures

All of these are 401, and all of them mean “get a working key” rather than “retry”: We answer unknown and revoked differently on purpose, because both are actionable by you and neither leaks anything: you already hold the key, so telling you its status reveals nothing an attacker could not learn by trying it. Contrast that with a rental id belonging to someone else, which returns 404 rather than 403 — there, distinguishing “does not exist” from “not yours” would confirm the existence of another account’s resource. Different question, different answer.

Keeping keys safe

  • Server-side only. Anything shipped to a browser or a mobile app is public, however well minified. There is no CORS configuration that makes a bearer token in front-end JavaScript safe.
  • Environment variables, not source. GPUOUTLET_API_KEY in your process environment or secret manager; never a literal in a repository, however private.
  • One key per integration. Separate keys for your scheduler, your dashboard and your CI mean you can revoke one without an outage in the others — and the usage panel tells you which one is misbehaving.
  • Scope down. A key that only reads the catalog cannot start a machine even if it leaks. See Scopes.
  • Cap the damage. A daily spend limit turns a runaway loop from an unbounded bill into a bounded one.

If a key leaks

Revoke first, investigate second. Revocation takes effect immediately.