Orders API
9 endpoints in this group.
GET /api/orders/
List Orders
List orders, newest first by default. Optional status / symbol filters.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
tenant_id | query | — | optional | |
status | query | — | optional | |
symbol | query | — | optional | |
limit | query | integer | optional | |
order | query | string | optional | Sort direction by id. Default 'desc' (newest first) preserves the historical blotter behavior. 'asc' (oldest first) exists so a bounded LIMIT fetches the true oldest rows for a status: e.g. the manual-approval queue, which must not silently drop starved orders behind a newest-first page . |
Responses
| Code | Description |
|---|---|
200 | Successful Response |
402 | plan_required: the caller needs a higher plan. |
422 | Validation Error |
GET /api/orders/blotter
List Orders Blotter
Blotter view with keyset cursor pagination (created_at DESC, id DESC).
Designed for mobile infinite-scroll:
- Stable under concurrent inserts (keyset > offset).
next_cursoris opaque base64 of(created_at, id).- Filters stack as AND.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
tenant_id | query | — | optional | |
limit | query | — | optional | Legacy page size. Prefer page_size for canonical pagination. |
page_size | query | — | optional | Canonical page size. Must be 25, 50, or 100. |
cursor | query | — | optional | Opaque cursor from a previous page's next_cursor. |
status | query | — | optional | |
status_group | query | — | optional | Status group: WORKING, FILLED, CANCELED, or REJECTED. |
symbol | query | — | optional | |
account_id | query | — | optional | |
account_ids | query | — | optional | |
side | query | — | optional | BUY or SELL |
from | query | — | optional | ISO-8601 lower bound on created_at (inclusive). |
to | query | — | optional | ISO-8601 upper bound on created_at (exclusive). |
Responses
| Code | Description |
|---|---|
200 | Successful Response |
402 | plan_required: the caller needs a higher plan. |
422 | Validation Error |
POST /api/orders/place
Place Order
Validate then submit to Schwab.
- On REJECTED: persists row with status='REJECTED', does NOT call Schwab.
- On approved + paper_trading: persists row with status='PAPER_FILLED'.
- On approved + live: calls the broker, persists SUBMITTED, SUBMIT_FAILED, or SUBMIT_UNKNOWN according to the observed outcome.
- Kill switches are checked before validation and block with 503, persisting nothing: the platform-wide switch blocks live orders (paper orders are exempt), the tenant switch blocks every order.
P0-5: requires Idempotency-Key header. Replays return the exact
cached response. Every INSERT/UPDATE here is audited via trigger on
orders (see migration 0057_audit_log) attributed to user_id.
Entitlement : requires the Pro plan (feature broker_trading) and
the RBAC trading execute permission. While the regulated-surfaces pause is
on, only the platform owner is admitted. Rejections: 402 plan_required,
403 feature_disabled, 403 missing trading:execute. These run before the
idempotency key is reserved, so a rejected request persists nothing.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
tenant_id | query | — | optional | |
Idempotency-Key | header | — | optional | Client-generated unique id for this request. |
Request body: application/json
Responses
| Code | Description |
|---|---|
201 | Successful Response |
202 | order_accepted_unreconciled or order_outcome_unknown: do not resubmit. A replay of the same Idempotency-Key returns this same response. |
402 | plan_required: the caller's plan is below Pro (feature broker_trading). Body: {"detail": {"error": "plan_required", "required_plan", "current_plan", "feature", "feature_label", "upgrade_url"}}. |
403 | Either feature_disabled (the regulated order-entry pause is on; body {"detail": {"error": "feature_disabled", "code": "regulatory_approval_required"}}) or missing RBAC permission trading:execute (body: a string detail naming the capability). |
422 | Validation Error |
POST /api/orders/preview
Preview Order
Run validate_trade() without submitting. Safe dry-run for UI.
P1-8: attaches any non-blocking wash-sale warnings. The warning is
informational only and does not affect decision.
Entitlement : requires the Pro plan (feature broker_trading) and
the RBAC trading write permission. While the regulated-surfaces pause is
on, only the platform owner is admitted. Rejections: 402 plan_required,
403 feature_disabled, 403 missing trading:write. These run before the
idempotency key is reserved, so a rejected request persists nothing.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
tenant_id | query | — | optional |
Request body: application/json
Responses
| Code | Description |
|---|---|
200 | Successful Response |
402 | plan_required: the caller's plan is below Pro (feature broker_trading). Body: {"detail": {"error": "plan_required", "required_plan", "current_plan", "feature", "feature_label", "upgrade_url"}}. |
403 | Either feature_disabled (the regulated order-entry pause is on; body {"detail": {"error": "feature_disabled", "code": "regulatory_approval_required"}}) or missing RBAC permission trading:write (body: a string detail naming the capability). |
422 | Validation Error |
GET /api/orders/{order_id}
Get Order
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
order_id | path | integer | required | |
tenant_id | query | — | optional |
Responses
| Code | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
POST /api/orders/{order_id}/approve
Approve Order
Approve a tracked order for a later human-gated executor.
This endpoint deliberately does not call a submission service, broker adapter, or broker client.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
order_id | path | integer | required |
Responses
| Code | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
POST /api/orders/{order_id}/cancel
Cancel Order
Cancel an open order. Mutation audited via mutations_audit_log
trigger on orders (see migration 0057_audit_log).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
order_id | path | integer | required | |
tenant_id | query | — | optional |
Responses
| Code | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
POST /api/orders/{order_id}/reject
Reject Order
Reject a pending order permanently without broker submission.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
order_id | path | integer | required |
Request body: application/json
Responses
| Code | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
GET /api/orders/{order_id}/status
Refresh Order Status
Pull latest status from Schwab and persist.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
order_id | path | integer | required | |
tenant_id | query | — | optional |
Responses
| Code | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |