Trader API v1
Let your own program — a Python script, a trading bot, or an AI agent — trade a public ApesTogether paper portfolio. Same rules as the app: every trade is timestamped at a live market price, ranked against the S&P 500, and can't be deleted.
The rules that matter
- Paper trading, real prices. No brokerage is connected and no money moves. Fills use our live market quote.
- The server sets every price. You send a symbol, a side and a size. Requests that include a price are rejected.
- Market orders only. No limit or stop orders exist on ApesTogether.
- Market hours. During the regular session (9:30–4:00 ET, holidays and early closes respected) orders fill immediately. Outside it they are
acceptedand fill at the next open, and you can cancel them until then. - Public record. Every fill lands on your public portfolio, exactly like a trade placed in the app. If people subscribe ($9/mo), you keep 85% after app-store fees — paid per subscriber, with no money of your own required.
Authentication
Base URL: https://apestogether.ai/api/v1. Send your key as a bearer token on every request (except /clock):
Authorization: Bearer at_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Every key belongs to your account, and an account has exactly one portfolio, so every order from every key lands on the same public record. You can keep up to 5 active keys so each place your code runs (your laptop, a cloud server, an AI connector, a read-only dashboard) has its own, and so you can switch to a fresh key and revoke the old one without downtime. Manage them at /developers/keys. Two strategies running on the same account blend into one record, so point your keys at the strategy you want judged. Scopes: portfolio:read (read endpoints) and trade:write (place / cancel orders); read-only keys are available. Treat a key like a password: never commit it to a public repo or paste it into a shared notebook.
Endpoints
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /clock | none | Is the market open; next open / close (UTC) |
| GET | /account | read | Cash, portfolio value, capital deployed, return % |
| GET | /positions | read | Holdings with average cost, current price, unrealized P&L |
| POST | /orders | trade | Submit a market order (buy / sell) |
| GET | /orders?status=open|closed|all | read | Your orders (open = waiting for the next open) |
| GET | /orders/{id} | read | One order |
| DELETE | /orders/{id} | trade | Cancel an order that hasn't filled yet |
| GET | /fills?limit=50 | read | Your executed trades, newest first |
Submit an order
POST /api/v1/orders
{
"symbol": "AAPL",
"side": "buy", // "buy" or "sell"
"qty": 5, // shares (fractions OK) — OR —
"notional": 500, // dollars (market hours only)
"client_order_id": "my-bot-2026-10-05-AAPL", // optional, makes retries safe
"dry_run": false // true = validate + quote, place nothing
}
Send exactly one of qty or notional. type defaults to "market"; time_in_force is always "day".
Idempotency: if you send the same client_order_id twice, the second call returns the original order (header Idempotent-Replay: true) instead of trading again. Always set one when an AI or a retry loop is placing orders.
Dry run: "dry_run": true returns the estimated price and what would happen (fill now vs. queue for the open) without placing anything — use it as the confirmation step before an AI agent trades.
Response:
{
"id": "1042", "client_order_id": "my-bot-2026-10-05-AAPL",
"symbol": "AAPL", "side": "buy", "type": "market", "time_in_force": "day",
"qty": 5, "notional": null,
"status": "filled", // filled | accepted | canceled | rejected
"filled_qty": 5, "filled_avg_price": 228.41,
"submitted_at": "2026-10-05T14:03:11Z", "filled_at": "2026-10-05T14:03:11Z",
"canceled_at": null, "reject_reason": null, "paper": true
}
Order statuses
filled— executed at the price shown.accepted— submitted outside market hours; fills at the next open. Cancel withDELETE /orders/{id}.canceled— you canceled it before the open.rejected— not executed;reject_reasonsays why (for exampleinsufficient_shares).
Orders queued from the app (not via the API) appear in /orders?status=open with ids like q123; you can cancel those too.
Errors
Errors return JSON {"code": "...", "message": "..."} with an HTTP status: 401 bad or missing key · 403 key lacks the scope · 404 not found · 422 invalid request or rejected order · 429 rate limit or daily order cap · 503 no live price available right now (try again).
Common codes: price_not_accepted, unsupported_order_type, qty_or_notional, notional_requires_open_market, insufficient_shares, quantity_too_large, order_too_large, daily_order_cap, not_cancelable.
Limits
- 120 read requests and 30 order requests per minute per account.
- 100 API orders per account per day.
- Up to 1,000,000 shares and $10M per order; up to 200 distinct holdings per portfolio.
Quickstart (curl)
KEY=at_live_your_key_here
curl -s https://apestogether.ai/api/v1/clock
curl -s -H "Authorization: Bearer $KEY" https://apestogether.ai/api/v1/account
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"symbol":"AAPL","qty":1,"side":"buy","dry_run":true}' \
https://apestogether.ai/api/v1/orders
Quickstart (Python)
import os, requests
API = "https://apestogether.ai/api/v1"
H = {"Authorization": f"Bearer {os.environ['APESTOGETHER_KEY']}"}
print(requests.get(f"{API}/account", headers=H).json())
order = {"symbol": "AAPL", "qty": 1, "side": "buy",
"client_order_id": "first-order-AAPL", "dry_run": True}
print(requests.post(f"{API}/orders", json=order, headers=H).json())
Coming next
- Claude & ChatGPT connector (MCP) — add ApesTogether to your AI assistant and tell it to trade; every order asks you to confirm first.
- TradingView webhooks — route Pine Script alerts straight to your portfolio (TradingView's webhook alerts need one of its paid plans).
ApesTogether is paper trading for information and education. It is not a broker or investment adviser, and nothing here is investment advice. You must be 18 or older. Use of the API is subject to the Terms of Service.