Agara

Portfolio

Reconcile AGARA collateral, positions, open orders, fills, activities, and withdrawals.

Portfolio reads require a personal access token with portfolio:read. These docs cover the AGARA exchange; keep the returned exchange fields in your models so each row remains self-identifying.

Summary

GET /trade/v1/portfolio/summary

Use the summary before sizing a new order and after any deposit, withdrawal, position operation, or automatic redemption.

curl "$AGARA_BASE_URL/trade/v1/portfolio/summary?exchanges=AGARA" \
  -H "Authorization: Bearer $AGARA_API_TOKEN"
{
  "summaries": [
    {
      "exchange": "AGARA",
      "cash_balance_micro": "250000000",
      "free_cash_micro": "250000000",
      "positions_value_micro": "18500000",
      "portfolio_value_micro": "268500000",
      "open_cost_basis_micro": "17200000",
      "open_unrealized_pnl_micro": "1300000",
      "accounting_status": "AVAILABLE",
      "as_of": "2026-07-20T12:00:00.000Z"
    }
  ]
}
FieldMeaning
cash_balance_microCurrent collateral balance
free_cash_microCash available to AGARA's BUY validation
positions_value_microMarked value of open positions
portfolio_value_microCash plus marked positions
open_cost_basis_microCost basis still attached to open positions
open_unrealized_pnl_microMarked value less open cost basis
as_ofTimestamp of this exchange snapshot

Nonterminal BUY commitments are not a separate summary field. Fully page POST /trade/v1/orders/list and account for their remaining collateral when your strategy computes its own available quoting budget. Use open orders for the portfolio's resting and active subset.

Positions

POST /trade/v1/portfolio/positions/list

Positions are returned in one unpaginated response. Treat the AGARA subset as complete only when unavailable_exchanges does not include AGARA; require the array to be empty for a complete multi-exchange response.

{
  "condition_ids": [],
  "exchanges": ["AGARA"]
}

An empty condition_ids array returns every current position. Use one or more condition IDs to narrow the snapshot.

Positions in the most recently registered markets appear first. When market registration times match, positions are ordered by current value, highest first, then by exchange name alphabetically. Positions with unavailable market registration times appear last.

{
  "positions": [
    {
      "exchange": "AGARA",
      "condition_id": "0x...",
      "token_id": "1234567890",
      "shares_micro": "5000000",
      "available_shares_micro": "3000000",
      "avg_price_micro": "430000",
      "open_cost_basis_micro": "2150000",
      "accounting_status": "AVAILABLE",
      "current_price_micro": "470000",
      "current_value_micro": "2350000",
      "to_win_micro": "5000000",
      "profit_loss_micro": "200000",
      "profit_loss_percent": "9.302325581395348837",
      "redeemable": false,
      "mergeable": false,
      "mergeable_shares_micro": null
    }
  ],
  "markets": {
    "1234567890": {
      "market_id": "1f9e566d-7823-49fb-a5c5-5a193eba3209",
      "market_title": "Will City A win?",
      "outcome_name": "Yes",
      "logo_url": null,
      "event_slug": "city-a-vs-city-b",
      "state": "ACTIVE",
      "neg_risk_id": null,
      "display": { "market": {}, "outcome": {} }
    }
  },
  "events": {
    "city-a-vs-city-b": {
      "event_title": "City A vs City B",
      "display": { "event": {} }
    }
  },
  "unavailable_exchanges": [],
  "as_of": "2026-07-20T12:00:00.000Z"
}

Average entry price uses the moving weighted-average acquisition cost of held shares, excluding trading fees. Selling removes proportional cost; closing a position clears its cost, so a later purchase starts a new average. Splitting a complete set assigns 50ยข per share to each outcome.

Holdings update immediately. The average and cost can briefly reflect earlier activity. open_cost_basis_micro applies the latest available average to the returned held quantity; use that field when calculating P&L instead of multiplying by the rounded avg_price_micro. profit_loss_percent is a percentage string: "9.3" means 9.3%.

Keep displaying shares when accounting_status is PENDING, and display an updating indicator for null average, cost or P&L fields. Retry your normal portfolio read to receive updated accounting. If the status is UNAVAILABLE, display those amounts as unavailable rather than zero. AVAILABLE means an average is available; it does not guarantee that it includes the latest fill.

