Trading API

Stock order placement via IBKR paper accounts

Authentication

All endpoints (except /health) require an API key in the request header:

X-API-Key: your-api-key-here

Unauthenticated requests return 401.

Base URL

http://hal.tail5dcc37.ts.net

Endpoints

GET /api/v1/health No auth
Check service status and IBKR gateway connectivity.
Example response
{
  "status": "ok",
  "accounts": {
    "DU8730189": true,
    "DUP203550": false
  }
}
POST /api/v1/orders API Key
Submit target positions. The API calculates deltas vs current holdings and places the difference.

Request body

{
  "account_id": "DU8730189",    // optional, defaults to DU8730189
  "orders": [
    {
      "symbol": "AAPL",
      "quantity": 100,          // target position (negative=short, 0=close)
      "limit_price": 150.50,    // optional — use LMT order at this price
      "expected_price": 150.00, // optional — for tolerance calculation
      "tolerance_pct": 0.5         // optional — max % from expected_price
    }
  ]
}

Order type logic

Parameters providedOrder typePrice
limit_priceLMTExactly limit_price
expected_price + tolerance_pctLMTBUY: price * (1 + tolerance/100)
SELL: price * (1 - tolerance/100)
NeitherMKTMarket price

Delta calculation

Target-based ordering: If you currently hold 50 shares of AAPL and submit "quantity": 100, the API will place a BUY order for 50 shares (the difference). Submitting "quantity": 0 closes the position entirely.
Example response (201)
{
  "batch_id": "a1b2c3d4e5f67890",
  "account_id": "DU8730189",
  "submitted_at": "2026-03-09T14:30:00+00:00",
  "results": [
    {
      "symbol": "AAPL",
      "current_pos": 50,
      "desired_pos": 100,
      "delta": 50,
      "action": "BUY",
      "qty": 50,
      "order_type": "MKT",
      "ibkr_order_id": 12345,
      "status": "Submitted"
    }
  ]
}
curl example
curl -X POST http://hal.tail5dcc37.ts.net/api/v1/orders \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{
    "orders": [
      {"symbol": "AAPL", "quantity": 100},
      {"symbol": "MSFT", "quantity": 50, "limit_price": 420.00}
    ]
  }'
GET /api/v1/orders/{batch_id} API Key
Poll status of a submitted batch. Refreshes order status from IBKR on each call.
Example response
{
  "batch_id": "a1b2c3d4e5f67890",
  "account_id": "DU8730189",
  "submitted_at": "2026-03-09T14:30:00+00:00",
  "orders": [
    {
      "symbol": "AAPL",
      "ibkr_order_id": 12345,
      "status": "Filled",
      "filled_qty": 50,
      "avg_fill_price": 150.25,
      "commission": 0.35,
      "delta": 50,
      "action": "BUY"
    }
  ]
}
GET /api/v1/orders API Key
List recent order batches (last 100, newest first).
Example response
{
  "batches": [
    {
      "batch_id": "a1b2c3d4e5f67890",
      "account_id": "DU8730189",
      "client": "client1",
      "submitted_at": "2026-03-09T14:30:00+00:00"
    }
  ]
}
GET /api/v1/positions API Key
Get current open stock positions and account value.

Query parameters

ParamRequiredDefaultDescription
account_idNoDU8730189Paper account ID
Example response
{
  "account_id": "DU8730189",
  "positions": [
    {
      "symbol": "AAPL",
      "quantity": 100,
      "avg_cost": 148.50,
      "conid": 265598
    }
  ],
  "net_liquidation": 500000.00,
  "updated_at": "2026-03-09T14:30:00+00:00"
}
DELETE /api/v1/orders/{batch_id} API Key
Cancel all open orders in a batch.
Example response
{
  "batch_id": "a1b2c3d4e5f67890",
  "results": [
    {"ibkr_order_id": 12345, "cancelled": true}
  ]
}

Order Statuses

StatusMeaning
SubmittedOrder sent to exchange
PreSubmittedOrder accepted by IBKR, awaiting exchange
FilledFully filled
CancelledCancelled by user or system
InactiveRejected or expired
no_changeDelta was zero, no order placed
errorBroker error (see error field)

Error Responses

HTTP CodeMeaning
400Bad request (missing fields, invalid account)
401Missing or invalid API key
404Batch not found
500Broker connection error

Available Accounts

Account IDType
DUP203550Paper
DU8730189Paper

Default account: DU8730189