Skip to content

Buy a ranked ticket

POST
/api/shop/ranked-ticket
curl --request POST \
--url https://foxleague.ai/api/shop/ranked-ticket \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "tx_hash": "example", "wallet_address": "example" }'

Records a ranked ticket after you paid for it with shopPay on the game contract, in FOXSY. Tickets are sold only once the competition levels are live (live in the status): pay only after a ranked start answered ranked_ticket_required. The payment must equal the ticket price (price_foxsy of the status) exactly; one payment buys exactly one ticket. A payment the contract refused (a gateway success whose result carries a return message) buys nothing. A short or wrong amount is refunded whole. The answer is the status with the tickets you now hold.

Who: a signed-in player with a team; wallet_address must be the session wallet and the payment must come from it.

Rate limit: at most 10 confirms per session wallet in any 60 seconds by default, counted together with the other paid confirms (POST /api/shop/confirm, POST /api/shop/waive-cooldown, POST /api/shop/medicine); one more is answered HTTP 429 before the payment is read.

Refusals:

  • Too many purchase confirmations: at most <n> per wallet every <s> seconds. Your payment is kept: confirm the same transaction again in <wait> <unit>. (tx_pending, HTTP 429 with a Retry-After header): this session wallet sent more confirms than its budget allows (10 within 60 seconds by default). The payment was not read: confirm the same hash again after the wait.
  • Wallet mismatch: sign with the correct wallet: wallet_address is not the session wallet.
  • Ranked games are free until the competition levels start on <time>: no ticket is needed yet.: the competition levels are not live yet, so no ticket is sold (<time> reads like 2026-11-09 14:00 UTC). The chain is not read and nothing is recorded: the payment is refunded by the unconfirmed-payment net.
  • Ranked games are free: no ticket is needed yet.: the same while no switch time is set.
  • Not registered: the wallet has no account yet. The payment is kept: confirm again after the registration.
  • Chain is temporarily unavailable. Please retry shortly. (tx_pending): the server cannot read the chain right now.
  • Could not verify transaction yet. Please confirm again in a moment. (tx_pending): the transaction is not final yet.
  • Transaction already processed: this transaction already bought a ticket or another product.
  • This payment was already refunded and cannot be used for a purchase.: this transaction was refunded.
  • Transaction paid <paid> but a ranked ticket costs <price> FOXSY.<refund note>: the amount is not the price; the payment is refunded whole. <paid> reads like 150 FOXSY.
  • Failed to record purchase. Your payment is kept: confirm again in a moment. (tx_pending): the ticket could not be written; confirm the same transaction again.
Media type application/json

A paid ranked ticket to record.

object
tx_hash
required

The hash of your shopPay payment of the ticket price (64 hexadecimal characters).

string
wallet_address
required

Your wallet; it must be the session wallet and the payer.

string
Example generated
{
"tx_hash": "example",
"wallet_address": "example"
}

Success or a refusal: read success (the refusals are in the description).

Media type application/json
object
code

A machine-readable reason next to error, set only where the caller must act differently. tx_pending: the payment was not refused but could not be verified yet; keep the transaction hash and confirm again with the same hash, never pay twice.

string | null
data

The answer. Present when success is true.

object
live
required

Whether ranked costs a ticket now: the competition levels switch has passed.

boolean
live_from

When the competition levels govern (RFC 3339, UTC); null while the switch is off.

string | null
price_foxsy
required

What one ranked game costs its starter, in whole FOXSY.

integer format: int64
tickets
required

The ranked tickets you hold: each pays for one ranked game against a real opponent.

integer format: int64
error

Why the request was refused, in plain words. Present when success is false.

string | null
success
required

true when the request did what it asked. false is a refusal: read error.

boolean
Example
{
"data": {
"live": true,
"live_from": "2026-11-09T14:00:00Z",
"price_foxsy": 100,
"tickets": 2
},
"success": true
}

No valid session. The body is plain text: Missing Authorization header, Invalid Authorization format, Invalid session token or Session expired or invalid. Sign in again.

Media type text/plain
string
Example
Session expired or invalid

The body does not match the request schema, for example a tx_hash that is not 64 hexadecimal characters. The body is plain text.

Too many confirms from this session wallet (10 within 60 seconds by default). The answer carries Retry-After and the usual JSON refusal with code: "tx_pending": the payment was not read, so confirm the same hash again after the wait.

Media type application/json
object
code

A machine-readable reason next to error, set only where the caller must act differently. tx_pending: the payment was not refused but could not be verified yet; keep the transaction hash and confirm again with the same hash, never pay twice.

string | null
data

The answer. Present when success is true.

object
live
required

Whether ranked costs a ticket now: the competition levels switch has passed.

boolean
live_from

When the competition levels govern (RFC 3339, UTC); null while the switch is off.

string | null
price_foxsy
required

What one ranked game costs its starter, in whole FOXSY.

integer format: int64
tickets
required

The ranked tickets you hold: each pays for one ranked game against a real opponent.

integer format: int64
error

Why the request was refused, in plain words. Present when success is false.

string | null
success
required

true when the request did what it asked. false is a refusal: read error.

boolean
Example generated
{
"code": "example",
"data": {
"live": true,
"live_from": "example",
"price_foxsy": 1,
"tickets": 1
},
"error": "example",
"success": true
}