Quoted current value remains available even while cost is pending. When neither a quote nor an acquisition average is available, current price and value are also null. Summary cost and P&L are null if any held position lacks cost; summary position and portfolio values are null only if a holding cannot be valued. Cash remains available, and an empty portfolio has zero position totals.

shares_micro is your total holding. Use available_shares_micro as the maximum size for a new sell order โ€” it excludes shares your own open sell orders have already committed, so "0" means every share you hold is already up for sale.

mergeable and mergeable_shares_micro are advisory snapshots for a held, available complete pair. redeemable identifies a resolved position; supported standalone markets are handled by automatic redemption. The sidecar's state tells you where each position's market is in its lifecycle: once it reaches PROPOSED a winner or a split has been proposed, so the position can no longer be sold and its payout is on the way. Positions in a market with a neg_risk_id are the exception: those are not redeemed automatically. Retry when unavailable_exchanges contains AGARA because that snapshot is missing AGARA rows.

to_win_micro is what the position pays if its outcome wins: one collateral unit per share. When a market's proposal or resolution is a split, it is your shares times that outcome's split price, rounded down: 10 YES shares on a split that pays 37ยข per YES share show "3700000".

Open orders

POST /trade/v1/portfolio/open-orders/list

{
  "token_ids": [],
  "exchanges": ["AGARA"],
  "limit": 100
}

The response contains:

  • orders: the active subset used by the portfolio view, in the same shape documented under Orders;
  • markets: metadata keyed by token_id, including each market's state, neg_risk_id, and raw market/outcome display objects;
  • events: metadata keyed by event slug, including the raw event display;
  • pagination: next_cursor and the applied limit;
  • as_of: the snapshot time.

Orders are newest first. Pass pagination.next_cursor back as cursor with the same token_ids and exchanges filters. A null cursor means the walk is complete.

This is an active-order view, not lifecycle history. For cancellation recovery or an audit of how each order ended, fully page POST /trade/v1/orders/list and follow each tracked order to a terminal state.

Trades

GET /trade/v1/portfolio/trades

Query parameters are limit (default and maximum 500) and an opaque cursor from the previous response.

{
  "trades": [
    {
      "exchange": "AGARA",
      "trade_id": "<uuid>",
      "fill_id": "42",
      "order_id": "<uuid>",
      "token_id": "1234567890",
      "side": "BUY",
      "shares_micro": "1000000",
      "price_micro": "470000",
      "fee_micro": "0",
      "role": "MAKER",
      "status": "CONFIRMED",
      "transaction_hash": "0x...",
      "executed_at": "2026-07-20T11:58:00.000Z"
    }
  ],
  "markets": {},
  "events": {},
  "pagination": { "next_cursor": null, "limit": 500 },
  "unavailable_exchanges": [],
  "as_of": "2026-07-20T12:00:00.000Z"
}

fill_id is serialized as a string. transaction_hash remains null until settlement supplies one. Any page can be partial, so check unavailable_exchanges after every response. If an AGARA-only page contains AGARA, discard the entire accumulated walk and restart without a cursor. Do the same for a multi-exchange walk whenever the array is nonempty. Continue only after every page satisfies the condition for your requested exchange set, and stop when next_cursor is null.

Activities

GET /trade/v1/portfolio/activities

Activities show AGARA history sorted newest first. limit defaults to 50 and accepts 1 through 500; pass the opaque cursor to continue to older activities. Each page returns current data; as_of is the time that page was read. Refresh from page one to see newer activities.

The type discriminator selects one of these wire shapes:

TypeFields in addition to type, exchange, id, and created_at
ORDERorder_id, current status, fill_status, condition_id, token_id, side, filled_shares_micro, average_fill_price_micro, filled_amount_micro, fees_micro
SPLITcondition_id, shares_micro, amount_micro, tx_hash
MERGEcondition_id, shares_micro, amount_micro, tx_hash
REDEEMcondition_id, redeemed token_id, shares_micro, amount_micro, tx_hash
DEPOSITamount_micro, chain_id, token_address, counterparty_address, tx_hash
WITHDRAWALamount_micro, chain_id, token_address, counterparty_address, tx_hash

An ORDER appears after its first recorded fill, including while the remaining shares are still open. One row collects all fills for that order. Later fills update its totals and current status; created_at stays at the first fill. Unfilled orders do not appear here. fill_status is FULL or PARTIAL.

