> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agg.market/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> To integrate AGG, start with Quickstart: REST (https://docs.agg.market/quickstart/rest), then Order lifecycle & statuses (https://docs.agg.market/concepts/order-lifecycle).
> Track every trade until it reaches a terminal status. Before retrying a failed or timed-out call, read Errors, retries & idempotency (https://docs.agg.market/concepts/errors).
> The API reference is generated from https://docs.agg.market/openapi/openapi.json.

# Paper Trading

> Simulated trading against live market data, for user-facing paper portfolios, testing, and QA

Paper trading prices quotes against current market data and records simulated balances, orders,
and positions. Live funds never enter the flow. Use it as a production feature (a paper account
next to a real one), as a testing and QA tool, or both.

There are two surfaces:

| Surface | Who calls it | Use it for |
| - | - | - |
| `mode: "paper"` on the normal trading calls | Your app, with the user's session | Users trading a paper account through the same quote and fill flow as live |
| Paper account management APIs | Your backend, with `x-app-api-key` | Creating, seeding, resetting, and inspecting paper accounts for simulators and test fixtures |

<Warning>
  Paper trading never submits to venues and never runs bridges, custody transfers, deposits,
  withdrawals, or redemptions. Do not treat paper balances as funded wallets or venue balances.
</Warning>

## How it works

<Steps>
  <Step title="User signs in">
    Paper mode is user-scoped. A signed-in user gets a paper account for your app the first time
    they request paper balances, positions, quotes, or a fill.
  </Step>

  <Step title="AGG prices against live books">
    Quotes and paper fills price against the current order book. The result is simulated, but the
    quote reflects current market depth.
  </Step>

  <Step title="Your app sends paper mode">
    Add `mode: "paper"` to the paper-capable calls in [SDK flow](#sdk-flow). For AGG UI
    components, set `trading.executionMode` once on `AggProvider`.
  </Step>

  <Step title="AGG writes paper state only">
    Paper fills update the `PAPER_USD` balance, paper orders, and paper positions. Live wallets,
    venue accounts, and live orders are not touched.
  </Step>
</Steps>

Keep paper and live state visually separate. A user can have both, but never show them as one
balance or one portfolio.

## SDK flow

Pass `mode: "paper"` on these calls. They, and only they, accept it:

| SDK method | API reference |
| - | - |
| `getManagedBalances({ mode: "paper" })` | [Get balances](/api-reference/portfolio/get-balances) |
| `getSmartRoute({ mode: "paper" })` | [Get a quote](/api-reference/trading/get-a-quote-smart-route) |
| `executeManaged({ mode: "paper" })` | [Execute quote](/api-reference/trading/execute-quote) |
| `getExecutionStatus({ mode: "paper" })` | [Get execution status](/api-reference/trading/get-execution-status) |
| `getExecutionPositions({ mode: "paper" })` | [Get user positions](/api-reference/portfolio/get-user-positions) |
| `getExecutionOrders({ mode: "paper" })` | [Get user orders](/api-reference/portfolio/get-user-orders) |

```ts theme={null}
import { createAggClient } from "@agg-build/sdk";

const client = createAggClient({
  baseUrl: process.env.AGG_API_BASE_URL!,
  appId: "your-app-id",
});

// After the user signs in...
const balances = await client.getManagedBalances({ mode: "paper" });

const quote = await client.getSmartRoute({
  venueMarketOutcomeId: "vmo_...",
  tradeSide: "buy",
  maxSpend: 25,
  mode: "paper",
});

const fill = await client.executeManaged({ quoteId: quote.quoteId, mode: "paper" });

let status = await client.getExecutionStatus({ quoteId: fill.quoteId, mode: "paper" });
while (!status.terminal) {
  await new Promise((r) => setTimeout(r, status.pollAfterMs ?? 1000));
  status = await client.getExecutionStatus({ quoteId: fill.quoteId, mode: "paper" });
}
```

<Warning>
  Keep the mode the same from quote to fill. A paper quote must be filled with `mode: "paper"`,
  and a live fill cannot execute a paper quote. Switching modes needs a fresh quote.
</Warning>

<Warning>
  [Place an order directly](/api-reference/trading/place-an-order-directly)
  (`POST /execution/orders`) is live only. It has no `mode` field and rejects one with `400`. Use
  a quote and fill with `mode: "paper"`, or a paper account order from your backend.
</Warning>

## UI components

Set paper mode once on `AggProvider`. `HomePage`, `EventMarketPage`, `PlaceOrder`, and
`UserProfilePage` read it when no `executionMode` prop is passed.

```tsx theme={null}
import { AggProvider } from "@agg-build/ui";
import { QueryClient, QueryClientProvider } from "@agg-build/hooks";
import { HomePage } from "@agg-build/ui/pages";

const queryClient = new QueryClient();

export function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AggProvider client={client} config={{ trading: { executionMode: "paper" } }}>
        <HomePage />
      </AggProvider>
    </QueryClientProvider>
  );
}
```

Pass `executionMode` on one component when it must differ from the provider:

```tsx theme={null}
import { EventMarketPage } from "@agg-build/ui/pages";

export function LiveEventOverride({ eventId }: { eventId: string }) {
  return <EventMarketPage eventId={eventId} executionMode="live" />;
}
```

Hide deposit, withdrawal, and redemption controls in a paper-only experience.

## Manage paper accounts from your backend

<Warning>
  These endpoints need a server-side `x-app-api-key` (see
  [Base URL, app IDs & API keys](/environments)). Never call them from the browser.
</Warning>

| SDK method | API reference |
| - | - |
| `createPaperTradingAccount` | [Create a paper trading account](/api-reference/paper-trading/create-a-paper-trading-account) |
| `listPaperTradingAccounts` | [List paper trading accounts](/api-reference/paper-trading/list-paper-trading-accounts) |
| `getPaperTradingAccount` | [Get a paper trading account](/api-reference/paper-trading/get-a-paper-trading-account) |
| `setPaperTradingBalance` | [Set a paper trading account cash balance](/api-reference/paper-trading/set-a-paper-trading-account-cash-balance) |
| `resetPaperTradingAccount` | [Reset a paper trading account](/api-reference/paper-trading/reset-a-paper-trading-account) |
| `placePaperTradingOrder` | [Place a paper trading order](/api-reference/paper-trading/place-a-paper-trading-order) |
| `listPaperTradingPositions` | [List paper trading positions](/api-reference/paper-trading/list-paper-trading-positions) |
| `listPaperTradingOrders` | [List paper trading orders](/api-reference/paper-trading/list-paper-trading-orders) |
| `getPaperTradingPortfolio` | [Get a paper trading portfolio](/api-reference/paper-trading/get-a-paper-trading-portfolio) |

```ts theme={null}
const agg = createAggClient({
  baseUrl: process.env.AGG_API_BASE_URL!,
  appId: process.env.AGG_APP_ID!,
  apiKey: process.env.AGG_APP_API_KEY!, // server-side only
});
```

### Seed the account a user sees

Browser paper mode uses the account whose `externalId` is `user:<aggUserId>`. Create or reset that
account from your backend and the signed-in user sees the seeded balance in the app.

```ts theme={null}
const aggUserId = "usr_...";

const account = await agg.createPaperTradingAccount({
  name: "QA paper account",
  externalId: `user:${aggUserId}`,
  initialBalanceRaw: "100000000", // 100.000000 PAPER_USD
});
```

`externalId` is unique per app, so creating an existing account returns a validation error. Look
it up instead:

```ts theme={null}
const page = await agg.listPaperTradingAccounts({ externalId: `user:${aggUserId}` });
const existing = page.data[0] ?? null;
```

### Reset or set cash

`resetPaperTradingAccount` clears open positions and sets cash. `setPaperTradingBalance` changes
cash only.

```ts theme={null}
await agg.resetPaperTradingAccount(account.id, {
  balanceRaw: "250000000", // 250.000000 PAPER_USD
  reason: "Reset before QA run",
});

await agg.setPaperTradingBalance(account.id, {
  balanceRaw: "50000000", // 50.000000 PAPER_USD
  reason: "Low-balance test case",
});
```

Raw amounts use 6 decimals. `initialBalance`, `balance`, and `spend` also accept numbers, but raw
strings are better for repeatable fixtures. Order history survives a reset.

### Place a simulated order

Direct paper orders build known positions before a UI test. They price against the current book
and come back filled or rejected.

```ts theme={null}
const order = await agg.placePaperTradingOrder(account.id, {
  venueMarketOutcomeId: "vmo_...",
  side: "buy",
  spendRaw: "25000000",
  slippageBps: 100,
  clientOrderId: "qa-run-123-buy-1",
});

if (order.status === "rejected") {
  console.log(order.rejectionReason);
}
```

On paper orders, `clientOrderId` is stored for traceability only. It is not an idempotency key.

### Inspect state

```ts theme={null}
const portfolio = await agg.getPaperTradingPortfolio(account.id);
const positions = await agg.listPaperTradingPositions(account.id, { limit: 50 });
const orders = await agg.listPaperTradingOrders(account.id, { limit: 50 });
```

## Testing with paper mode

For pre-release checks or CI smoke tests:

* Sign in a test user through the normal auth flow.
* Read paper balances and check `PAPER_USD` is present.
* Quote a current open market with `mode: "paper"`, fill it, and poll status to a terminal state.
* Read paper orders and positions and check the fill is there and cash changed.

Negative paths:

* Fill a paper quote without `mode: "paper"` and expect a rejection.
* Switch from paper to live and require a fresh quote before filling.
* Check paper pages show no deposit, withdrawal, bridge, or redemption actions.

For repeatable runs, reset the user's `user:<aggUserId>` account before the run, pick test
outcomes from current discovery instead of hardcoding one that can close, and use scenario-owned
`clientOrderId` values on backend orders so logs map fixtures to orders.

## Launch checklist

* Decide whether paper trading is for testing only, user-facing, or both.
* Show a clear paper badge or account switcher.
* Set `config.trading.executionMode = "paper"` on `AggProvider` while the paper account is
  selected.
* Pass `mode: "paper"` on custom SDK calls for balances, quotes, fills, status, positions, and
  orders.
* Never send `mode: "paper"` to `POST /execution/orders`.
* Use live mode only after the user explicitly picks their real account.
