Skip to content
PONGITDOCUMENTATIONGitHub ↗Back to arcade ↗
V4 · Testnet
Docs/Technical reference

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 pathPurpose
GET /independent/configApproved manifest, admission gate, per-arena epoch/health and sponsoring status
POST /independent/transactionsAllowed signed lobby, family, profile, private-data, market or vault call
GET /independent/operations/:hashQueued, pending, confirmed or failed operation and available transaction reference
GET /independent/profile-migration/:addressPublic reserved username and avatar hint
GET /independent/player/:address/recentVerified recent summaries with versioned references and replay availability
GET /independent/player/:address/frequentVerified recent-opponent suggestions
GET /independent/player/:address/paymentsCurrent financial obligations and payment states
GET /independent/replay/:id?after=-1Up to 1,000 recorded revisions for this exact deployment
GET /independent/market/:id?player=0x…&side=0&shares=1000000000000000Market quote, position and published-result state
POST /independent/creditOwner-signed one-time test-credit request, bound to this vault and expiry
POST /independent/arena-commandOwner-signed renewal or revocation of an active arena binding
GET /independent/import/contactsLegacy HttpOnly app session; only the authenticated owner's old private contacts
POST /independent/diagnosticsLimited-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 pathPurpose / response
GET /healthok, chain head, queue/funding error and payment worker status; 503 if unhealthy
GET /configActive deployment, recursive legacy manifests, relayer and observed server time
GET /matchesCurrent match list in matches
GET /matches/:idMatch, clock, chain head and snapshot observation time; fresh=1 requests a fresh read
GET /player/:addressRatings, balances, active game and authorization/nonces needed by the app
GET /arcade/:addressCurrent arcade authorization information
GET /leaderboard?mode=0Player rows with current ratings and public profile data
GET /profiles?search=neonUp to 30 public prefix matches; also accepts a full address
GET /profiles/:addressSaved profile or the account's default avatar
GET /player/:address/recent-matchesUp to three cross-deployment summaries in Match
GET /history?before=BLOCKActive deployment's result history, up to 100 rows
GET /replay/:id?after=VERSIONUp to 1000 Frame records after the version cursor
GET /replay-status/v4:12Replay availability for a qualified reference
GET /tournamentsRecent tournament data in tournaments
GET /positions/:id/:addressPaid cost, due amount, position state and payment details
GET /payouts/:address?offset=0Paginated account payment history
GET /jobs/:idSanitized transaction job state, receipt hash, error and timing
GET /inputs/:id/:addressLatest input-lane state for a match/player
GET /alertsIndexed 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 pathBody / purpose
PUT /profileshandle, avatar integer 0–11; returns the saved public profile
DELETE /profilesRemoves the authenticated public profile
GET /notebookrevision, and saved iv/ciphertext if present
PUT /notebookExpected revision, base64url iv and ciphertext; returns new revision
GET /blocksOwn blocked addresses
POST or DELETE /blocksplayer address to block or unblock
GET /challengesOwn recent inbox, with expiry and room/transaction state
POST /challengesrecipient address or null for an open link, mode, ranked
POST /challenges/rematchmatchRef, such as v4:12; server verifies participation and derives opponent/rules
GET /challenges/:idA visible invitation; addressed links enforce their recipient
POST /challenges/:id/acceptAccept and reserve the room atomically
POST /challenges/:id/declineDecline a pending invitation
POST /challenges/:id/cancelCancel 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 pathPurpose
GET /interlude/configApp, rules, capacity, runtime admission and maintenance stage
GET /interlude/financeOwn rooms credit, wallet balance, vault/market nonces and recent positions
GET /interlude/markets/:id?side=0&shares=1000000000000000Quote, window version/cutoff, result, own position, payout and receipt
POST /interlude/finance/creditOwner-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/withdrawplayer, recipient, amount, nonce, deadline, owner signature bound to the rooms vault
POST /interlude/finance/retryMatch 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.

InterfaceData and authorization
GET /interlude/recent-matchesRooms 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=-1Rooms 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.