API Reference
All endpoints are served by FastAPI at 127.0.0.1:8000. Interactive OpenAPI docs are available at
GET /docs. Signal endpoints require the X-API-Key header (compared in constant time); a missing
or wrong key returns 401 and logs only whether a key was present.
Endpoints
| Method & path | Auth | Purpose |
|---|---|---|
POST /v1/signals | X-API-Key | Validate and execute a signal (idempotent by signal_id). |
GET /v1/signals/{signal_id} | X-API-Key | Retrieve the durable stored state of a signal. |
GET /health/live | none | Liveness — the process is running. |
GET /health/ready | none | Readiness — terminal connected and TRADING_ENABLED=true (else 503). |
Submitting a signal
POST /v1/signals. Required fields: signal_id, occurred_at, execution_type, symbol,
direction, volume. entry_price is required for limit and stop, and prohibited for
market. Optional: stop_loss, take_profit, expires_at, deviation_points, note. Unknown
fields are rejected (extra="forbid"), and timestamps must be timezone-aware.
| Field | Type | Notes |
|---|---|---|
signal_id | string (UUID) | Idempotency key. Never reuse with changed fields. |
occurred_at | RFC 3339 datetime | When the signal fired; used for freshness checks. |
execution_type | market | limit | stop | Order type. |
symbol | string | Exact, case-sensitive broker symbol (must be in ALLOWED_SYMBOLS). |
direction | buy | sell | Trade side. |
volume | decimal string | Lots; validated against the broker volume step and MAXIMUM_VOLUME. |
entry_price | decimal string | Required for limit/stop, prohibited for market. |
stop_loss, take_profit | decimal string | Optional; validated for precision and stop distance. |
expires_at | RFC 3339 datetime | Optional expiry for pending orders. |
deviation_points | integer | Optional slippage cap (bounded by MAX_DEVIATION_POINTS). |
note | string | Optional free-text tag. |
Example — market entry
{
"signal_id": "3a939594-f36e-4dc7-96a5-97e84e21c36e",
"occurred_at": "2026-07-14T15:00:00Z",
"execution_type": "market",
"symbol": "EURUSD",
"direction": "buy",
"volume": "0.10",
"stop_loss": "1.08000",
"take_profit": "1.10000",
"deviation_points": 10,
"note": "strategy-a breakout"
}Example — expiring pending (limit) entry
{
"signal_id": "c0c95e51-13d4-4567-b543-a0e41098f008",
"occurred_at": "2026-07-14T15:00:00Z",
"execution_type": "limit",
"symbol": "EURUSD",
"direction": "buy",
"volume": "0.10",
"entry_price": "1.08500",
"expires_at": "2026-07-14T18:00:00Z"
}Example — client call (PowerShell)
$headers = @{ "X-API-Key" = $env:API_KEY }
$body = Get-Content .\signal.json -Raw
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8000/v1/signals `
-Headers $headers -ContentType "application/json" -Body $bodyResponse statuses
A successful response reports one of these states, plus broker tickets and the normalized result:
| State | Meaning |
|---|---|
filled | The order was fully executed. |
partially_filled | The order was partially executed. |
placed | A pending (limit/stop) order was accepted and is resting. |
GET /v1/signals/{signal_id} returns the durable stored state, including terminal states like
rejected and unknown.
Error codes
| HTTP | Code | When |
|---|---|---|
| 401 | — | Missing or invalid X-API-Key. |
| 409 | idempotency_conflict | Same signal_id re-sent with a different payload. |
| 409 | signal_in_progress | The same signal is still being processed. |
| 422 | validation error | Payload failed Pydantic validation (bad/missing fields, wrong types). |
| 422 | preflight_rejected | The broker’s order_check() preflight returned a nonzero retcode. |
| 503 | not ready | Readiness failed — terminal disconnected or TRADING_ENABLED=false. |
| 503 | execution_outcome_unknown | order_send() result is ambiguous. The order is not retried — a human must inspect. |
Idempotency contract. Re-sending an identical payload for a completed
signal_idreplays the stored response (or re-raises the stored error) — it never places a second trade. Changing any field for an existingsignal_idis a409 idempotency_conflict.
See Architecture for how these outcomes are produced and reconciled.