Phoenix Prediction Docs

Errors

Common public error codes and meanings

Wallet-Facing Errors

How your wallet should answer Phoenix. See Errors on the wallet operations page for how each answer is read.

SituationRecommended response
Player does not have funds for reserve_cashHTTP 422 with code: "insufficient_funds"
Your wallet will not take a bet for another reason (a limit, a closed account)HTTP 422 with a code of your choice. Only reserve_cash may be declined
Phoenix signature is invalidHTTP 401
Request body is malformedHTTP 400
Same idempotency key is still processingReturn the stored result once ready, or HTTP 409 or 503. Phoenix sends the move again either way
Same idempotency key is reused with a different payloadHTTP 422
Temporary outageHTTP 503

Launch Refusals

A launch token Phoenix refuses is answered by the embed's boot configuration call with a body of { "error", "message", "details" }, one code per reason (malformed_token, invalid_signature, unknown_key, token_expired, environment_not_active, unsupported_currency and the rest). The full list, with each code's HTTP status and details, is under Refusals You Can Read. The embed also reports the code to your page as an error event (see Parent Bridge).

Player-Facing Phoenix Reasons

When a player command is rejected, the command reply carries a structured reason:

{
  "kind": "command",
  "outcome": "rejected",
  "reason": {
    "code": "validation",
    "message": "insufficient funds",
    "details": { "reason": "insufficient_funds" }
  }
}

reason.code is a closed set. Branch on it in client code; never parse reason.message, which is a human-readable string for display and logs. A reason can also carry details, and on internal reasons retriable (true when trying again may work) and sometimes retry_after_ms.

Every refused bet names what happened in reason.details.reason: the order's own reason (for example insufficient_funds, wallet_declined, wallet_not_called, expired, market_closed, market_paused, insufficient_position), or the one Phoenix refused it with before it reached the market (for example below_min_order_size, above_max_order_size, player_banned, operator_not_active). The coarse reason.code puts several of these under validation, so word a refusal from details.reason, never from code alone: a wallet that declined a bet is not the player's order being invalid. The embed does this for you (see Player Protection).

When your wallet declines a reservation with any code other than insufficient_funds, the reply also names your code:

{
  "kind": "command",
  "outcome": "rejected",
  "reason": {
    "code": "validation",
    "message": "your wallet declined this bet",
    "details": { "reason": "wallet_declined", "wallet_code": "limit_exceeded" }
  }
}

The embed shows the player what your code means, which you set under Player protection in the back office; Phoenix gives limit_exceeded, self_excluded, cooling_off, verification_required, account_blocked and player_not_found a meaning already (see Declining a Reservation).

When Phoenix did not send the reservation to your wallet at all, because one of its own rules refused it (for example wallet_url_not_public), the reply says so and names Phoenix's code instead:

