Trader vs operator credentials
Two very different integrations use this API, and they need different credentials:
- a trader — a person or bot acting on their own account: placing orders, reading their positions, streaming their fills;
- an operator (partner / tenant) — a business acting on its tenant: creating traders, prop firms, challenge templates, risk profiles and trading groups, approving payouts.
A credential is minted for exactly one of these. The audience is fixed at mint and never changes, and one credential can never be both.
What each can do
Section titled “What each can do”| Trader credential | Operator credential | |
|---|---|---|
| Acts on | Its own account | Your tenant |
| Minted from | Paper account: the workspace operator, in the admin console — Account → API keys. Live account: the account, in the browser — Settings → API Clients | The admin console — API Clients |
| Carries | A tier (readonly / liquidation / fullTrading), a risk envelope, venue + symbol allowlists, and an agent wallet |
Scopes: prop:manage, firm:operate, tenant:config |
| Can place orders | Yes | Never on a real venue — paper only |
| Can administer a tenant | No — scopes are rejected at mint | Yes, and only its own tenant |
Why an operator can’t trade
Section titled “Why an operator can’t trade”Not a missing feature, and not something to work around. Authority over an account comes from that account, never from a credential: a trader credential can place orders because the account’s own wallet signed an agent authorization for it, in the browser, where the wallet is. An operator has no access to that wallet and cannot forge that signature — the constraint is cryptographic.
So an operator credential holds no agent wallet by design. Sending one to
POST /api/v1/oms/intents for hyperliquid, aster, polymarket or kalshi
returns 403 wrong_credential_audience.
venue: "paper" is the exception, and it follows from the same rule rather
than bending it: a paper fill signs nothing and moves no funds, so there is no
custody to authorize and no agent wallet to be missing. That is what lets an
operator drive the account it provisioned with
POST /api/v1/sandbox/paper-account and
validate an integration end to end without minting a second credential. The
moment the venue is real, the gate above applies.
In the SDK
Section titled “In the SDK”Use the client that matches your credential. Calling the other surface then fails at compile time instead of at runtime.
import { TronChartsTrader, TronChartsOperator } from '@tronchartsxyz/api-client'
// Acting on your own accountconst trader = new TronChartsTrader({ baseUrl, token: traderToken, tenantSlug })await trader.oms.place({ /* … */ })await trader.accounts.state(accountId)
// Administering your tenantconst ops = new TronChartsOperator({ baseUrl, token: operatorToken, tenantSlug })const { user } = await ops.users.create({ externalId: 'crm-4471' })await ops.propTemplates.create({ /* … */ })| Client | Resources |
|---|---|
TronChartsTrader |
auth · oms · accounts · propAccounts · market · reports · venues · kyc · referrals · analytics · indicators · backtests · copyTrading |
TronChartsOperator |
auth · users · firms · propTemplates · propSetup · riskProfiles · tradingGroups · tenant · sandbox · propAccounts · reports · analytics |
TronCharts still exposes both surfaces on one object. It works, and it tells
you nothing about which half your token can reach — prefer the scoped clients.
When you get it wrong
Section titled “When you get it wrong”{ "error": "wrong_credential_audience", "detail": "this endpoint is for operator credentials, but this is a trader credential. …", "expected": "operator", "actual": "trader"}HTTP 403. The fix is never to change the credential you have — audiences are
immutable — but to mint the other one and keep both.
You may still meet the older, less direct errors underneath this gate:
| Error | What it actually means |
|---|---|
wrong_credential_audience |
Wrong kind of credential. Mint the other one. |
credential_missing_agent_wallet |
A trader credential minted without an agent wallet. Re-mint it from the account it should trade. |
tier_insufficient |
The credential’s tier is below what the route needs. readonly cannot open or close; liquidation can cancel and flatten but not open; fullTrading can do both. |
prop_manage_required / firm_operate_required / tenant_config_required |
Right audience, missing that specific scope. Scopes are granted per credential and are opt-in at mint, so a credential minted with every box unticked holds none. |
forbidden on reports |
Right credential, wrong account — see the scoping note above. |
Browser sessions
Section titled “Browser sessions”A cookie session (your own logged-in user in the FE) carries no credential and no audience, so this gate does not apply to it. Each route handles it on its own terms: the operator surface refuses it outright — tenant administration is an explicit, audited credential capability — while the trading surface accepts it as the trader it represents.
Next: Credentials & tokens · Scopes & tiers · How an account is configured