# CrossTrade API Integration — Agent Instructions > Universal AGENTS.md for any AI coding assistant. Drop in your project root. ## Quick reference - **Base URL:** `https://app.crosstrade.io` - **Path prefix:** `/v1/api/...` (NOT `/api/...`) - **Auth:** `Authorization: Bearer ` (env: `XTRADE_TOKEN`) - **Catalog:** `GET /v1/api/_endpoints` returns every public route - **Full reference:** `https://app.crosstrade.io/v1/api/llms-full.txt` - **OpenAPI:** `https://app.crosstrade.io/v1/api/openapi.json` ## Rules of the road 1. **Never invent paths.** If you don't know an endpoint, fetch the catalog or the OpenAPI spec first. 2. **Use the documented HTTP endpoints.** If the project already has helper functions, verify they map to documented routes before relying on them. 3. **Always check `success`.** The shape is `{"success": bool, "error"?: str, "data"?: ...}`. Branch on `error`, not on the HTTP status alone. 4. **Handle add-on disconnects.** HTTP 408 means the user's NinjaTrader / CrossTrade add-on isn't connected. Tell the user, don't retry blindly. 5. **Respect the rate limit.** 180 req/min, 20 burst. Bulk operations should sleep between requests. ## Endpoint patterns | Action | Method | Path | |---|---|---| | List accounts | GET | `/v1/api/accounts` | | Get one account | GET | `/v1/api/accounts/{account}` | | List positions in account | GET | `/v1/api/accounts/{account}/positions` | | List positions everywhere | GET | `/v1/api/positions` | | Place an order | POST | `/v1/api/accounts/{account}/orders/place` | | Cancel one order | POST | `/v1/api/accounts/{account}/orders/{id}/cancel` | | Cancel all orders | POST | `/v1/api/orders/cancelall` | | Flatten positions in account | POST | `/v1/api/accounts/{account}/positions/flatten` | | Flatten all accounts | POST | `/v1/api/positions/flatten` | | Place bracket (atomic cancel+place) | POST | `/v1/api/accounts/{account}/orders/cancel_and_bracket` | | Get a quote | GET | `/v1/api/market/quote?instrument=...` | | Historical bars | POST | `/v1/api/market/bars` | | List strategies | GET | `/v1/api/accounts/{account}/strategies` | | List executions | GET | `/v1/api/accounts/{account}/executions` | ## Body shapes **PlaceOrder (in body):** ```json { "instrument": "ES 03-26", "action": "Buy" | "Sell", "quantity": 1, "orderType": "Market" | "Limit" | "Stop" | "StopLimit", "limitPrice": 4500.0, "stopPrice": 4490.0, "timeInForce": "Day" | "GTC" | "GTD" | "IOC" | "FOK" } ``` **CancelAndBracket:** ```json { "instrument": "ES 03-26", "action": "Sell", "quantity": 1, "takeProfit": 4550.0, "stopLoss": 4450.0, "ocoId": "protect_long_001" } ``` **GetBars:** ```json { "instrument": "ES 03-26", "periodType": "minute" | "day" | "week" | "month" | "year", "period": 5, "limit": 500, "fromTime": "2026-01-01T00:00:00Z", "toTime": "2026-01-31T23:59:59Z" } ``` ## Instrument formats All five forms resolve to the same NT8 instrument: - `"ES 03-26"` — full dated (preferred in generated code) - `"ES"` — root only (front month auto-selected) - `"ES1!"` — TradingView continuous - `"ESH26"` — CME quarterly code - `"ES SEP25"` — space-normalized ## When errors happen Use the `error` code, not string-matching the `detail`: | HTTP | `error` code | What it means | |---|---|---| | 401 | `auth_error` / `Invalid bearer token` | Bad/missing/expired token, or non-Pro account | | 408 | `Client not ready...` | NT8 / add-on isn't connected | | 429 | `Rate limit exceeded` | Slow down | | 404 | `unknown_endpoint` | Wrong path. Response includes `did_you_mean`. | | 400 | varies | Validation; read `detail` | | 200 + `success: false` | varies | Domain error (no such account, no positions to flatten, etc.) | ## Don't generate - Direct SQL or DB calls. There is no DB endpoint. - WebSocket frames as raw bytes — use the documented `{action, ...}` JSON shape. - Polling loops faster than 1 Hz on a single endpoint. The WebSocket has streaming. - Code that hardcodes a token. Always read `XTRADE_TOKEN` from env.