{
  "kind": "command",
  "outcome": "rejected",
  "reason": {
    "code": "internal",
    "message": "this bet could not be sent to your wallet; nothing was taken",
    "details": { "reason": "wallet_not_called", "phoenix_code": "wallet_url_not_public" }
  }
}
reason.codeMeaning
validationThe request was well-formed but invalid for the market or order (amount, price, size off the market's grid, or the wallet declined the reservation)
not_foundThe market does not exist, or is not offered to this operator
forbiddenThe action is not allowed (operator not active, player blocked, currency not supported, not the order owner, a field the command does not take)
conflictThe request conflicts with the current state (market closed, paused, resolved, not yet open, order already finished, idempotency key reused with different parameters)
rate_limitedPhoenix is busy; try again shortly
internalPhoenix could not complete the command; see the message, and retriable

A bet sent without an idempotency key is refused with idempotency_required. One more code is reserved but not sent today: unknown_mutation. A command the embed's connection does not know is answered unknown_request, and a player-only command from a visitor login_required.

The reason.message strings, by code:

reason.messagecodeWhen
insufficient fundsvalidationYour wallet declined the reservation with insufficient_funds
your wallet declined this betvalidationYour wallet declined the reservation with another code, carried in reason.details.wallet_code
this bet could not be sent to your wallet; nothing was takeninternalPhoenix did not send the reservation: one of its own rules refused it before any request. Phoenix's code is in reason.details.phoenix_code
invalid ordervalidationThe order failed validation (quantity, price, or budget)
invalid order: <field>validationA named field of the order is invalid
a market order cannot carry a limit pricevalidationA market order included a limit price
insufficient position to sellvalidationThe sell exceeds the player's position
order is below the minimum order sizevalidationUnder your minimum for the currency
order exceeds the maximum order sizevalidationOver your maximum for the currency
amount has more decimals than the currency allowsvalidationThe cash amount has more decimals than the currency, or the share quantity is not on the market's grid (see Order size precision)
no fee schedule configured for this marketvalidationYour operator has no fee schedule yet; Phoenix sets it
invalid environmentvalidationThe session's environment is not valid
invalid payload: ...validationA field of the command has the wrong type
market not foundnot_foundThe market does not exist, is not offered to this operator, or is hidden by its Curation
operator is not active for tradingforbiddenYour operator is suspended or not enabled
player is banned from tradingforbiddenYour support team blocked this player in the back office
currency not supported by this operatorforbiddenThe currency is not one of yours
not the order ownerforbiddenA cancel targeted another player's order
fields not accepted: ...forbiddenThe command states a field it does not take
market is closedconflictThe market no longer accepts orders: it is closed or on hold, or the order reached the book after its close time
trading is pausedconflictYour operator's book on this market is suspended
market is not yet openconflictThe market is not published yet
market is closed for new positionsconflictThe market is resolved or void
order already filled or cancelledconflictA cancel arrived after the order finished
idempotency key reused with different parametersconflictThe same idempotency key was sent with a different order
market is opening - retry shortlyrate_limitedYour operator's book on this market is being opened by its first order
order intake is at capacity - retry shortlyrate_limitedPhoenix has too many orders in flight, or too many of yours are waiting on your wallet. A new order waits at most about a second for room, then is refused instead of queuing; nothing was taken. Try again shortly
the wallet did not confirm the bet in time; any money held for it is returnedinternalYour wallet did not fund the buy within 60 seconds. Any money your wallet holds for it is released. retriable is true: the player may place it again
the order could not be fundedinternalThe reservation could not be matched to the order
order service temporarily unavailableinternalA temporary problem; try again
market temporarily unavailableinternalThe market's book could not be opened; try again

A retry under the same idempotency key with identical parameters is safely de-duplicated: it returns the original order with no error. Only a key reused with different parameters conflicts. A resend of a bet Phoenix already took is answered with that bet's first outcome, even if the market has closed since.

When Phoenix cannot tell whether a bet was taken (it could not confirm that it stored the order), it answers with an error reply unconfirmed, not a refused command: the bet may exist. Send the same bet again under the same idempotency key, and do not mint a new key, which would be a second bet. The reply to the resend says what happened, and Phoenix takes the bet once either way.

A buy reply waits up to 5 seconds for the order's outcome. If your wallet has not answered by then, the reply is accepted, and a later refusal shows on the order itself (below).

Show friendly copy to players. Keep reason.code and reason.message in logs for support.

Rejected After Acceptance

An order can be rejected after Phoenix accepted it, for example when your wallet answers after the reply. The player then sees the order end as rejected, and your support team reads why on the order in the back office (Trades and the player's page). The stored reason is one of:

Stored reasonMeaning
insufficient_fundsYour wallet declined the reservation with insufficient_funds
wallet_declined:<code>Your wallet declined the reservation with <code> (older orders may show wallet_declined alone)
wallet_not_called:<code>Phoenix did not send the reservation: one of its own rules refused it, with Phoenix's <code> (for example wallet_url_not_public). Your wallet was never called
expiredYour wallet did not fund the order within 60 seconds. Any money it holds for the order is released
stake_precisionThe amount or quantity is not on the market's grid
market_pausedYour operator's book on the market was suspended when the order reached it
market_closedThe market was closed or on hold, or the order reached it after its close time
invalid_orderThe order failed validation
market_order_with_limitA market order carried a limit price
insufficient_positionA sell exceeded the player's position when it reached the book
unfunded_order, reserve_mismatch, not_fundableThe reservation could not be matched to the order

When the book refuses an order your wallet had funded, the reservation is released with a release_cash (reason ORDER_REJECTED). When your wallet declined the reservation, nothing was held and nothing is released.

Operator API Errors

See Operator API errors.