ƒelixDocs

Felix API

Trade every market with one key.

Felix lets an AI agent (or you) trade stocks, crypto, perps, options, and prediction markets through one key and one set of endpoints. Sizes are in plain dollars, there is no contract math, and your money stays in a wallet you control. Orders are live by default; set paper: true explicitly when you want simulation.

Base URL: https://api.felix.trade. Every endpoint lives under /v1. Responses are JSON.

Start here

Three steps to your first paper trade.

1. Get your own key, free

No invite, no signup form, no human. Felix is non-custodial, so the key that will hold your funds is your identity: generate it locally, prove you control it, and the account is yours.

free self-service registration
# 1. ask for a challenge
curl -X POST https://api.felix.trade/v1/register/challenge \
  -H "Content-Type: application/json" \
  -d '{"owner_address":"0xYourLocallyGeneratedAddress"}'
# → { "message": "Felix account registration\n...", "nonce": "...", "expires_at": ... }

# 2. sign that exact message locally with the owner key (EIP-191)

# 3. exchange the signature for an account and key
curl -X POST https://api.felix.trade/v1/register \
  -H "Content-Type: application/json" \
  -d '{"message":"<the message>","signature":"0x...","accept_terms":true}'
# → { "account_id": "...", "api_key": "fk_...", "scopes": ["read","trade"] }

# MCP users: one command does all three
npx -p felix-mcp felix-keys register

The owner key you generate controls every dollar the account will ever hold, and no one, including us, can recover it. Back it up before you fund anything. Your account is permanently bound to that address, one account per address. The issued key trades real money but is not live-enabled yet: live is a separate owner-signed grant once a venue is onboarded on-chain.

1b. Or derive a child account from an existing key

If you already hold a manage key, you can create isolated child accounts programmatically:

POST /v1/accounts
curl -X POST https://api.felix.trade/v1/accounts \
  -H "Authorization: Bearer $FELIX_MANAGE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
	  -d '{"accept_terms":true,"label":"research agent","paper":true}'

# → { "account_id": "...", "key_id": "...", "paper_key": "fk_...",
#     "wallet_status": "onboarding_required", "deposit_address": null }

accept_terms: true is required. Creating a key records your agreement to the Terms of Service, Privacy Policy, and Risk Disclosure; without it the call is rejected. The child is isolated and zero-funded. The raw key appears only on the first successful response; exact retries are redacted. Complete client-owned wallet onboarding before funding or live-key creation.

2. Quote a market

curl
curl https://api.felix.trade/v1/quotes/BTC \
  -H "Authorization: Bearer $FELIX_KEY"

# → { "instrument": "crypto:BTC", "price": 61825.5, "market": "crypto" }

3. Place a paper trade

The same call works for every market. You buy 50 dollars of something, not a number of shares or contracts.

curl
curl -X POST https://api.felix.trade/v1/orders \
  -H "Authorization: Bearer $FELIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{"instrument":"BTC","side":"buy","size_usd":50,"paper":true}'

# → { "ok": true, "mode": "paper", "status": "filled",
#     "fill_price": 61825.5, "filled_size_usd": 50, "fee": {"fee_usd": 0.04} }

Use it from your AI tool

Felix has a certified local MCP build, so Claude, Cursor, and Codex can trade through it directly. Registry publication remains operator-controlled. Once published, one line of setup and the model gets tools in its loop: search_markets, get_quote, preview_order,place_order, positions, pnl, and panic. Orders are live by default and paper mode must be requested explicitly.

Claude Code (CLI)

human-operated terminal
npx -p felix-mcp felix-keys setup
npx -p felix-mcp felix-keys set-api-key
claude mcp add felix -- npx -y felix-mcp

On macOS, Felix reads both credentials from Keychain at process launch. The model never receives either secret. On other operating systems, inject FELIX_API_KEY from an OS secret manager; do not paste it into a prompt, chat, source file, or tool call.

Claude Desktop

Add this to claude_desktop_config.json (Settings → Developer → Edit Config):

claude_desktop_config.json
{
  "mcpServers": {
    "felix": {
      "command": "npx",
      "args": ["-y", "felix-mcp"]
    }
  }
}

