---
title: "Api Place Paper Order"
method: POST
path: "/api/paper/order"
---

# Api Place Paper Order

`POST /api/paper/order`

## Request

- Base URL: `https://www.oxfordledge.com` (the document declares no server; this is the origin it was published from)
- URL: `https://www.oxfordledge.com/api/paper/order`
- Auth: none declared

Place a paper-trading market order.

Body: {
    "ticker": str,
    "side": "buy" | "sell",
    "shares": number,
    "thesis": str (optional, ≤250 chars),
    "challenge_id": str (optional),
    "client_order_id": str (optional, ≤64 chars of [A-Za-z0-9_-])
}

client_order_id (v254, P1-22, external review 2026-09-26): the order
form's idempotency key. A repeat of an order that already filled returns
the ORIGINAL fill (200, same body) and never fills twice.

Returns PaperOrderResponse:
  success: { ok: True, fill: {...} }
  reject:  { ok: False, error: "...", code: "<machine-readable>" }

Validation/rejection paths return 200 with ok=False so the FE can
display the rejection reason without distinguishing HTTP status
from business-logic state. True transport/auth errors raise.

## Response `200`

Successful Response

- PaperOrderResponse: `POST /api/paper/order` — place a paper-trading order. Success path: ok=true + fill payload. Validation/rejection path: ok=false + error + code (machine-readable). Frontend dereferences `result.fill.fill_price` on success and `result.code` on error; REQUIRED fields are declared accordingly so the error envelope can't drift to a shape that NPEs the UI.
  - `ok` boolean, required: Whether the order was filled.
  - `fill` PaperOrderFill: The fill record returned by a successful paper order.
    - `order_id` integer, required: paper_orders.id
    - `trade_id` integer, required: paper_trades.id
    - `ticker` string, required: Resolved + uppercased ticker.
    - `side` string, required: 'buy' or 'sell'.
    - `shares` number, required: Filled share quantity.
    - `fill_price` number, required: Per-share fill price (delayed quote).
    - `cash_delta` number, required: Negative for buys (cash leaves), positive for sells (cash arrives).
    - `new_cash` number, required: Portfolio cash balance after this fill.
    - `filled_at` unknown, required
  - `error` string, nullable: Human-readable error on rejection.
  - `code` string, nullable: Machine-readable error code: ticker_invalid, side_invalid, shares_invalid, thesis_too_long, no_portfolio, quote_unavailable, insufficient_cash, insufficient_shares, fill_failed.
  - `needed` number, nullable: Cash needed (insufficient_cash only).
  - `available` number, nullable: Cash available (insufficient_cash only).
  - `held` number, nullable: Shares held (insufficient_shares only).
  - `requested` number, nullable: Shares requested to sell (insufficient_shares only).

---

[API](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api.md) · [All operations](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/llms.txt) · [OpenAPI document](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/revisions/e832a1260f0b?raw)
