Base URL: http://localhost:8000/api (dev) or http://localhost:8080/api
(Docker, proxied through nginx — see Design Document.md).
Interactive docs (Swagger UI, auto-generated by FastAPI from the route
signatures and Pydantic schemas): GET /docs. Raw OpenAPI schema: GET /openapi.json (24 documented paths as of v1.0.0).
| Method | Path | Purpose |
|---|---|---|
| GET | /api/health |
Liveness check — {"status": "ok"}. Used by the Docker HEALTHCHECK. |
| GET | /api/version |
{"version": "1.0.0", "api": "autotrader"} — added in the Task 10 audit; previously no version endpoint existed. |
| GET | /api/strategies |
Registered strategies (id, label, param schema) |
| GET | /api/contracts |
Contract specs (tick size/value, margins) merged from settings.yaml |
| GET | /api/data-sources |
Which data providers are actually usable right now (real checks, not assumptions — see below) |
| Method | Path | Purpose |
|---|---|---|
| POST | /api/backtests |
Run a backtest, returns a summary + backtest_id |
| GET | /api/backtests/{id} |
Fetch a stored result |
| GET | /api/backtests/{id}/report |
Self-contained HTML report export |
Request/response shapes: api/schemas/backtest.py. Validation errors
return 400 with a message describing what's wrong (e.g. "No data
available for this backtest") — see SECURITY_AUDIT.md
for a review of what these messages do and don't expose.
WS /api/replay/{id} — WebSocket, steps a ReplayEngine bar-by-bar for
the Live Replay UI page.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/schwab/status |
Auth status, hours until refresh-token expiry |
| GET | /api/schwab/auth-url |
Start OAuth2 flow |
| POST | /api/schwab/complete-auth |
Finish OAuth2 flow with the redirect URL |
POST /api/optimize — parameter sweep over a strategy's param grid.
api/export/formats.py — shared CSV/Excel/PDF/Word export used by both
the raw data-export endpoint and the backtest report export. Was
missing fastapi, openpyxl, reportlab, and python-docx from
requirements.txt prior to the Task 10 audit — a fresh install could
not have served these endpoints. Fixed; see
RELEASE.md.
api/main.py configures CORSMiddleware from the
AUTOTRADER_CORS_ORIGINS environment variable (comma-separated origins),
defaulting to the two common local dev ports (5173, 3000). This
did not exist before the Task 10 audit — it was masked in dev because
Vite's proxy makes requests same-origin from the browser's perspective.
Docker's default topology (nginx proxies /api/* — see
Design Document.md) also avoids needing it, but the policy
is there for anyone deploying the API standalone.
Endpoints raise HTTPException(400, ...) for validation failures (bad
symbol, missing data, auth not complete) and let unexpected exceptions
propagate as FastAPI's default 500. Error messages include the raw
exception text in several places (str(e)) — reviewed in the Task 10
security audit: every instance found is a scoped, user-actionable
validation message (e.g. "file not found: ..."), not a leaked stack trace,
secret, or internal path outside what the message is already about. This
is appropriate for a single-operator internal tool; re-review before any
multi-tenant or public-facing deployment.
Most endpoints (backtests, data_export) return raw
dicts rather than typed Pydantic response_models — request bodies ARE
typed (api/schemas/), but response shapes aren't fully reflected in the
generated OpenAPI schema for those routes. Documented as a known
limitation in RELEASE.md rather than retrofitted
here — it's a documentation-completeness gap, not a correctness bug, and
fixing it properly means new schema classes for several complex nested
result types (out of scope for a release audit).