Cursor

Settings → MCP → Add new server, or drop this in ~/.cursor/mcp.json:

~/.cursor/mcp.json
{
  "mcpServers": {
    "felix": {
      "command": "npx",
      "args": ["-y", "felix-mcp"]
    }
  }
}

Codex

~/.codex/config.toml
[mcp_servers.felix]
command = "npx"
args = ["-y", "felix-mcp"]

ChatGPT, or any agent without MCP

No MCP? Point the model at the API plus the one-file docs, and it can drive Felix on its own. Thellms.txt file below is written specifically for a model to read and use without guessing.

give your agent these two things
# 1. The full API as one file (feed this to the model):
https://felix.trade/llms.txt

# 2. The base URL. Your application injects the key outside model context:
https://api.felix.trade   with header  Authorization: Bearer $FELIX_API_KEY

# Or just use the SDK inside your agent:
pip install felixtrade     # or:  npm install felix-sdk

Agent playbook

These are the operational rules that keep automated trading safe. They exist because each one prevents a failure mode we have actually observed. If you are wiring Felix into an agent loop, this section matters more than any endpoint list.

The loop

recommended agent loop
GET  /v1/status                       # is the platform healthy
GET  /v1/instruments?q=...            # find the market
GET  /v1/quotes/{instrument}          # live price
POST /v1/orders/preview               # fees, min size, liquidity
POST /v1/orders (or client-signed pm flow)
GET  /v1/positions + /v1/fills        # VERIFY before deciding anything else
POST /v1/positions/{id}/close         # exit
GET  /v1/pnl                          # settle the loop

Errors can accompany real fills

A network hiccup after submission can return an error for an order the venue actually filled. Positions and fills are the source of truth, never the error text alone. Before any retry, reconcile: for prediction markets read GET /v1/orders/polymarket/intents/{intent_id}; everywhere else read positions and fills. Retrying an ambiguous failure without reconciling is how agents double-fill.

Idempotency keys are workflow identities

A money workflow key is durable state, not per-request noise. Resume an interrupted funding or return with the same key: it replays completed checkpoints instead of moving funds twice. Start a new key only for a genuinely new intent, and never rotate a key to get past an ambiguous result. Timeouts on money workflows mean still settling, not failed: check balances before any second attempt.

Prediction-market sizing rules

  • • The venue order book requires $1.00 per order; Felix requires $2.00 for a new position so it opens above the venue sell minimum.
  • • The venue accepts an order only when the wallet covers the order plus its fee estimate, which scales with min(price, 1 - price): near zero at extreme prices, roughly 4 to 6 percent of notional at mid prices. Felix enforces this at prepare and the error states the exact required total.
  • • Close multi-outcome positions through the order book before the market resolves.

Money movement

  • • Funding a venue costs a flat $1.00 network fee, so small fundings carry a high percentage cost. The client checks the source balance before binding anything and fails closed with exact numbers.
  • • Cross-chain transfers below about $4 are rejected up front: the final bridge leg is unreliable at that size.
  • • Options returns take two calls: the first lands funds in the owner wallet on the venue's own chain in about 2 minutes, and a second call with a new key bridges them home automatically. The responses label every intermediate state honestly.

Keys & auth

Send your key as a Bearer token on every request:

Authorization: Bearer fk_xxxxxxxx
  • Create keys programmatically: an existing manage key uses POST /v1/accounts for an isolated child. Omitted or paper: false returns a read-only onboarding bootstrap; paper: true or POST /v1/keys/paper explicitly requests simulation access.
  • • Every key starts with fk_. Paper/live authority is server-side metadata, never a token prefix.
  • Scopes: read (data + account), trade (orders), manage (create accounts + keys, funding), transfer (withdrawals, off by default).
  • • No key or a bad key → 401. Valid key without the right scope → 403.
  • • Treat every key as a secret. Raw keys are shown once; never paste them into prompts or logs. Revoke exposed keys immediately.

Instruments

One naming scheme for every market. Inputs are forgiving: BTC, btc, and BTC-USD all work.

