Integrator Fees and Payouts
With an integrator key you can charge your own fee on the trades your users make through you, then claim what you have earned. The fee is taken inside the trade, every settled trade records it, and you pay yourself out in USDC, on demand, to an address Treasures registers for you.
How it works
- Treasures configures your fee. Your key carries a default fee and a ceiling, both agreed with your Treasures contact.
- You quote with your key. Every quote you request with
X-API-Keycharges your default fee. Sendintegrator_fee_bpsto use a different fee on one quote. - The trade pays it. The fee is stacked into the same on-chain fee as Treasures' own, so the quoted output already allows for it. Nothing extra is signed.
- You submit with the same key. A quote that carries your fee can only be submitted with the key that requested it.
- Settled trades record it. Each trade's fee appears in
GET /settlementsas anintegrator_feeentry. - You claim it.
POST /payoutssends everything you are owed to your registered address.
Setting your fee
integrator_fee_bps is accepted on POST /quote/buy, POST /quote/sell and POST /quote/preview. It is your fee on that quote in net basis points (0 to 10000), up to your ceiling.
- Omit it to charge your configured default. Send
0to charge nothing on that quote. - It needs your key. A non-zero value without
X-API-Keyis refused. - It is net. On Solana the execution venue keeps half of the fee it collects, so the trader is charged twice your figure there and you net the figure you sent.
- The quote shows it. Every leg reports
cost_breakdown_bps.integrator_fee_bpsbesidetreasures_fee_bps, andestimated_output_*is already net of both. It reads0on an anonymous quote, and on a leg whose venue could not collect a fee. - Submit with the same key. A quote with a non-zero fee on any leg must be submitted to
POST /trade/submitwith the key that quoted it. Anything else is refused and nothing is broadcast. Zero-fee quotes have no such rule.
| Response | When | What to do |
|---|---|---|
400 invalid_integrator_fee | The fee is above your ceiling (max_bps says what it is), or a venue on the route cannot carry it; reason is then fee_above_maximum, fee_below_minimum or fee_unavailable | Lower the fee, send 0, or omit the field. Treat reason as an open set |
400 integrator_fee_requires_api_key | A non-zero integrator_fee_bps without X-API-Key | Send your tik_ key, or drop the field |
403 quote_integrator_mismatch | A fee-carrying quote submitted without the key that quoted it, or with a different key | Resubmit with the key that quoted it |
503 integrator_fee_misconfigured | Your configured fee no longer fits a venue Treasures routes through. A Treasures-side issue that retrying soon will not clear | Contact Treasures, or send integrator_fee_bps: 0 to quote without your fee |
What you have earned
Every settled trade that carried your fee has an integrator_fee entry in its fee_costs on GET /settlements:
{ "name": "integrator_fee", "percentage": "0.0020", "amount_usd": "0.500840", "included": true, "payout_id": null }
payout_id is null while the fee is still owed to you, and names the payout it went out in once one claims it. Two filters on the same route reconcile the two sides:
payout_status=unpaidlists exactly the fees no payout has claimed yet. They sum toamount_usdonGET /payouts/accrued.payout_id=ipo_…lists exactly the trades one payout covered. Theirintegrator_feeamounts sum to that payout'samount_usd.
payout_status=processing and payout_status=paid follow the status of the payout that claimed each fee. A read-only trk_ reporting key can use these filters, which makes /settlements the place to hand an accountant; the payout routes themselves need your general tik_ key.
Claiming a payout
Check what is owed
GET /payouts/accrued returns what you are owed right now and whether you can claim it:
| Field | Meaning |
|---|---|
amount_usd, trade_count | What you are owed now and how many trades it came from. Fees earned on every chain are pooled into one USD figure (USDC and USDG count 1:1) |
payout_chain, payout_address | Where payouts go: USDC on Solana (sol) or Base (base). null until Treasures registers an address for you |
previous_payout_address, payout_address_updated_at | The address the last change replaced and when, so an unexpected change is visible to you |
payouts_enabled | Whether POST /payouts is open |
minimum_usd, maximum_usd | The smallest and largest payout the route makes. Above the maximum, Treasures pays on request |
next_eligible_at | Unix seconds before which a claim is refused (a cooldown after your last payout, or a hold after an address change); null when nothing is waiting |
Only Treasures can set or change your payout address; ask your contact. There is no API to change it, by design.
Claim it
POST /payouts sends all of what you are owed to your registered address. You choose nothing: the body is empty (or {}), the amount is your accrued balance, and the destination is your registered address.
Idempotency-Keyis required, and a key is yours forever. Repeating one returns the payout it first created (200), whatever its status, includingfailed. To try again after a failure, send a new key.- One payout at a time, at least
minimum_usd, at mostmaximum_usd, one per cooldown window, and none for a while after your address changes. 202means the transfer was sent or is being sent. PollGET /payouts/{payoutId}until it is final.
Payout status | Meaning |
|---|---|
processing | Created or sent, not yet final. On Solana tx_hash is known as soon as the transfer is sent; on Base, once it lands |
paid | Final. tx_hash is the transfer and paid_at is set |
failed | The transfer did not happen. Its fees are owed to you again; claim with a new Idempotency-Key |
cancelled | Withdrawn before sending. Its fees went back into what you are owed |
GET /payouts lists every payout, newest first; page with cursor, reading next_cursor and has_more. To see the trades one payout covered, call GET /settlements?payout_id=….
When a claim is refused
| Response | Meaning | What to do |
|---|---|---|
409 payout_in_progress | Another payout is still in flight; payout_id names it | Wait for it to finish |
409 payout_cooldown, 409 address_hold | Too soon after your last payout, or after an address change | Retry after retry_after (Unix seconds; also a Retry-After header) |
409 payout_address_missing | No payout address is registered | Ask Treasures to register one |
409 nothing_to_pay | Nothing is owed right now | Nothing to do |
422 below_minimum | What you are owed is under minimum_usd | Wait until it grows |
422 requires_review | What you are owed is over maximum_usd | Ask Treasures, who pays balances this large on request |
503 payouts_unavailable | Payouts are paused or cannot be made right now | Retry later |
403 insufficient_scope | A trk_ reporting key on a payout route | Use your tik_ key |
404 payout_not_found | No such payout of yours. Another organisation's payout id answers the same way | Check the id |
Every field is in the API Reference.