A REDEEM appears separately for each outcome you held. shares_micro is positive for both outcomes. amount_micro is the collateral received: the shares times the price their outcome paid, rounded down. For winners, that is one unit per share. For losers, it is zero: 7 losing shares give shares_micro: "7000000" and amount_micro: "0". On a split resolution, each outcome pays its own price, so 7 NO shares paid at 63ยข give amount_micro: "4410000".

Confirmed LP rewards appear as LP_PAYOUT, with amount_micro, epoch_date, and tx_hash. The same reward transfer does not also appear as a deposit.

If a cursor returns 422, restart from page one.

{
  "activities": [
    {
      "type": "REDEEM",
      "exchange": "AGARA",
      "id": "redeem:<uuid>",
      "condition_id": "0x...",
      "token_id": "1234567890",
      "shares_micro": "5000000",
      "amount_micro": "5000000",
      "tx_hash": "0x...",
      "created_at": "2026-07-20T11:55:00.000Z"
    }
  ],
  "markets": {},
  "conditions": {},
  "events": {},
  "pagination": { "next_cursor": null, "limit": 50 },
  "as_of": "2026-07-20T12:00:00.000Z"
}

The metadata sidecars cover only rows present on the current page: markets is keyed by outcome token ID, conditions by condition ID, and events by event slug. Activities do not return unavailable_exchanges.

Position operations

Split and merge convert between collateral and complete binary token pairs:

  • POST /trade/v1/portfolio/positions/split requires positions:split;
  • POST /trade/v1/portfolio/positions/merge requires positions:merge.

Both accept a scoped personal access token and return 201 with batch_hash, status: "PENDING", and as_of. Poll GET /trade/v1/batches/{batch_hash} for settlement. If it finishes as FAILED or FAILED_DIVERGENT, inspect the typed failure object and wait for unwound_at before treating provisional inventory as restored. If a lower batch is FAILED_DIVERGENT, a higher failed batch's unwound_at alone is not proof of restoration; keep mutations paused and follow the stranded-sequence recovery rule. See Positions for request shapes, validation, and cross-match settlement.

Supported resolved standalone markets use automatic redemption; no client-submitted operation is required.

Withdrawals

The standard withdrawal flow requires a current browser session. A personal access token alone cannot execute it.

  • Same-chain withdrawal sends USDC to an address on Base.
  • Send to a wallet address, not the token's own address. A request that names the token as its recipient is refused with a 422 error, because the token's own address is not a wallet.
  • Accepted AGARA withdrawals return 201 with a pending batch hash. Poll the batch until it reaches SETTLED before treating destination funds as final; a terminal failure carries the same typed failure object.
  • Requests queue per account and settle in order. A 409 means the queue is full; retry once a queued request finishes.
  • The minimum is 10000 micro units. The environment's batch ceiling can impose a tighter bound.

For a cross-chain withdrawal:

  1. Use a personal access token to read GET /trade/v1/portfolio/bridge/withdraw/supported-assets.
  2. Request POST /trade/v1/portfolio/bridge/withdraw/quote with the destination chain, token, recipient, and source amount.
  3. Review the current quote, then confirm in the signed-in web flow.

If a route refunds to the AGARA account, the return appears as a DEPOSIT activity. A quoted route minimum can be higher than the standard withdrawal minimum. Request a new quote before retrying.

Withdrawing to Solana. When Solana is offered, its supported asset has address_type SOL and a base58 token address. Send both values back exactly as listed.

  • Set recipient_address to the base58 address of a Solana wallet you control, exactly as the wallet shows it. Solana addresses are case-sensitive, so never change their letter case.
  • Some addresses are refused with a 422 error before anything moves: a wallet's associated token account, a program-controlled wallet such as a multisig vault, and the USDC token address itself. Any other address is accepted exactly as entered.
  • The wallet must already have a USDC account; an empty one is fine. If it does not, the quote and the withdrawal answer 422 recipient_token_account_missing and nothing moves. Receiving any amount of USDC in that wallet once creates the account; then request a new quote.
  • SETTLED means the USDC has left your AGARA account. It usually reaches the Solana wallet within a minute. A withdrawal to Solana cannot be reversed or refunded, and USDC sent to an address that no wallet controls is lost, so check the address before you confirm.

Common pattern

Before placing a new quote, fetch summary and fully page the order list. Use the summary's free_cash_micro as AGARA's current BUY-validation cash, then apply your own risk limits and account for every remaining nonterminal commitment. Use the portfolio open-orders endpoint for the resting-liquidity view.

Every portfolio endpoint's full request and response shape is in the Portfolio API reference.