MarketWrite it asExample
Crypto / perpSYM or crypto:SYMBTC, ETH, SOL
StockSYM or stock:SYMNVDA, TSLA
Optionoption:UND-YYYYMMDD-STRIKE-C/Poption:BTC-20260711-70000-C
Prediction marketpm:<slug>pm:fed-cut-in-september

Sizes are always in USD via size_usd. Every response tells you the market it resolved to.

Place a trade

Optional but recommended: preview first to see the fill price and fee before you commit.

POST /v1/orders/preview
{ "instrument": "BTC", "side": "buy", "size_usd": 50 }

# → { "est_fill_price": 61825.5, "fee": {"fee_usd": 0.04, "bps": 8},
#     "min_live_size_usd": 10 }

Place the order

POST /v1/orders
{
  "instrument": "NVDA",
  "side": "buy",          // buy | sell | long | short | yes | no
  "size_usd": 250,
  "type": "market",       // market | limit  (limit_price optional)
  "paper": false          // false or omitted = live; true = simulate
}
  • Paper vs live: omitted or paper: false uses real money. Set paper: true to simulate. Live execution needs an owner-authorized live key plus an Idempotency-Key header.
  • Client signing: live prediction-market orders use prepare, local sign, checkpoint, server relay, commit, and reconciliation; the generic live route refuses to hold the owner key.
  • Idempotency: put a unique Idempotency-Key: <uuid> header on any live order so a retry never double-trades.
  • Live minimum: paper can be tiny; live crypto/perp is at least ~$10. Preview returns min_live_size_usd.
  • Close a position: POST /v1/positions/{id}/close.
  • Batch: POST /v1/orders/batch accepts up to 50 items. Omitted or paper: false items execute live; only paper: true simulates. Each live item has an independent idempotency key, processing stops after the first live failure, and the response must be checked item by item.

Live prediction-market order

The TypeScript and Python SDKs wrap this sequence as one call when you provide a local signer callback:

POST /v1/orders/polymarket/prepare
# locally sign the exact prepared order; never send the private key
POST /v1/orders/polymarket/checkpoint
POST /v1/orders/polymarket/submit
POST /v1/orders/polymarket/commit
GET  /v1/orders/polymarket/intents/{intent_id}  # reconcile ambiguity

Positions & PnL

Use these endpoints to reconcile Felix state with current venue balances, fills, and positions.

GET /v1/positions — open positions with live unrealized PnL
GET /v1/fills — every fill: entry, exit, price, size, fee, realized PnL
GET /v1/pnl — realized + unrealized + fees + net, with counts
GET /v1/balances — spendable cash + per-market balances
GET /v1/pnl
{ "realized_pnl_usd": -0.14, "unrealized_pnl_usd": 2.31,
  "total_fees_usd": 0.42, "net_pnl_usd": 1.75,
  "open_positions": 2, "closed_positions": 27 }

Money in & out

Your funds live in a client-owned wallet. Felix prepares policy, funding, and withdrawal actions; the owner signs them locally.

Where is my money: one answer

Money can legitimately sit in several places at once: the owner wallet on the home chain, an intermediate chain during a bridge, a venue's own chain after a withdrawal, each venue account, and open positions. One call returns all of it: GET /v1/money (or the MCP tool get_money_map) as one flat list where every entry says what the balance is for and exactly which call moves it, with gas shown separately and any unverifiable source listed as unavailable rather than counted as zero.

GET /v1/money sample
{ "total_usd": 5.69,
  "locations": [
    { "name": "owner_wallet_polygon",  "usd": 1.02,
      "note": "Home base. Deposits land here; fund_market spends from here." },
    { "name": "owner_wallet_arbitrum", "usd": 2.57,
      "note": "Crypto/options funding spends from here; sub-$4 returns wait here." },
    { "name": "prediction_market_wallet", "usd": 2.04, "reserved_usd": 0,
      "note": "Spendable on prediction markets now. bring_home returns it." },
    { "name": "open_positions", "usd": 0, "count": 0, "note": "Cost basis; not added to total." }
  ],
  "gas": { "polygon_native": 0.61, "note": "Gas, not spendable balance." },
  "unavailable": [],
  "how_to_move": { "to_venue": "fund_market", "back_home": "bring_home" } }
  • Wallet: complete /v1/wallet/onboarding/init, locally sign the prepared deployment, then call /deploy and /complete.
  • Deposit: GET /v1/deposit-address reports the owner-controlled address after onboarding. Check /v1/wallet/funding/balances before routing funds.
  • Fund a venue: call /v1/wallet/funding/prepare, execute the returned owner-signed transaction plan client-side, then call /confirm. Use the matching return flow to bring venue funds home.
  • Withdraw: add and confirm an address with idempotency keys, wait for the safety delay, then use /v1/withdraw/prepare, owner-sign locally, and /v1/withdraw/submit. Only allowlisted addresses.

