Quickstart
Six steps from an API key to an embedded game, a seventh to a played match — the same hosts, paths and payloads production uses.
The hosts
| What | Where | Called by |
|---|---|---|
| API | https://api.peritusgames.com | your backend |
| Game frame | https://games.peritusgames.com | your page (iframe) |
| Partner portal | https://peritusgames.com/portal | your team (browser) |
One API host serves both environments; which one a call lands in follows from the key, never the URL — see Keys and environments.
Before you start
- Your account's partner id — 3–32 characters of lowercase letters, digits and hyphens (acme below).
- A test API key, minted by your first admin in the portal.
- The origin that will embed the frame, registered in the portal — until then the frame refuses to render. See Embedding a game.
1. Mint a session, from your server
curl -X POST https://api.peritusgames.com/partner/sessions \
-H "Authorization: Bearer pgs_test_<your key>" \
-H "Content-Type: application/json" \
-d '{
"playerId": "u_8813",
"gameId": "streakpeaks",
"displayName": "Ada Lovelace"
}'2. Read the response
200 {
"uid": "ptr:test:acme:u_8813", // a TEST key — a live one gives ptr:acme:u_8813
"token": "eyJhbGciOiJIUzI1NiJ9…",
"expiresAt": 1754211600,
"displayName": "Ada Lovelace"
}Valid one hour, scoped to that player and game; mint per session, do not store it. The uid is derived from playerId — store it. Full rules in Identifying your player.
3. Embed the frame
<iframe
src="https://games.peritusgames.com/embed/test/acme"
allow="fullscreen; clipboard-write"
title="Streak Peaks"
></iframe>The path segment is your partner id, not your key — no credentials here. Live drops /test.
4. Answer the handshake
const GAME_ORIGIN = "https://games.peritusgames.com";
window.addEventListener("message", async (e) => {
if (e.origin !== GAME_ORIGIN) return;
if (e.data?.type === "ready") {
frame.contentWindow.postMessage({
type: "init",
token: session.token,
uid: session.uid,
dealerUrl: "https://api.peritusgames.com",
gameId: "streakpeaks",
}, GAME_ORIGIN);
}
if (e.data?.type === "needToken") {
const fresh = await mintSession(); // same player, same game
frame.contentWindow.postMessage(
{ type: "token", token: fresh.token },
GAME_ORIGIN,
);
}
});Every message your page sends and trusts is listed in Embedding a game.
5. Read the result from your server
curl "https://api.peritusgames.com/partner/results?limit=50" \
-H "Authorization: Bearer pgs_test_<your key>"The authoritative outcome — the frame never reports a score to your page. See Match results.
6. Go live
Move your backend to a live key and your page to the live embed path; the base URL stays the same. Live access is per game, requested from the portal.
7. Play for a prize
This step seats a match. Live play needs a live key plus two more calls — GET /partner/tiers for the ladder, POST /partner/matches to seat a player — free of charge with a test key. The handshake's init message must also carry seating: "host", which puts the tier cards in the frame — omit it and your player has no way in. To seat from your own page instead, send route. Paid matches has the full treatment.
A paid match seats two players of the same operator — never paired with ours or another platform's. Plan your liquidity on that.
The games, and their ids
The gameId in every call is one of these, licensed per environment: test instant and self-service, live requested the same way.
| Game | gameId |
|---|---|
| Streak Peaks | streakpeaks |
| Poker Squares | pokersquares |
| Spades | spades |
| Streets | streets |
| Dice 13 | dice13 |
| Press | press |
| Squeeze | squeeze |
| 21 | twentyone |
Each game runs, playable and without an account, from the games page.