Phoenix Prediction Docs

Environments

Sandbox and production, what each one holds, and the hosts and paths an integration uses

Every operator has two environments:

EnvironmentToken env and API header valueUse for
SandboxsandboxIntegration testing, your test wallet, staff training
ProductionprodReal players and real money

The value is prod, never production: a token or request with production is refused.

One Phoenix deployment serves both environments, on the same hosts. The launch token's env claim (or the X-Operator-Environment header on the Operator API) decides which environment a launch or request belongs to.

What Belongs to an Environment

Each environment has its own:

ValueNotes
Ed25519 public keyOne key, or two while you rotate (see Rotating a Key). Either verifies your launch tokens and your Operator API requests for that environment. Use a different key pair for sandbox and production
Wallet base URLWhere Phoenix sends that environment's wallet calls. A public https URL (see Wallet base URL)
Wallet API version1.0 by default; Phoenix switches an environment to 1.1 on request (see Positions)
Sites that embed itThe exact origins of your pages that frame the embed (see Allowed Origins)
StatusActive, Suspended or Archived. Only an Active environment takes launches; a launch into any other is refused with environment_not_active. Your Admin suspends and resumes it; Phoenix archives and restores it
CurationWhich events your players see, what is featured, and your category order (set in the back office per environment)
Order limitsEach currency's minimum and maximum order size. A save for one environment never changes the other's; a currency Phoenix adds to your operator starts with the same limits in both
Books and moneyTrades, positions and wallet moves are kept per environment and never mix
Wallet test resultsThe wallet test runs against one environment at a time

These are shared by both environments, because they belong to your operator:

ValueNotes
Operator code, name and display nameThe code is your iss; the display name shows in the embed's header
CurrenciesThe currencies your players can use, and their order. Only Phoenix changes them; each environment keeps its own limits for them (see above)
Languages and formatting countrySee Languages
Trading engine and feesSet by Phoenix
Events and categoriesA published event belongs to no single environment: it is visible in both, unless you hide it in one environment's Curation

Your back-office Admin can change the display name, time zone, languages, formatting country, each environment's currency minimum and maximum order, wallet URL, sites, key and status (suspend or resume) under Manage > Your operator. Only Phoenix creates an operator, sets its code, which currencies it takes and in which order, the trading engine, the fees and the wallet API version, and archives or restores an environment. A change to any of these from your staff is refused, with the message that only Phoenix makes it.

Keep environments separate

A production player launched with a sandbox token, or a production environment pointed at a test wallet, are launch bugs. Mint prod tokens only from production systems, with the production key.

What to Send Phoenix

For each environment:

  • Your Ed25519 public key. Phoenix stores the raw 32-byte key; send it as 64 hex characters or as a PEM public key. You keep the private key. To change keys later without a gap, see Rotating a Key.
  • Your wallet base URL, public and https.
  • The exact origins of every page that will frame the embed, for example https://acme.example and https://play.acme.example. A site's www twin comes with it (see Allowed Origins).
  • A test player for the wallet test: a player id that exists in that environment's wallet, with funds in a currency you offer.
  • Minimum and maximum order sizes for each currency you offer. Sandbox and production keep their own.

Once, for your operator: your display name, currencies, languages (default first), formatting country, and a business and a technical contact.

Rotating a Key

An environment holds one key, or two while you rotate. A launch token or an Operator API request signed with either key verifies, so you can move your signers over without refusing a single launch:

Send Phoenix the new public key. Phoenix registers it beside the current one.

Switch your signing to the new key. Until you do, tokens signed with the old key keep verifying. A token's kid header says which of the two keys signed it (see Key Id).

Ask Phoenix to retire the old key, by its key id. The environment goes back to one key. It never retires its only key, and never holds more than two.

Entering a new key under Manage > Your operator is a hard cut instead: it replaces the current key at once, and tokens and requests signed with the old key are refused from that moment. Use it when a key has leaked, and switch your signing at the same time.

Hosts and Paths

https://prediction.phoenixverse.io       Phoenix backend: APIs and the live connection
https://embed.prediction.phoenixverse.io Embed host: the iframe
Path (backend)Purpose
GET /healthLiveness probe (returns the plain body ok, unauthenticated)
GET /openapi.json, GET /docsOperator API OpenAPI spec and its Redoc UI
GET /.well-known/signing-key.pemPhoenix's public key, for verifying wallet calls (see Security)
/operator/api/*Signed Operator API
GET /embed/api/config, GET /o/{operator_code}/embed/api/configThe iframe's boot configuration, called by the embed with your launch token
/player/websocketThe embed's live connection, opened with your launch token

The embed URL is:

https://embed.prediction.phoenixverse.io/o/{operator_code}?token={JWT}

If the operator code in the path is not the token's iss, the launch is refused with operator_mismatch.

Token Examples

{
  "iss": "acme",
  "env": "sandbox",
  "currency": "KES",
  "iat": 1779100000,
  "exp": 1779100900
}
{
  "iss": "acme",
  "env": "prod",
  "currency": "KES",
  "iat": 1779100000,
  "exp": 1779100900
}

Both are visitor tokens; add sub, name and avatar for a player (see Launch Tokens).

Allowed Origins

Each environment lists the sites that frame the embed, as origins: scheme, host, and a port only if it is not the default. The embed can only be framed by https pages, so list https origins.

A listed site's www twin is always allowed with it: listing https://acme.example also allows https://www.acme.example, and listing https://www.acme.example also allows https://acme.example, with the same scheme and port, in both environments. An IP address or a single-name host such as localhost has no twin, and any other subdomain, such as https://play.acme.example, is its own entry. The list keeps what you entered; the back office shows the twins under it as Also allowed.

Phoenix saves each origin the way a browser writes it in its Origin header: the scheme and host in lowercase, the default port dropped, a trailing slash dropped, duplicates removed. HTTPS://Www.Acme.example:443/ is saved as https://www.acme.example. Phoenix refuses, and names, an origin no browser would ever send:

  • a wildcard such as https://*.acme.example (list each origin exactly);
  • a path, a query or a fragment;
  • credentials in front of the host;
  • a host with non-ASCII characters (write it in its xn-- form);
  • http, since the embed is framed only by https pages.

An origin saved earlier that does not meet these rules is refused by name the next time you save the environment, so replace it then.

The listed sites and their www twins are enforced in three places:

  • Framing. The embed page tells the browser that only the sites listed on the environment its launch token names (env) may frame it. A page on any other site gets a blank frame. List every site that frames the embed, staging pages included.
  • The bridge. The embed takes the framing page's origin from the browser, sends its events only to a listed site, and ignores commands from any other. Nothing the page claims in the iframe URL adds a site.
  • The boot configuration. GET /embed/api/config answers a browser only from one of the environment's listed origins, their www twins or a Phoenix host. A request from any other origin is refused with HTTP 403 and the body { "error": "origin_not_allowed", "message": ..., "details": {} }. The hosted iframe itself runs on Phoenix's embed host, so it is always allowed.

The origins are not a substitute for keeping tokens private: anyone holding a valid launch token can open the embed as that visitor or player until the token expires. Mint short-lived tokens and keep them out of logs and URLs you share.

Reaching a Development Wallet

Phoenix must be able to reach your wallet base URL from the internet. It never calls localhost, private addresses or plain http.

  • Deploy a sandbox wallet endpoint on a public https host.
  • During development, use an https tunnel that forwards to your local wallet service, and set the tunnel's URL as the sandbox wallet base URL.