Launch Tokens
Mint visitor and player JWTs for Phoenix Prediction iframe launch
Your backend mints Phoenix Prediction launch tokens. The browser receives a ready-to-use token, but it never sees your private signing key.
Phoenix Prediction launch tokens are EdDSA JWTs signed with your Ed25519 private key. Phoenix verifies them with the Ed25519 public key registered on your operator account.
Required Claims
| Claim | Required | Description |
|---|---|---|
iss | Yes | Your Phoenix Prediction operator code |
env | Yes | Operator environment: sandbox or prod |
typ | Optional (metadata) | visitor or player. Phoenix does not validate this claim; the visitor-vs-player distinction is enforced by the presence of sub (player) or its absence (visitor). |
aud | Optional | Audience claim. Phoenix does not verify it for launch tokens; if present, use the constant pmm_default. |
exp | Yes | Expiry time, Unix seconds |
iat | Recommended | Issued-at time, Unix seconds |
sub | Player only | Your player ID for this user |
name | Player only | Display name Phoenix can show in player-facing UI |
avatar | Player only | Avatar object |
currency | Yes (player) | Session money currency, e.g. USD or ETB. Required on every player token; a token without it (or with a currency outside your supported list) is rejected at connect. |
cfg | Optional | Per-user UI policy object, e.g. { "deposit": false }. Omitted -> all UI visible. |
Use short-lived tokens. A practical starting point is minutes, not hours. Phoenix can confirm the exact TTL target for your environment.
Environment Claim
env is not just metadata. It selects which Phoenix operator environment receives the launch.
env | Meaning |
|---|---|
sandbox | Test/review environment for staging launches, test wallets, discovery configuration, and operator training |
prod | Production environment for real players and production operations |
Each environment can have its own public key, allowed parent origins, wallet settings, discovery configuration, listings, and settlement mode. Mint sandbox tokens only for sandbox/testing traffic. Mint prod tokens only from production systems that are ready for real player activity.
Token Shapes
Use a visitor token when the user is not authenticated or should only browse.
{
"iss": "acme",
"env": "sandbox",
"typ": "visitor",
"aud": "pmm_default",
"iat": 1779100000,
"exp": 1779100900
}Visitor tokens must not include sub.
Use a player token after your site has authenticated the user.
{
"iss": "acme",
"env": "sandbox",
"typ": "player",
"sub": "operator-player-123",
"aud": "pmm_default",
"iat": 1779100000,
"exp": 1779100300,
"currency": "USD",
"name": "Player Name",
"avatar": { "kind": "none" }
}sub is your stable player identifier. Phoenix stores an internal player UUID, but wallet operations, bridge-facing support, and operator investigations continue to use the ID you supplied in sub.
Player display names are trimmed and capped at 80 characters. Player tokens without a valid name and avatar are rejected.
Avatar Values
Use none when you do not want to show an avatar:
{ "kind": "none" }If image avatars are enabled for your operator, Phoenix will provide the accepted image shape and validation rules.
Session Currency
Phoenix is multi-currency. The top-level currency claim selects the money currency for the player's whole session: every market they trade resolves under that currency.
currencymust be one of your operator's supported currencies. A token whosecurrencyis outside that list is rejected at connect (the socket never opens).currencyis required on every player launch token, including single-currency operators; omitting it rejects the launch at connect.- Set
currencyper launch to route a player to a specific currency (for example a USD player vs an ETB player).
Node.js Example
import { SignJWT, importPKCS8 } from 'jose';
const privateKeyPem = process.env.PHOENIX_PREDICTION_OPERATOR_PRIVATE_KEY_PEM!;
const key = await importPKCS8(privateKeyPem, 'EdDSA');
const now = Math.floor(Date.now() / 1000);
export async function mintPlayerToken(player: {
id: string;
name: string;
phoenixEnv: 'sandbox' | 'prod';
currency: string; // one of your operator's supported currencies, e.g. 'USD' or 'ETB'
}) {
return new SignJWT({
env: player.phoenixEnv,
typ: 'player',
sub: player.id,
currency: player.currency,
name: player.name,
avatar: { kind: 'none' },
})
.setProtectedHeader({ alg: 'EdDSA' })
.setIssuer('acme')
.setAudience('pmm_default')
.setIssuedAt(now)
.setExpirationTime(now + 5 * 60)
.sign(key);
}Token Rotation
When a token is close to expiry, the iframe can ask the parent page for a replacement. Your site should mint a fresh token for the same visitor or player session and send it to the iframe with pmm:setToken.