Integrator API Keys
An integrator API key identifies your organisation to the Treasures API. It goes in the X-API-Key header. This page lists the two kinds of key, what each route does with one, exactly what the key-gated routes return, and the errors a key can produce.
A key and an ownership proof are independent credentials. The proof is per request and per wallet: it proves control of the wallet. The key is per organisation: it identifies the caller. A route can want neither, either or both.
Two kinds of key
| Prefix | Name | Reaches | Purpose |
|---|---|---|---|
tik_ | General key | Every route | API access. Use this for your integration |
trk_ | Reporting key | GET /settlements only | Read-only. Safe to hand to an accountant, an auditor or a reporting partner: everywhere else it answers 403 insufficient_scope |
Both kinds are issued per organisation by the Treasures team; see Getting a key. A credential for a different Treasures product (for example a twk_ wallet key) is not addressed to this API and is ignored, so such requests are served anonymously.
What a key does on each route
"Optional" means the route can be called without a key. It does not mean a key you send is ignored: every key is verified, and a bad one is rejected rather than quietly downgraded to an anonymous call.
| Route | Key | What changes when you send one |
|---|---|---|
GET /stocks/{ticker} | Required, tik_ only | The whole route. Company profile, listings, tradfi snapshot, extended hours, market session, analyst consensus and grades, next earnings, latest news |
POST /quote/preview | Required, tik_ only | The whole route. Prices a trade with no wallet and no ownership proof |
GET /settlements | Required, tik_ or trk_ | The whole route. Your organisation's settled trades |
GET /payouts/accrued, POST /payouts, GET /payouts, GET /payouts/{payoutId} | Required, tik_ only | The whole routes. What you are owed in integrator fees, claiming it, and your payout history |
POST /trade/submit | Optional, but send it; required for a quote that carries your fee | The trade is attributed to your organisation and appears in GET /settlements. A submit without the key is attributed to no one and cannot be recovered afterwards. A quote carrying your integrator fee must be submitted with the key that quoted it (403 quote_integrator_mismatch) |
GET /portfolio | Optional, but send it | Positions on Robinhood Chain and Base are read for any eth_wallet, not only wallets Treasures already knows. Rate limiting moves from your IP to your organisation bucket |
POST /quote/buy, POST /quote/sell | Optional | Your integrator fee is charged: your configured default, or the integrator_fee_bps you send, reported on each leg as cost_breakdown_bps.integrator_fee_bps. The key is verified and your organisation bucket applies. Company details are not part of a quote; they come from GET /stocks/{ticker} |
GET /stocks, GET /stocks/tickers, GET /stocks/prices, GET /quote/{quote_id}/status, POST /bridge/quote, GET /bridge/{bridge_quote_id}/status, GET /trades | Optional | The key is verified and your organisation bucket applies. Nothing else |
The portfolio row deserves a sentence more. Treasures reads positions on Robinhood Chain and Base only for wallets it has a reason to know about, which bounds address enumeration by anonymous callers. Your end users' wallets are not Treasures wallets, and a wallet that merely holds a token there (an airdrop, a transfer in) has no record anywhere until it trades. Without your key such a wallet comes back with an empty positions list and is not flagged partial. With your key, every wallet you ask about is read. Idle cash on those chains (usdc.base, usdg.robinhood) is never gated either way.
What the key-gated routes return
GET /stocks/{ticker}
Everything the catalog knows about one ticker, in one call and cached for 60 seconds:
- Profile:
name,description,sector,industry,website,logo_url,display_ticker,exchange,exchange_country,data_delay - Listings:
available_chainsand alistingsarray with one entry per (protocol, chain), each carrying its own availability and any tradability warning - Market data: the
tradfisnapshot, theextended_hours(pre- and post-market) print,market_session, andis_holiday/holiday_name - Research:
analystconsensus,analyst_grades, the nextearningsdate and the latestnews
Every block is best-effort and degrades to null on its own, so a missing analyst block never fails the call. The route deliberately carries no on-chain price block; for per-protocol on-chain prices keep using GET /stocks/prices. It takes no query parameters.
POST /quote/preview
The buy-quote shape with no wallet and no ownership proof. It prices every chain the ticker lists (or those your chain and protocol filters allow) and returns the same legs POST /quote/buy would, minus quote_id, expires_at, every leg's signable_payloads and warnings_ack_token. Nothing is persisted: there is no status to poll and nothing to submit. Re-quote through /quote/buy for anything you intend to sign.
Two things to know about its limits. amount_usdc is capped at 1,000,000 on this route. And on top of your per-IP and per-organisation budgets, the route has one ceiling shared by every caller, because a preview needs no wallet and is the cheapest request to make in bulk. A 429 here can be someone else's traffic: honour Retry-After and retry, and read X-RateLimit-* on this route as the shared bucket rather than your own. Identical requests inside a 10-second window are answered from one price lookup.
GET /settlements
Every trade submitted through POST /trade/submit with your key presented, newest first. Only settled fills appear: a trade is listed once it reaches completed, which on Ethereum and Robinhood Chain can be minutes after submission. Until then the amounts on record are quote-time expectations, so they are withheld rather than reported as fact.
Each row carries trade_id, status, side, ticker, protocol, chain, the addresses involved, timestamp, tx_hash, token_out_address, amount, amount_usd, shares, the sending and receiving legs and the fee_costs breakdown, which includes an integrator_fee entry on a trade that carried your fee. Filter with chain, protocol, ticker, side, token_out_address, settled_from, settled_to, and, to reconcile payouts, payout_id and payout_status; page with limit and cursor, reading next_cursor and has_more from each response. data may be shorter than limit while has_more is still true.
A sell quoted with payout_chain is the one row whose legs differ: sending is the sale on the row's chain, and receiving is the payout, its own transaction on the chain the USDC landed on. The row's chain and tx_hash stay the sale's. The chain filter therefore matches the stock's chain, not the payout's; to select sells by where their USDC landed, filter token_out_address on that chain's USDC.
If you reconcile exactly, re-scan roughly the last two hours on each pass rather than relying on the cursor alone. A small number of Solana trades are settled by a recovery job that records the on-chain block time, which is earlier than when the row appeared, so such a row lands behind a cursor you have already paged past. trade_id is stable, so re-scanned rows deduplicate cleanly. Trades that predate this endpoint are absent.
Rate limits with a key
Presenting a valid key adds a per-organisation bucket shared by all of your keys. It is a cross-IP aggregate bound, additive to the per-IP limits rather than a raised ceiling. On GET /portfolio the organisation bucket replaces the per-IP row entirely and is sized for one request every 5 seconds per active end user. See Enterprise Integration for the full picture.
Errors a key can produce
| Response | Meaning | What to do |
|---|---|---|
401 invalid_api_key | Missing, malformed or unknown key on a route that requires one, or a malformed key on any route | Check the header value. The message is deliberately generic |
403 key_revoked | The key was retired | Use a current key; contact Treasures if you have none |
403 integrator_suspended | Your organisation is suspended, so every one of your keys is affected | Contact Treasures |
403 insufficient_scope | A read-only trk_ reporting key on a non-reporting route | Use your tik_ key for API access |
A key is verified on every route it is sent to, including the optional ones. Sending a bad key to GET /stocks/prices fails the request; it is not silently treated as anonymous.