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

WhatWhereCalled by
APIhttps://api.peritusgames.comyour backend
Game framehttps://games.peritusgames.comyour page (iframe)
Partner portalhttps://peritusgames.com/portalyour 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.

GamegameId
Streak Peaksstreakpeaks
Poker Squarespokersquares
Spadesspades
Streetsstreets
Dice 13dice13
Presspress
Squeezesqueeze
21twentyone

Each game runs, playable and without an account, from the games page.