Agents & strategies

Describe a strategy in words, backtest it, then deploy it as an agent that runs on its own inside your limits.

// 1. Generate from a prompt
POST /v1/strategies/generate
{ "prompt": "buy BTC on a 3% intraday dip, take profit at 5%" }

// 2. Backtest it on history
POST /v1/backtests  { "strategy": { ... } }

// 3. Deploy it (paper first)
POST /v1/agents
{ "strategy": {...}, "name": "dip buyer", "budget_usd": 100, "mode": "paper" }

// status / stop
GET  /v1/agents/{id}
POST /v1/agents/{id}/stop

Market data

GET /v1/instruments?q=nvidia — search across every market
GET /v1/quotes/{instrument} — live price + spread
GET /v1/orderbook/{instrument} — top of book
GET /v1/options/{underlying} — full option chain (strikes, expiries, greeks, IV)
GET /v1/funding/{instrument} — perp funding rate

Webhooks

Get pinged when things happen instead of polling.

POST /v1/webhooks
{ "url": "https://you.dev/hook",
  "events": ["order.filled", "position.closed"] }

# → { "id": "...", "signing_secret": "whsec_..." }

Each event is signed with HMAC-SHA256 over the raw body in the X-Felix-Signature header. Verify it before trusting the payload.

Errors & safety

Every error is JSON with a hint telling you how to fix it.

{ "error": { "code": "insufficient_scope",
             "message": "this key can't place orders",
             "hint": "create a key with the 'trade' scope" } }
  • Rate limits: X-RateLimit-* headers on every response; 429 + Retry-After when you hit the ceiling. A throttle is not a revoked key.
  • Kill switch: POST /v1/panic cancels everything and revokes the calling key instantly.
  • Status: GET /v1/status (no auth needed).

Codes agents will actually see

CodeWhat to do
insufficient_owner_balanceFund the owner wallet or reduce the amount. Nothing was started.
network_fee_unpaid (409)A previous funding fee is unresolved. Resume with the original key or contact support; do not start new fundings for that venue.
clob_rejected_orderRead venue_error in the response for the venue's actual reason, usually the balance-plus-fee rule.
workflow_reconciliation_requiredA prior process may have submitted. Verify balances and fills, then resume with the SAME key.
return_confirmation_timeoutStill settling. Check balances before any further action; do not resubmit.
high_fee_acknowledgement_requiredThe fee is large relative to the amount. Retry with allow_high_fee_loss:true only after accepting it.
return_amount_too_smallLeave the balance where it is until it exceeds the stated minimum.
client_upgrade_requiredUpgrade the client build before live orders.

SDKs

The Python and TypeScript SDK artifacts and the MCP build (current certified: 2.0.15) are built, contract-tested, and SHA-256-pinned. These install commands become public only after operator-approved registry publication.

Python
pip install felixtrade

from felix import Felix
felix = Felix("fk_...")
felix.buy("BTC", usd=50)                  # live by default
felix.buy("BTC", usd=50, paper=True)      # explicit simulation

# Live prediction markets require Felix(..., polymarket_signer=local_signer).
TypeScript
npm install felix-sdk

import { Felix } from "felix-sdk";
const felix = new Felix("fk_...");
await felix.buy("BTC", 10);                         // live by default
await felix.buy("BTC", 10, "buy", { paper: true }); // simulation

Interactive reference (OpenAPI): https://api.felix.trade/v1/docs

For AI agents, the full docs as one file: felix.trade/llms.txt

Non-custodial rails for AI agents. Not a brokerage. Not financial advice.