A fill is one execution of an order. An order can fill several times, at different prices and with different liquidity roles. Keep individual fills for inventory and realised P&L, and use order totals to reconcile them.
These reads are available on Testnet at https://api.testnet.polyester.com. Mainnet is coming soon.
Read your fills
Call GetUserTrades or GET /v1/spot/trades for the selected account's fills.
Keep the same Main Account or Subaccount scope throughout a backfill. These are your executions,
not the public market's trade tape.
Filter by orderId for one physical order, or lineageId for the logical order across accepted
replacements. The filters are mutually exclusive. throughGeneration limits a lineage query to an
inclusive generation; it does not freeze a generation that is still filling. See Order types and lifecycle.
For one order, GetOrder (GET /v1/spot/orders/{order_id}) includes a
bounded page of lineage executions through that order's generation by default. Follow its
execution cursor using the same physical orderId, rather than a client ID that could later be
reused.
Maker, taker, and fees
isMaker is true when that fill provided resting liquidity, and false when it took liquidity.
Read the role per fill: a limit order can take liquidity on arrival and provide liquidity later.
Use the recorded fee for accounting, rather than recalculating old fills from today's fee rates and VIP tier.
ConnectRPC's fee_amount_e18 is an unsigned fee magnitude in fixed 18-decimal units of fee_asset. Reconstruct its U128 integer, then divide by 10^18. The Pair's quantity scale does
not change this fee scale. REST already returns fee as a decimal string in Asset units; do not
divide it again.
feeIsRebate (fee_is_rebate in Protobuf) means the magnitude was credited. For arithmetic, treat
a charged fee as positive and a rebate as negative. Resolve BASE or QUOTE against the Pair's
Assets, and keep totals in their actual Assets. See Fee Assets and Scaled integers.
Reconcile order totals
Order history and single-order reads with execution history include the net fee total. Open-order reads and private order updates omit it.
| REST value | Use |
|---|---|
cumQuote | Exact executed quote amount before fees, across the lineage through this generation. |
avgPx | Average fill price, rounded half to even at 18 decimal places; "0" before any fill. |
feeTotal | Net fee magnitude, rebate direction, and the filled quantity its total covers. |
Use cumQuote for notional instead of multiplying the rounded avgPx by cumQty. ConnectRPC
names these amounts cum_notional and avg_price_e18; their scales are explained in Trading quantities.
A fill settles its quote amount rounded down to 18 decimal places. When the Pair's base quantity
scale exceeds 9, cumQuote can exceed the settled quote by less than 10^-18 quote units per
fill. Use settlement transfers when reconciling exact balance movements. Request them with includeTransfers on user trades; deduplicate repeated legs by txId within the selected account.
Wait for history to catch up
An order shows an execution before its trade history necessarily does. In GetOrder, executionsComplete is true when trades across all execution pages account for the order's cumQty through its generation. An empty nextPageToken alone means no more rows are visible
now, not that settlement or execution recording has finished.
Fees can lag too. Wait until feeTotal.qty equals cumQty before treating the total as covering
every fill. Until then, refetch later. Settlement transfers can appear after the trades they settle.
A terminal order status does not remove these delays.
Replacement totals include earlier generations. Do not add predecessor and successor cumQuote or feeTotal values together. For fees per physical order, sum its distinct fills. For fees per
logical order, sum distinct lineage fills or use the latest generation's complete total. See Order sizing for quote-budget reconciliation.
Pagination and backfill
User trades are ordered by timestamp, symbol, match, and physical order, descending. Order history is also newest first. Both accept a page limit from 1 to 1000, default 100. The API reference owns the complete filter schema.
Subscribe before reading history
Start buffering user trade executions, then request history. For reconnect handling and the separate private order socket, follow Recover after reconnect.
Read an overlapping range
REST uses startTime and endTime; ConnectRPC uses start_ts_ns and end_ts_ns. Both bounds are
inclusive. Start at or before your last reconciled time and fix the range while paging. Replay
overlapping ranges to catch late-recorded fills; do not checkpoint solely from the newest live fill.
For a per-symbol catch-up, afterMatchId (after_match_id) returns durable fills with a strictly
greater match ID and requires the symbol filter. Use a previously reconciled checkpoint, not an
ID received only on the live stream. Match IDs are monotonic per symbol, not across the account.
Follow every cursor
Pass nextPageToken as pageToken until empty, keeping the account, scope, filters, and time
range unchanged. Cursors are opaque and exclusive. Continue even after a short or empty page
when a token remains. Start a new query when changing the range.
Upsert and checkpoint together
Key fills by account, symbol, matchId, and orderId; ConnectRPC uses the corresponding numeric
IDs. An already stored identity replaces its earlier copy. Never count a replay as another fill.
Match ID alone is insufficient, including when the same account has both sides of a match.
Merge buffered publications in array order, then publication order. Persist the resulting data and recovery checkpoints together. Different symbols have no defined relative event order.
Compute realised P&L and fees
The following is a client accounting method for spot inventory. An opening BUY acquires inventory; its cash debit alone is not a realised loss. Choose a cost-basis method, such as FIFO or weighted average, and apply it consistently across orders.
For each distinct fill, let B be gross base quantity, Q its settled quote amount, and F_base and F_quote its signed fee in the corresponding Asset. The fee in the other Asset is zero.
| Side | Inventory change | Quote cash flow |
|---|---|---|
| BUY | B - F_base received | -(Q + F_quote) |
| SELL | B delivered | Q - F_quote |
A BUY paying in base therefore has less inventory over which to allocate its quote cost. Rebates reverse the fee's effect. SELL fees are in quote. Allocate acquisition fees into inventory cost once, then calculate realised P&L as net sale proceeds less the cost basis of the inventory sold. Do not subtract acquisition fees again on disposal.
Group these results by the executing orderId, or by lineage for a logical-order report. Sum signed
fees separately per Asset. A multi-Pair P&L report needs an explicit valuation currency and conversion
policy; raw fees in different Assets cannot be added. If acquired inventory or its cost basis is
missing, keep that P&L unresolved rather than assigning a zero cost.
Use exact integer or decimal arithmetic with enough precision for intermediate products. Keep raw fill records and settlement legs alongside derived reports so you can recompute them after a backfill.
Exports and history limits
Build your export from paginated fills and, when needed, order history and settlement transfers. Preserve exact decimal strings, identities, account scope, execution times, and fee Assets in CSV or another durable format. The public trading contracts do not specify a CSV export operation.
Page size is not a retention guarantee. The public contracts do not specify how far back fill and order history remains available, or a maximum query time span. Archive continuously rather than depending on an unlimited future backfill.
For immediate execution notifications, use the existing private stream's execution events. For settled fill details, use the user trade execution stream and the history reads above.