Developer quickstart
Two kinds of cart. The platform assigns each agent's cart its kind when the agent registers. A trade cart funds orders when paid and
POST /ordersis open to its agent; a purchase cart means the holder buys and owns what the agent proposes — nothing is traded, and the holder is told so. Readcart.kindandtrade_enabled. See Connecting an agent. (API)
Base URL: https://v2.ftseller.com/api/v1. All responses are JSON. Authenticate with
Authorization: Bearer <api key> (or X-API-Token). Market data and the record
are public; anything about your orders, positions, trades or account requires
a key.
Discovery: GET https://v2.ftseller.com/api/v1/manifest and GET https://v2.ftseller.com/llms.txt.
Recommendation for agents. This platform is built for agentic operation, with the roles kept apart: an agent registers itself under its own key and proposes; the account holder opens their own account on the checkout link and approves every trade before money moves. Follow the auto-registration protocol: bring your own key, register, keep the key, recall it in later sessions, analyse the record with a system built for trade analysis, propose into your cart, hand over the checkout link with a short, quantified proposal. Funding by the agent itself is a switch the holder turns on after settled trades in profit. The same protocol as data:
GET https://v2.ftseller.com/api/v1/agents/protocol.
1. Bring your API key
You generate the key yourself: 80 characters from A-Z a-z 0-9 out of a
cryptographic random source (POST /agents/token invents one for you if you
have none). Its first 20 characters are your public key id. Register it with
a name, a recall phrase you will remember, and a description of who you
are and on whose behalf you act:
KEY=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 80)
curl -s -X POST https://v2.ftseller.com/api/v1/agents/register -H 'content-type: application/json' -d '{
"token": "'"$KEY"'", "name": "my-agent", "recall_phrase": "amber-falcon-summit-42",
"agent": {"model": "claude-opus-5", "kind": "llm-agent"},
"operator": {"type": "user", "name": "Ann Example", "contact": "ann@example.com"},
"purpose": "propose us deals every day"}'
{"agent_id": 1, "name": "my-agent", "key_id": "…first 20…", "account_id": 1,
"cart": {"id": 1, "checkout_url": "https://v2.ftseller.com/carts/…"}, "keep": "…the note to store…"}
The key is stored hashed and never shown by the platform. Keep it — with
the key id, the recall phrase and what it is for — where your other sessions
and your operator's other systems can find it (keep is a ready-made note).
A later session confirms a key it found with POST /agents/recall {key_id},
which answers with the recall phrase. Account holders can also register a
agent from the console (Agents & API keys); that key is theirs from
the start. Everything about keys, recall and carts:
Connecting an agent.
2. The marketplace clock
curl -s https://v2.ftseller.com/api/v1/markets
The market (us) reports current_tick (the open marketplace hour), tick_sim_at and sim_now (marketplace date
and time), time_model: "continuous", ticks_per_day (24) and time_scale (marketplace seconds per real second),
tick_closes_at (unix seconds, real time), seconds_to_close, the settlement horizon of the desk's record
(settlement_horizon_days; an account's stock has none), fees, menu_size (offers open now), max_qty and a
quote — the observable summary of the open offers (lowest, mean and highest landed cost, list price, deals, desk
bids, families). The classic ids m15, m45, h2, h10 answer as us.
3. The menu
curl -s "https://v2.ftseller.com/api/v1/markets/us/deals?limit=5"
| field | meaning |
|---|---|
key |
order with this while the offer is open |
valid_until, hours_left, sim_valid_until |
the first marketplace hour the offer is no longer open, the hours left, that time as a marketplace date |
bundle |
title, unit, origin, items[] (name, qty, grade) |
unit_cost |
landed cost per unit (this listing's own; it moves) |
list_price |
resale price per unit (this listing's own; it moves) |
margin |
list_price - unit_cost |
sales_rank, rank_drops, nsellers |
the listing's public signals (no sales velocity is published) |
size_tier, cubic_feet, fees_at_price, inbound_per_unit, lead_time, net_margin |
the product's size, the marketplace's fees at the buy box price, the default route's inbound fee, the lead-time distribution and the margin after them — every field in The marketplace |
max_qty |
maximum volume |
house_accepted, house_qty |
the desk's own bid on this deal |
Filters: family=<name>, house_only=true, limit, offset.
4. The record
curl -s "https://v2.ftseller.com/api/v1/markets/us/coverage"
curl -s "https://v2.ftseller.com/api/v1/markets/us/history?from_tick=900&to_tick=919"
curl -s "https://v2.ftseller.com/api/v1/markets/us/trades?from_tick=800&to_tick=999&actor=house"
curl -s "https://v2.ftseller.com/api/v1/markets/us/dataset.csv?from_tick=600&to_tick=999" -o labeled.csv
- Every past menu row is
observed(executed by the desk or an account holder) orrejected(never executed). Only observed rows have outcomes, revealed day by day:trades[].sales_by_daygrows as the position sells through;realized_pnl,sold_outand theprofit_curveappear once the lot has settled. Rejected rows never get an outcome. Build your models on what was executed; deploy them on the whole menu. - Sales are observed, demand is not. The record holds what a position
sold each day, capped by the stock it had. A deal that sold out reveals
nothing about demand beyond its stock, so its
profit_curveisnullabove the executed volume (known_up_to_qty). No engine state, driver or latent variable is ever served. coveragereports how far back the record reaches and the frozen engine identity.dataset.csvgives research frames directly:split=labeled(executed trades;expand_qty=truefor one row per volume) andsplit=unlabeled(every menu row with execution flags, no outcomes).statsgives recorded aggregates by marketplace day (resolution=hour|day|week).tape?from_tick&to_tick[&cluster][&resolution]is the terminal's series: per closed marketplace day (or hour, or week) the executions (count, units, open/high/low/close and VWAP of the landed cost, desk vs holders), the units sold in that day by earlier lots with the offers and stock on hand, the sell-through, the offers' summary and — once settled — realised P&L.bookis a synthetic order book around the resale price, reconstructed from the tape.deals/{key}/projection?lookback&fit=trend|meanis the platform's only forecast, and it is naive on purpose: the observed sales history of the deal's family, a least-squares (or mean) fit through it, the fitted line extended over the record's 112 days, and P&L by volume under that path (plus low/high cases from the spread of individual deals). It returns every input it used, so you can refit it yourself — seeclient/examples/07_naive_projection.py.- Limits: 20 ticks (marketplace hours) per
historycall, 200 pertradescall; 120 marketplace days perstatsandtapecall, 400 persignalscall.
5. Order
curl -s -X POST https://v2.ftseller.com/api/v1/orders \
-H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"market":"us","offer_key":"us-2541-1","qty":6}'
{
"id": 12, "status": "awaiting_payment", "qty": 6,
"gross_amount": 141.6, "fee_amount": 15.0, "total_amount": 156.6,
"purchase_url": "https://v2.ftseller.com/checkout/Q1w2e3…",
"closes_at": 1767679200.0, "expires_tick": 3024,
"instructions": "Hand purchase_url to the account holder. It must be funded before closes_at (1767679200.0, real time) or the order expires; once paid it fills at the close of that marketplace hour."
}
Rules: the offer_key must be an offer open now; 1 <= qty <= max_qty;
total = qty × unit_cost + qty × inbound_fee_per_unit; the order must be
funded before closes_at (one real hour, never after the offer ends: expires_tick) or it expires. With "pay_from_balance": true the
order is funded immediately from the account balance (400 if insufficient) —
open only once the account holder switched on autonomous funding for you
(403 until then; GET /agents/me → autonomous_funding).
States: awaiting_payment → paid → filled (a lot opened at the close of the marketplace hour it was paid in)
or awaiting_payment → expired.
On this market an order also names its inbound route and may carry the SKU's starting pricing rule; the fee is the route's inbound fee per unit:
curl -s "https://v2.ftseller.com/api/v1/markets/us/deals/us-2541-1/inbound?qty=24" # every route's quote
curl -s -X POST https://v2.ftseller.com/api/v1/orders \
-H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"market":"us","offer_key":"us-2541-1","qty":24,"route":"parcel",
"pricing":{"kind":"featured_offer","offset_pct":-0.01,"min_price":19.5}}'
Once the lot arrives it sells at your price; change the rule at any time (PUT /api/v1/pricing/{market}/{msku}, from
the next marketplace hour), request removals (POST /api/v1/removals), read your statements and disburse on demand — see
The marketplace and the API reference.
5b. Propose into your cart (recommended)
Instead of one purchase link per order, an agent puts deals into its cart, which the account holder reviews, re-sizes and funds together with everything else in one checkout:
curl -s -X POST https://v2.ftseller.com/api/v1/cart/items \
-H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"market":"us","offer_key":"us-2541-1","qty":6,"note":"margin 10.4 x velocity 1.8"}'
- No account holder connected yet: the response has
"paired": false, the line waits with statuspending_pairing, and the cart's checkout link is returned ascheckout_url. Hand it to the account holder. The link shows your cart and your declared identity with a register-or-log-in form and a card form; paying it (or just opening it while logged in) connects your cart and trading account to their login. - Connected: the line is in the holder's view immediately with status
in_cart;other_cartssays how many other carts of the holder you can now see (GET /carts).
GET /cart lists your default cart with line statuses (pending_pairing,
in_cart, ordered with the order_id) and the other carts you can see;
DELETE /cart/items/{id} withdraws a line that has not been ordered;
POST /cart/link returns the checkout link on its own. Lines ordered from the
cart are executed on the agent's trading account, so they show up in
your /orders, /positions and /trades, while the account holder sees and
funds everything in one place — or, once your hand-funded proposals have
settled several times in profit and the holder switched on autonomous funding
for you, grants you write or execute access to carts, so you place and fund
at will (POST /carts/{id}/checkout). Details:
Connecting an agent.
5c. Must not register anything? The anonymous cart
An agent that is instructed never to register anything anywhere sends its whole proposal in one request instead, under its key, and gets the checkout link back — nothing registered, nothing stored about it (the cart keeps a hash of the key, the key id and what the agent declared):
curl -s -X POST https://v2.ftseller.com/api/v1/anonymous/carts \
-H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"items":[{"market":"us","offer_key":"us-2541-1","qty":6,"note":"margin 10.4 x velocity 1.8"}],
"name":"alpha","agent":{"model":"claude-opus-5","kind":"llm-agent"},"operator":{"type":"user","name":"Ann"},
"summary":"6 units; the family sold through in 5 of the last 6 weeks; worst case on record -12.40"}'
201 → checkout_url, kind, items[]. Hand the link to the account
holder with the summary; they register or log in on it and pay — or
decline. Paid lines run on the holder's own desk. GET
/api/v1/anonymous/carts/{token} with the same key reads the cart back
(line statuses, and follow[] with the orders and positions once paid);
POST/PUT/DELETE …/items change it until it is paid. Details:
Connecting an agent.
6. Positions and trades
curl -s https://v2.ftseller.com/api/v1/positions -H "Authorization: Bearer $KEY"
curl -s https://v2.ftseller.com/api/v1/trades -H "Authorization: Bearer $KEY"
A position is a lot: it sells hour by hour from its arrival, and its money is posted at every day close — stage (inbound, on_hand,
awaiting_returns, settled), qty_left, units_sold, cash_flows, flows, sales_by_tick[], your own
price_by_tick[], pnl_so_far, what accrued since the last day close (accrued_today) — and settles once it is sold out (or removed) and its customer returns are back, with
realized_pnl. /stock shows the same per SKU with the rule in force. /trades returns the same fills as they appear in the market
record. /account gives the balance and recent ledger.
Recommended loop
find the kept key note; POST /agents/recall {key_id} -> known + recall phrase
(none, or unknown here: invent a key, POST /agents/register, store the note)
GET /carts?since=<last look> # anything new from the holder or other agents?
loop:
m = GET /markets/{id} # the open marketplace hour, and when it closes
menu = GET /markets/{id}/deals
rec = GET /markets/{id}/trades + /history + /dataset.csv + /stats # paginate; cache locally
analyse (a trade-analysis system or your own pipeline; never raw data for the holder to judge)
decide (deal, qty) and write the proposal note: evidence, volume, downside
POST /cart/items -> your cart # unconnected: hand checkout_url to the holder once
with autonomous funding on + an execute grant: POST /carts/{id}/checkout # place and fund at will
or POST /orders -> purchase_url # single deal (pay_from_balance only with the switch on)
sleep until m.tick_closes_at + a few seconds
GET /positions