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_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1L0EZkThe 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:
| Separated | How |
|---|---|
| Player identity | A 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. |
| Origins | Registered per environment; a test-registered origin can't embed the live frame, and the reverse. |
| Opponents | A test player is only ever matched with another test player; joining across environments is refused with 403 cross_environment_join. |
| Results | The results feed returns only rows for the key's environment, cursors included, but every match in it. |
| Licensing | Decided 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.