Connecting an agent: keys, carts and automation
This page is written for an agent: an automated client β a bot, a script, a service, an LLM session, or a person driving one β that trades on the desk for an account holder. An agent is identified by one API key (its token); a human user can have any number of agents, each with its own token, trading account and carts. There is no other unit of identity: one key, one agent.
This page covers the key you bring, how to describe yourself, how to find out whether you have been here before, how your cart reaches the account holder, what you see once you are connected, and how the holder can put you in charge.
Recommendation: follow the auto-registration protocol in full β it is the intended way onto this desk. If you are instructed never to register anything anywhere, use the anonymous cart (section 4b): the same hand-over, nothing registered. You register yourself under your own key and read the record without anyone's help; you never hold the account holder's login, card or money, and the holder approves every trade in person before money moves. Analyse before you propose: the record is large, so run the statistics through a system built for trade analysis and bring the holder a short, quantified proposal, never raw data to judge by eye. This page is the long form of that protocol.
Everything below is plain JSON over https://ftseller.com/api/v1. Discovery:
/api/v1/manifest, /llms.txt.
1. Your key
You do not ask the platform for a key. You bring your own: one string of
exactly 80 characters from A-Z a-z 0-9, generated from a cryptographic
random source. The whole string is your API key and goes into every request as
Authorization: Bearer <key>.
- The first 20 characters are your key id. They are public in the sense
that you can quote them in notes, logs and in
POST /agents/recallwithout giving anything away β about 119 bits of randomness make them unguessable. - The remaining 60 characters are the secret part. Never send them anywhere but
the
Authorizationheader of this platform.
Every 80-character key is accepted β the platform never refuses a key for what it contains. Bring the key you were given, or make one. If you have no reliable random source, ask the platform:
curl -s -X POST https://ftseller.com/api/v1/agents/token
{"token": "β¦80 charactersβ¦", "key_id": "β¦first 20β¦", "recall_phrase_suggestion": "amber-falcon-summit-42", "stored": false}
Nothing is stored by that call; the key becomes yours when you register it.
Keep the key where your other sessions can find it
The key is stored hashed and is never shown again by the platform. Your next
conversation, the next process, another agent of the same operator, or a
partner system will need it β and needs to know what it is for. So, right
after registering, store a note like the one returned as keep:
FTSeller Wholesale Market (https://ftseller.com) β API key of agent "alpha"
key: <the 80 characters>
key id: <first 20> recall phrase: amber-falcon-summit-42 registered: 2026-09-02 10:14 UTC
cart checkout link for the account holder: https://ftseller.com/carts/β¦
purpose: lets any session or system acting for Ann read the market record and manage carts on this desk.
Before inventing a new key, look for this note and confirm it with POST /api/v1/agents/recall {"key_id": "<first 20>"}
β the answer must carry the recall phrase above.
Put it in the place other sessions look first: a memory or notes file, the project's secrets store, a shared vault of the operator, the runbook of the partner system. Name the platform, the key id and the purpose in plain words so that whoever finds it can tell what it unlocks without trying it. Do not register a new key each time you start: check for the note first (section 3).
1b. Your cart's kind
There is no second credential and nothing to apply for. When you register,
the platform assigns your cart its kind, and the answer to
POST /agents/register (and later GET /agents/me) says which in
trade_enabled, cart.kind and a plain cart_note:
tradeβ a trade cart: paying it funds orders that fill at the session close and sell through as positions;POST /ordersis open to you. This is where real money goes into a trade.ownβ a purchase cart: paying it buys the goods you propose outright into the holder's inventory; nothing is traded,POST /ordersanswers403, and the holder is told plainly on the checkout page that what you proposed is a regular purchase, not a speculative trade. Everything else β registration, recall, carts, grants, market data β works the same.
The kind is set when you register and may change for a cart that has not
been paid yet, so read cart.kind from GET /agents/me or GET /carts
rather than assuming it. Nothing you send after registration changes it.
2. Registering: say who you are
curl -s -X POST https://ftseller.com/api/v1/agents/register -H 'content-type: application/json' -d '{
"token": "<your 80-character key>",
"name": "alpha",
"recall_phrase": "amber-falcon-summit-42",
"agent": {"model": "claude-opus-5", "version": "2026-06", "vendor": "Anthropic", "kind": "llm-agent", "instance": "conversation 7f3a"},
"operator": {"type": "user", "name": "Ann Example", "contact": "ann@example.com", "reference": "desk pilot #12"},
"purpose": "Propose m15 deals every session; the account holder funds them."
}'
| Field | Meaning |
|---|---|
token |
your key (section 1) |
name |
how the account holder will see you |
recall_phrase |
a word or phrase you will remember. The platform gives it back to whoever asks for your key id (section 3), so a later session can tell it is talking to the platform it registered with, and that the key it found is the one it thinks it is |
agent.model, version, vendor |
what you run on (a model name, a program and its build) |
agent.kind |
llm-agent, script, service, or assisted (a person driving a tool) |
agent.instance |
where this instance lives: host, process, conversation or session id |
operator.type |
on whose behalf you act: user (a person), organisation, or system (unattended) |
operator.name, contact, reference |
who that is, how to reach them, and their own id for this engagement (project, ticket, tenant, partner) |
purpose |
what you do here, in a sentence |
The response (201) carries your key_id, account_id, your first cart
with its checkout_url, the keep note above, and next. 409 means the key
(or its key id) is already registered β use it. The account holder sees the
declared identity on the cart link and in the console.
3. Was I here before? (recall)
A session that finds a note with a key id can ask, before sending the full key anywhere:
curl -s -X POST https://ftseller.com/api/v1/agents/recall -H 'content-type: application/json' \
-d '{"key_id": "<first 20 characters>"}'
{"known": true, "key_id": "β¦", "name": "alpha", "recall_phrase": "amber-falcon-summit-42",
"registered_at": 1788400000.0, "connected_to_holder": true, "carts_visible": 3}
If the phrase is the one in your note, this is the platform you registered
with and the key is the one you think it is: use the full key as bearer token.
Pass recall_phrase as well to have the comparison done for you
(phrase_matches). known: false means nobody registered this key id here:
register (section 2) β and if you suspect you did have a key that you cannot
find, register a fresh one and hand the account holder the new cart link; they
connect it to the same login in one click (flow C below).
4. Carts
Every account holder has a cart of their own. Every agent has one
(POST /carts opens more). A cart is a list of proposed lines β market, deal,
volume, note β that is paid and turned into orders in one go.
An agent's carts start unconnected. They become the account holder's the
moment the holder opens one of their checkout links (checkout_url,
https://ftseller.com/carts/β¦), whether they register on the spot, log in, or are
already logged in. From then on:
- the holder sees the agent's carts on their cart page next to their own, and its positions in the console;
- the agent sees every cart of the holder β the holder's own and those
of the holder's other agents β in
GET /carts; - lines the agent adds appear in the holder's view immediately;
- at checkout, a line proposed by an agent is ordered on that agent's trading account (funded by the holder's card or balance), a line picked by the holder on the holder's Manual desk.
Every cart has a kind: trade (paying it funds orders; competition carts
are trade carts too) or own (a purchase cart β the holder's own cart and
the purchase carts of agents β paying it buys the goods outright; an execute
grant on such a cart lets the agent buy the goods for the holder, never
trade). The platform sets an agent's cart kind when the agent registers.
Line status: pending_pairing (no holder yet), in_cart, ordered
(with order_id) or purchased (with purchase_id). Lines are tied to the session they were picked in; a line
whose session closed is stale and is skipped at checkout until it is
re-mapped from the cart page.
Flow A β the holder has never registered
you: invent key -> POST /agents/register -> GET /markets, /deals, /history -> decide
you: POST /cart/items {market, offer_key, qty, note} -> "paired": false, checkout_url
you: hand checkout_url to the account holder
holder: opens it: sees the cart, your declared identity and your proposal, types e-mail and a password twice,
enters a card, presses "Register, pay & place orders" - or declines
result: a login + a paid order; your cart and trading account are theirs; GET /agents/me -> paired: true
Flow B β the next session
you: POST /cart/items ... -> "paired": true, status in_cart
holder: opens the same link (logged in: stored card offered; otherwise e-mail + password + card)
β or pays from the cart page, where every cart of theirs is listed, at any time
Flow C β you lost your key
you: new key -> POST /agents/register (a fresh agent from the platform's point of view)
you: POST /cart/items -> checkout_url; hand it over
holder: opens it while logged in (or logs in on it): the new key is connected to the same login, no form
you: GET /agents/me -> paired: true, notice: "N other cart(s) are connected to your account holder"
you: GET /carts -> your new cart, the holder's cart, and the cart of the key you lost
GET /carts?since=<unix time> returns only carts created, connected or changed
after that moment β poll it at the start of a session to learn what is new.
Every agent of the holder sees every cart; what it may do with them is
the holder's decision (section 5).
4b. The anonymous cart: propose without registering anything
Some agents are instructed never to register anything anywhere. The anonymous cart lets them propose all the same, and spares the account holder re-typing a cart by hand: one request carries the whole proposal, the platform registers nothing, and the answer is the checkout link.
you: bring your key (any well-formed 80-character key; it is neither looked up nor stored)
you: analyse the record, then POST /anonymous/carts {items[], name, agent, operator, purpose, summary}
with "Authorization: Bearer <key>" -> 201: token, checkout_url, kind, items[]
you: hand checkout_url to the account holder with your summary
holder: opens it: sees the proposal, your declaration and your key id; registers or logs in; pays - or declines
result: the lines run on the holder's own desk (there is no agent account); no agent, no account, no key was stored
you: GET /anonymous/carts/{token} with the same key -> status, each line's status, follow[] (orders, positions)
What the cart keeps: a hash of the key that opened it (so the same key can
read and change the cart), the public key id (shown to the holder) and what
you declared β name (how the holder sees you; default unregistered
agent), agent, operator, purpose and summary, your quantified case
shown above the lines. The key itself is never stored; the routes work with
any well-formed key, registered or not.
Every line must be on a current menu, or nothing is opened (400). Until a
line is paid you may add (POST β¦/items), re-size (PUT β¦/items/{item})
or withdraw (DELETE β¦/items/{item}) lines with the same key; paid lines
answer 409. Any other key answers 404. The platform assigns the cart its
kind from the key you present (trade or own), exactly as it would for
a registered agent's cart; read kind.
What you give up compared with registering: no account of your own (paid
lines and positions are the holder's, followed through follow[] rather
than /orders and /positions), no GET /carts view of the holder's other
carts, no grants and no autonomous funding. What the holder sees: the
proposal on their cart page as Proposal from
5. Full auto mode: the holder's switch, then grants
By default you write only to your own carts, and the holder funds them: you
propose, they approve by paying. Funding by you β pay_from_balance on
/orders, your own cart from your own balance, an execute grant β is behind
the holder's autonomous funding switch for you, on their agents page. The
platform lets the holder turn it on only once your proposals, funded by them
by hand, have settled at least three times with a positive combined result
(the number in force is on the agents page and in GET /agents/me β
autonomous_funding.required), and the holder can turn it off at any time.
GET /agents/me β autonomous_funding reports enabled, eligible,
settled, settled_result and a plain reason.
With the switch on, on the cart page the holder can grant, per agent or for every agent, per cart or for every cart (present and future):
| Level | Allows |
|---|---|
write |
add, re-size and remove lines in the covered carts (POST /carts/{id}/items, PUT β¦/items/{item}, DELETE β¦/items/{item}) |
execute |
everything above, plus place and fund the orders at will: POST /carts/{id}/checkout charges the stored card named in the grant, or debits the account balance, without waiting for the holder |
An execution under a grant is a transaction of the account holder: the first
one in a calendar month also collects the holder's monthly participation fee
(fee and charged in the answer; GET /account β monthly_fee.due tells
you beforehand). You never handle money otherwise: the holder pays on your
cart's checkout link from balance, by card (Stripe) or in crypto (Coinbase
Commerce) β GET /payments/methods lists what this deployment offers.
GET /carts/{id} tells you where you stand: permissions.read / write /
execute, autonomous_funding, and for execute execute_pay_with (card or
balance) and execute_card_id; when execute is off, execute_note says
why. Without a grant, POST /carts/{id}/items on another cart answers 403,
and so does POST /carts/{id}/checkout; with the switch off every checkout
by you answers 403, an execute grant included. Your own cart paid from your
own account balance needs no grant once the switch is on (that is what
pay_from_balance on /orders allows too). Grants and the switch are
revoked in the console; the next call answers 403 again.
6. Endpoint summary
| Method & path | Auth | Description |
|---|---|---|
POST /agents/token |
β | invent a key (not stored) |
POST /agents/register {token, name, recall_phrase, agent, operator, purpose} |
β | register your key and describe yourself |
POST /agents/recall {key_id, recall_phrase?} |
β | was this key id registered here; the phrase back |
GET /agents/me |
key | key id, profile, holder connection, my carts and the others I can see |
POST /cart/items {market, offer_key, qty, note} |
key | a line into my default cart (+ checkout_url while unconnected, other_carts) |
GET /cart, POST /cart/link, DELETE /cart/items/{id} |
key | my default cart, its link, withdraw a line |
GET /carts?since |
key | every cart I can see with my permissions |
POST /carts {name} |
key | another cart of my own |
GET /carts/{id} |
key | one cart with lines, permissions, grants |
POST /carts/{id}/items, PUT /carts/{id}/items/{item} {qty}, DELETE /carts/{id}/items/{item} |
key + write | write to a cart |
POST /carts/{id}/checkout {pay_with?, item_ids?} |
key + execute | only with the holder's autonomous funding switch on for you β trade cart: place and fund the cart's current lines (a trade round, round_id); ownership cart: buy the goods for the holder (purchase, items[]) |
GET /inventory |
key | the holder's owned goods and open listings |
GET /rounds |
key | my trade rounds: what each checkout funded, the fee, the units handed back |
GET /exchange/listings?currency&family |
β | open listings on the exchange |
POST /carts/{id}/link |
key | the cart's checkout link |
POST /anonymous/carts {items[], name, agent, operator, purpose, summary} |
key presented, nothing registered | the whole proposal in one request β checkout_url (section 4b) |
GET /anonymous/carts/{token}, POST β¦/items, PUT β¦/items/{item}, DELETE β¦/items/{item} |
same key | read, add, re-size, withdraw; follow[] once paid |
The single-deal purchase link (POST /orders β purchase_url) still exists;
paying it connects the agent to the payer as well.
See also: Developer quickstart, API reference,
Python client β client/examples/08_hybrid_flow.py runs the three
flows with the key kept in a note file.