Keys and environments

One API key authenticates your backend. Which environment a call belongs to follows from the key, not the URL — there is no second host to point at.

What a key looks like

pgs_live_8f3a1c9d2e7b4a6f5c0d1e2f3a4b5c6d7e8f9a0b14NXoq pgs_test_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1L0EZk

The prefix names the environment; the 46 characters after it are fixed-length and self-checking, so a truncated paste or mistyped character is refused as a 401.

The key is a server credential

It never belongs in a browser: a key readable from your page lets any of your players mint a session as any other player of yours. Keep it in your backend's secret store and call the mint endpoint from there. Your account starts with no key; your first admin claims their invite, enrols a second factor, and mints the first key themselves, shown exactly once. We store only a hash, so a lost key is replaced, never re-displayed. Keys are created, rotated and revoked entirely by your team, from the portal.

Test and live

Both environments are served by https://api.peritusgames.com. Keys are scoped to one environment each; an account may hold more than one live key and more than one test key at once. What they keep apart:

SeparatedHow
Player identityA test session produces ptr:test:<partnerId>:<playerId> — the same playerId is two different players.
The embed path/embed/test/<partnerId> instead of /embed/<partnerId>, same games host.
OriginsRegistered per environment; a test-registered origin can't embed the live frame, and the reverse.
OpponentsA test player is only ever matched with another test player; joining across environments is refused with 403 cross_environment_join.
ResultsThe results feed returns only rows for the key's environment, cursors included, but every match in it.
LicensingDecided per environment; a game enabled for test says nothing about live.

Reading your own account

One call answers “what have I got, and which environment am I in” — a build script or start-up check can ask it without anyone signing in:

GET /partner/me Authorization: Bearer pgs_test_<your key> 200 { "partnerId": "acme", "name": "Acme Arcade", "apiVersion": 1, "environment": "test", "games": ["streakpeaks", "pokersquares"], "origins": ["https://staging.acme.example"], "prices": { "usd_10": 700 }, "webhook": { "url": "https://staging.acme.example/hooks", "enabled": true, "consecutiveFailures": 0, "createdAt": 1785000000, "secretRotatedAt": 1785000000, "disabledAt": null } }

partnerId is what every uid and later record is built from. prices is sparse: an unpriced tier is absent rather than 0, since absent means our floor — read entryUsdCents on the tier ladder for what a player actually pays. webhook is absent when unconfigured, and never carries the signing secret, shown once, in the portal.

It is a read, and only a read. Changing any of it — minting a key, registering an origin, setting a price or a webhook URL — stays in the portal.

This response, like every one on this surface, is answered on your account's pinned version unless the call named a different one — see Versioning and change. apiVersion on the body is the version this call was actually answered on, always equal to the X-Peritus-Api-Version response header on the same reply — read whichever one your code already has in hand.

How two test players are paired

A stake joins the oldest waiting seat matching on game and tier whose stake is confirmed — deterministic, unlike live's skill-based pairing, so a two-account rig behaves the same on its fiftieth run as its first. A test key can also decide a match outright — see Testing your integration.

Licensing a game

Turning a game on for test is instant and self-service from the portal. Live access is requested from the same place and granted by someone on our side; withdrawable anytime, and a denial isn't final — but a game must be on in test first. The mint endpoint distinguishes a game licensed in the other environment (game_not_licensed_in_this_environment) from one licensed in neither (game_not_licensed) — both in Errors and limits.

Rotating a key

Rotation is an overlap, not a cutover: it mints the new key immediately — shown once — and schedules the old one for revocation seven days out; both mint valid sessions until then, and the portal shows a live countdown plus each key's last use. After revocation, calls with the old key answer 401 invalid_key — but that affects future mints only, so an already-issued token stays valid until it expires, up to an hour later. To stop sessions already in play, use the emergency stop in the portal instead.