Technical reference
HTTP API & WebSocket reference
Read application data and understand the authenticated transaction interfaces.
Independent human arenas#
All paths below are relative to https://pongit.xyz/api. Read-only methods require no passkey, except the explicitly private legacy contact import. Transaction bodies use {to, data} with ABI-encoded calls to the approved manifest only. Contracts verify the appropriate family, game-key or owner signature; this endpoint is not an arbitrary transaction relay. Responses identify a persistent operation, and an absent receipt never authorizes a new nonce.
| Method and path | Purpose |
|---|---|
GET /independent/config | Approved manifest, admission gate, per-arena epoch/health and sponsoring status |
POST /independent/transactions | Allowed signed lobby, family, profile, private-data, market or vault call |
GET /independent/operations/:hash | Queued, pending, confirmed or failed operation and available transaction reference |
GET /independent/profile-migration/:address | Public reserved username and avatar hint |
GET /independent/player/:address/recent | Verified recent summaries with versioned references and replay availability |
GET /independent/player/:address/frequent | Verified recent-opponent suggestions |
GET /independent/player/:address/payments | Current financial obligations and payment states |
GET /independent/replay/:id?after=-1 | Up to 1,000 recorded revisions for this exact deployment |
GET /independent/market/:id?player=0x…&side=0&shares=1000000000000000 | Market quote, position and published-result state |
POST /independent/credit | Owner-signed one-time test-credit request, bound to this vault and expiry |
POST /independent/arena-command | Owner-signed renewal or revocation of an active arena binding |
GET /independent/import/contacts | Legacy HttpOnly app session; only the authenticated owner's old private contacts |
POST /independent/diagnostics | Limited-key authenticated, bounded and private network measurements |
Ordinary movement goes directly to the assigned engine. Rules-14 controls bind both epoch and logical match ID; the browser journals the signed transaction before sending. launchClock(id) returns the shared countdown deadline and engine-clock observation for engine-ticks-v1 manifests. Snapshot events update the cache, while missing identity, nonce or result data requires an authoritative read.
Recovery errors retain a readable message plus code, source, retryAt and requestId where available. CONTRACT_REJECTED is distinct from a temporarily unavailable action. A 404 operation response is not proof that a previously submitted engine transaction failed. Historic reference format remains 10143:arena:epoch:id.
Base URLs and conventions#
HTTP base: https://pongit.xyz/api. WebSocket: wss://pongit.xyz/ws.
This reference describes the delivered application interfaces, not an unrestricted RPC service. Examples are inert text: this documentation never executes a transaction. Large integer values are encoded as decimal strings; use bigint rather than JavaScript Number for wei, nonces and physics values. Mode 0 is Classic, 1 is Chaos.
const response = await fetch('https://pongit.xyz/api/config');
if (!response.ok) throw new Error('Configuration unavailable');
const config = await response.json();
console.log(config.version, config.chainId, config.game);
Public reads#
| Method and path | Purpose / response |
|---|---|
GET /health | ok, chain head, queue/funding error and payment worker status; 503 if unhealthy |
GET /config | Active deployment, recursive legacy manifests, relayer and observed server time |
GET /matches | Current match list in matches |
GET /matches/:id | Match, clock, chain head and snapshot observation time; fresh=1 requests a fresh read |
GET /player/:address | Ratings, balances, active game and authorization/nonces needed by the app |
GET /arcade/:address | Current arcade authorization information |
GET /leaderboard?mode=0 | Player rows with current ratings and public profile data |
GET /profiles?search=neon | Up to 30 public prefix matches; also accepts a full address |
GET /profiles/:address | Saved profile or the account's default avatar |
GET /player/:address/recent-matches | Up to three cross-deployment summaries in Match |
GET /history?before=BLOCK | Active deployment's result history, up to 100 rows |
GET /replay/:id?after=VERSION | Up to 1000 Frame records after the version cursor |
GET /replay-status/v4:12 | Replay availability for a qualified reference |
GET /tournaments | Recent tournament data in tournaments |
GET /positions/:id/:address | Paid cost, due amount, position state and payment details |
GET /payouts/:address?offset=0 | Paginated account payment history |
GET /jobs/:id | Sanitized transaction job state, receipt hash, error and timing |
GET /inputs/:id/:address | Latest input-lane state for a match/player |
GET /alerts | Indexed integrity signals, not automatic sanctions |
Quotes and fixed-recipient retries#
POST /quote accepts matchId as a decimal string, side 0 or 1, and shares in base units. It returns amount, open, version, book and remainingUs. A quote is not a reservation or a transaction.
{"matchId":"12","side":0,"shares":"1000000000000000"}
POST /payouts/retry accepts an existing payment task id. It cannot specify a replacement recipient or amount. Throttling and onchain debt checks still apply.
Authenticate app requests#
POST /auth/challenge with player returns nonce, expires and the exact message to sign. POST /auth/session with player, nonce and signature establishes the app cookie. GET /auth/session checks it; DELETE /auth/session closes it. Do not invent or reuse the challenge message.
Private app calls use browser credentials, an allowed Origin and x-pongit-player matching the authenticated account. Cookie possession does not authorize an onchain spend.
| Method and path | Body / purpose |
|---|---|
PUT /profiles | handle, avatar integer 0–11; returns the saved public profile |
DELETE /profiles | Removes the authenticated public profile |
GET /notebook | revision, and saved iv/ciphertext if present |
PUT /notebook | Expected revision, base64url iv and ciphertext; returns new revision |
GET /blocks | Own blocked addresses |
POST or DELETE /blocks | player address to block or unblock |
GET /challenges | Own recent inbox, with expiry and room/transaction state |
POST /challenges | recipient address or null for an open link, mode, ranked |
POST /challenges/rematch | matchRef, such as v4:12; server verifies participation and derives opponent/rules |
GET /challenges/:id | A visible invitation; addressed links enforce their recipient |
POST /challenges/:id/accept | Accept and reserve the room atomically |
POST /challenges/:id/decline | Decline a pending invitation |
POST /challenges/:id/cancel | Cancel if eligible; a submitted job returns its actual state |
Signed gameplay and finance#
POST /queue accepts a signed player request including player, expires, signature, tournamentId and mode. GET /queue/:address retrieves that player's queue/room state. POST /queue/cancel uses a signed cancellation. POST /ready supplies the room ticket and bilateral match consent.
POST /inputs accepts { request, intent } and returns 202 after input-lane acceptance. request must target game.submitInput; the intent includes a signed client sequence. Lane states include accepted, superseded, submitted, confirmed and failed. Acceptance is not chain confirmation.
POST /relay accepts deployment, contract, functionName and ABI-ordered args, returning a 202 job acknowledgement. Supported calls are allowlisted and simulated; arbitrary contract calls are not accepted. Journal jobs use queued, signed, sent, succeeded, failed and superseded. In particular, a confirmed successful receipt is exposed as succeeded, while the input lane calls that state confirmed. GET /jobs/:id returns tx_hash and timing with queueMs, broadcastMs, confirmationMs and totalMs; durations not yet observed are null.
Owner signatures are required by financial contracts for purchases, withdrawals and registration. POST /faucet also verifies its signed test-credit request. Consult the actual typed-data and ABI definitions and client signing flow; the cookie is not a substitute.
POST /rpc exposes selected JSON-RPC methods. Contract reads/estimates are restricted to known deployments; raw transaction submission is reserved for onchain administrators, with target and chain checks.
Legacy requests#
GET /legacy/player/:address, /legacy/claims/:address, /legacy/history, /legacy/matches/:id and /legacy/replay/:id select an archive using ?deployment=v1, v2 or v3. Without that parameter, the handler defaults to V1. Replay/history cursors retain their meanings.
Legacy signed withdrawals go through the supported relay with the correct deployment. Never sign using the active V4 domain for a V1 vault.
WebSocket events#
The socket enforces the allowed Origin. It sends an initial head, then public head, match and job updates. Treat it as a notification feed and re-read current state after reconnecting; it is not a durable replay log.
An authenticated app client may send:
{"type":"subscribe-social","player":"0x0000000000000000000000000000000000000001"}
The player must match the app cookie. inbox is sent only to the relevant subscribed account; reload its inbox through HTTP. social-expired means authentication or account binding is no longer valid. The illustrated address is a placeholder, not a credential.
Errors and recovery#
Read the returned error and HTTP status rather than assuming every failure is 401. The current server commonly returns 400 for validation/authentication failures, 404 for missing routes/jobs, 409 for notebook revision conflicts, 410 for retired replays, 429 for traffic limits and 503 for unhealthy service status. RPC errors follow JSON-RPC envelopes.
Refresh expiring quotes and nonces after failure. Do not resend a different transaction for a job already signed or sent; recover its state and receipt first. No API route in this reference grants access to another player's private notebook.
Rooms acceptance recovery#
POST /interlude/offers/ready with {id, operation} stores the authenticated player's UI readiness separately from engine consent. The second ready player starts one persisted three-second offer.launch.at deadline. Repeated requests do not restart it. Updated clients send countdown: true with their acceptance preflight, which is rejected before this deadline. Older tabs that omit this countdown preflight must refresh before accepting. State and action responses include serverNow in milliseconds for display-clock synchronization; this field is excluded from lobby notification revisions. The existing signature checks and receipt acknowledgement remain mandatory.
POST /interlude/offers/accept with {id, operation} checks a duel before the SDK call. This HTTP response does not confirm engine consent. After a successful acceptMatch receipt, send {id, receiptHash, operation} to the same endpoint. The coordinator verifies the receipt's application, player and duel event before marking acceptance. alreadyAccepted: true means the client must observe the existing duel instead of sending another acceptance.
The browser keeps a pending receipt hash in this tab's session storage so F5 can resume acknowledgement without another transaction. A failed or uncertain engine send stops automatic submission and offers Retry acceptance, which restores the SDK nonce and checks the duel first. An unstarted expired offer requires an explicit rejoin; it does not generate replacement tickets indefinitely. Upstream HTTP 429 responses retain Retry-After through the rooms API.
Rooms notifications and service errors#
GET /interlude/config includes stateTransport (events or polling). The event adapter subscribes to interlude_subscribe("applied") on the deployment's node. It filters the application and subscription id, decodes contract events and reconciles discontinuities through the existing snapshot getter. The limited game key signs every command directly to the engine. The current compact rooms contract caches the verified SDK grant instead of receiving it with every movement.
An authenticated POST /interlude/presence heartbeat runs every ten seconds. rooms-changed notifications carry an account-specific revision and are sent only when the visible lobby changes. The browser coalesces refreshes and retains fallback polling. rooms-unavailable means the authorization service could not be reached: retain the local key, but do not perform unverified actions. rooms-expired is reserved for a verified invalid, revoked or expired session.
Rooms errors retain error and add code, source, optional retryAt (Unix milliseconds) and requestId. ENGINE_RATE_LIMIT identifies an upstream 429; ENGINE_COOLDOWN identifies an action prevented locally during backoff. ACCOUNT_RATE_LIMIT and API_RATE_LIMIT identify PONGIT's separate budgets. SESSION_UNAVAILABLE returns 503; SESSION_REJECTED returns 401.
ENGINE_PUBLICATION_UNAVAILABLE is a separate 503: the node has stopped accepting transactions because it cannot publish them. Recreating a player passkey does not repair publication. The relayer retains the exact pending transaction and slows its recovery checks; it does not replace that transaction or reset the sender nonce.
POST /interlude/diagnostics accepts an ephemeral browser instance UUID and up to 200 payload-free samples. These private operational counters have no public read endpoint and expire after seven days. They exclude command parameters, signatures, private keys, cookies and notebook content.
Rooms finance interfaces#
These paths are under /api, use the rooms HttpOnly cookie, allowed Origin and matching x-pongit-player. /interlude/auth/challenge and /interlude/auth/session authenticate possession of the scoped SDK session key and verify the owner grant, app, chain, epoch and expiry. This is not a spending authorization. The private socket subscription is subscribe-rooms; after rooms-changed, reload HTTP state. A rooms-expired notification requires reconnection.
| Method and path | Purpose |
|---|---|
GET /interlude/config | App, rules, capacity, runtime admission and maintenance stage |
GET /interlude/finance | Own rooms credit, wallet balance, vault/market nonces and recent positions |
GET /interlude/markets/:id?side=0&shares=1000000000000000 | Quote, window version/cutoff, result, own position, payout and receipt |
POST /interlude/finance/credit | Owner-signed expires and signature for this app's one-time test credit |
POST /interlude/finance/buy | {bet, signature} using Bet typed data, the rooms market domain and fresh market nonce |
POST /interlude/finance/withdraw | player, recipient, amount, nonce, deadline, owner signature bound to the rooms vault |
POST /interlude/finance/retry | Match id; the server derives this account's fixed payout identifier |
Financial mutations return the existing relayer job acknowledgement. GET /jobs/:id supplies the actual status and transaction hash. There is no public arbitrary rooms payload escape through /relay. All amounts and match ids are decimal strings; typed signatures bind chain 10143, exact contract and fresh sequential nonce. A quote is not a reservation. The game grant never signs a financial spend.
Room finance generations#
Financial GET requests accept app as well as financeId; financial POST requests include those fields in the body. They identify immutable deployments, not the currently selected room. Unknown applications and mismatched market bindings are rejected. Accounts expose earlier applications in archives, with separate balances and no automatic transfer. The active live-betting generation is realtime-v1 with manifest.betting: "realtime".
For live-betting markets, window[0] indicates current availability and window[1] binds the epoch and rules. It is not a block countdown. claimPreview returns eligible winnings plus refunds, the refund component, and readiness. Old window encodings remain unchanged.
Authenticated GET /interlude/finance returns the current financial manifest, balances, nonces, history and archives for previous generations. Use ?financeId= for the original room account or ?financeId=early-v1 for the early testnet account. Responses from GET /interlude/markets/:id include the match's fixed financial manifest and settlementPolicy.
Versioned Chaos interfaces#
These interfaces apply to human rules-6 and rules-8 manifests. The snapshot wire format remains version 6; the immutable rules number selects the physics kernel. Historical APIs and financial bindings keep their original meaning.
| Interface | Data and authorization |
|---|---|
GET /interlude/recent-matches | Rooms authentication; the account's three retained references from Envio, across generations, with score and replay availability. |
GET /interlude/replay?app=0x…&epoch=1&id=1&after=-1 | Rooms authentication; at most 250 recorded snapshots strictly after the revision cursor. Includes both balls and effects. |
chaosState(id) | Public atomic engine read of the complete header, eight packed state words, committed draw and pending verified draw. |
submitRandomness(id, request, signature) | Permissionless engine submission of the exact committed drand round. The contract checks context and BLS proof; no owner spending approval. |
recordMatch(id) | Permissionless Monad call to the financial adapter. It reads the published result and emits MatchRecorded for discovery. No caller-supplied scores or payout mutation. |
Replay responses distinguish available, pruned, not-recorded and awaiting-publication. Match references use 10143:app:epoch:id. A missing or retired replay does not remove the result or any financial right. Big integers in snapshots are decimal strings, not executable code.
The rules-6 pressure message uses a 32-bit rally number, separately from the score sum, and EIP-712 pressure domain version 2. Original rules-5 pressure signatures retain version 1. A financial manifest with rulesVersion: 6 or rulesVersion: 8 is checked against the actual immutable game and its sealed links before the worker starts.
Financial POST requests for buy, withdraw and credit include financeId for the intended account. A match cannot be reassigned to another market. EIP-712 spending signatures still target the selected market or vault address. A mismatched generation is rejected before enqueueing. Internal relayer jobs preserve roomApp and optional roomFinance; historical jobs without roomFinance keep their original destinations.