Overview
A terminal has to answer four questions at a glance: what do I hold, what is it worth, what is working, and how do I act. On a spot exchange that is largely solved by rendering the API’s response objects. Prediction markets break that assumption in one specific way. A position can be finished without being closed. The event concluded, the outcome is decided, the shares are worth a dollar each, and none of that money is available yet. A UI that models positions as open or closed will show users balances they cannot withdraw, and that generates support tickets faster than any other bug in this class of product. This guide builds the terminal around that distinction.Read time: about 17 minutes. TypeScript and general front-end experience assumed. No prediction market background needed.
TL;DR
- Four calls on load: account, balances, positions, open orders. Make account first, because it tells you which controls to render and how fast you may poll.
- Working orders and running strategies are separate endpoints. Merging them into one panel without fetching both is the most common terminal bug.
- Positions have four states, not two. Open, awaiting resolution, resolved-unredeemed, redeemed.
- Cost basis arrives computed. Do not reconstruct it from fills.
- Every number is a JSON string. Render with a decimal type or your balances will disagree with the venue by a cent.
- Generate the idempotency key when the user opens the ticket, not when the request fires.
What you will do
- Bootstrap a terminal with four calls and read capability off the account
- Render balances, positions, working orders, and running strategies
- Build an order ticket that handles all eight types through one code path
- Set per-panel polling intervals from your actual rate limit
- Model the four position states so users are never shown inaccessible money
- Handle
429and503without breaking the whole app
What you will need
Knowledge- TypeScript, and a UI framework of your choice
- A decimal library. Examples use
decimal.js.
- A Bravado API key with
trade.read, plustrade.executeif the terminal places orders - A backend. Keys must never reach the browser.
Bootstrap: the four calls
Why account comes first
It is not just identity. It carries two things that shape the entire UI:trade.withdraw produces a 403 the user cannot act on. Reading scopes lets you hide it instead of explaining it.
A read-only terminal is a legitimate product. Every Data API endpoint works on any public wallet with no funded account, so a free tier that shows any trader’s portfolio needs no provisioning at all.
Render the panels
Each panel has one source:
Working orders and running strategies are separate for a reason. A resting
LIMIT is on Polymarket’s book. A TWAP is a Bravado-side supervisor placing orders over time. They are genuinely different objects.
You can render them in one list, but you must fetch both, and you must keep track of which is which so cancel hits the right endpoint:
The order ticket
One endpoint serves all eight types, so the ticket is one code path with a changing payload:Generate the key at ticket-open
Surface warnings
200 with a failed bracket leg means the user holds a position with no exit and no indication anything went wrong. Show it.
Poll within budget
Different panels change at different rates, and polling everything on one fast timer burns quota on data that did not move:429.
Back off one panel, not the app
Model four position states
This is the part that matters most, and the part generic exchange UIs get wrong.
The two middle states are what make prediction markets different. Collapsing them into “closed” tells the user they have money when they cannot touch it. Collapsing them into “open” hides a redeem action they need to take.
Field names for the resolution flags depend on the response shape; confirm against the positions reference. The four-state distinction is the part that matters, not the exact field.
Render money correctly
0.62 is both 62 cents and a 62% implied chance. Showing 62¢ (62%) reads well and teaches the user the model without a tooltip.
Handle 503 as a state, not an error
Data API statement endpoints return503 with available: false while a wallet is still being computed. For a wallet nobody has queried before, this is normal.
Wrapping up
Four calls to bootstrap, one endpoint for every order type, and two things to get right that a generic exchange UI would not prompt you to consider: orders live in two places, and positions have four states. Everything else in a terminal is ordinary product work. Those two are where the domain leaks into the interface, and where users notice if you got it wrong.Frequently asked questions
Why can I not put the API key in the frontend?
Why can I not put the API key in the frontend?
A Bravado key can place orders and, with the right scope, move funds. Anything shipped to a browser or mobile app can be extracted. Your frontend should call your backend, and only your backend should hold the key.
Do I need websockets for live prices?
Do I need websockets for live prices?
The guides here use polling with per-panel intervals, which is sufficient for portfolio and order state. Match your interval to
rate_limit_per_min rather than polling as fast as possible.Why does a user's TWAP not appear in their open orders?
Why does a user's TWAP not appear in their open orders?
Managed strategies live on
/v2/trade/strategies. Only LIMIT, MARKET, and TAKE_PROFIT appear on /v2/trade/orders/open. Fetch both.A user says their winning position shows a balance they cannot withdraw.
A user says their winning position shows a balance they cannot withdraw.
They are in
resolved_unredeemed. The outcome is final and the shares are worth a dollar each, but the collateral is not in the wallet until redeemed. Surface a redeem action rather than showing it as available cash.Should I recompute cost basis from the trade log?
Should I recompute cost basis from the trade log?
No. Splits, merges, and redemptions are not ordinary buys and sells, and treating them as such produces a basis that disagrees with the chain. Positions come with cost basis already computed.
How do I support multiple end users?
How do I support multiple end users?
Provision each under a partner master key so they get their own wallet and scoped key, which makes positions and PnL attributable per user. See White-label sub-accounts.
Resources
- Display positions and PnL, cost basis and the four states in depth
- Track order and strategy state, the two-endpoint problem
- White-label sub-accounts, provisioning end users
- Place an order, every order type and its payload
- Trade API reference, full field documentation
- Rate limits, quotas and backoff