GET /me), the money side of your wallet (GET /account/*), and a single cross-vertical roll-up of positions and trades across every group (GET /positions, GET /trades). Everything here is a read — the only “write” in the funding story is depositing USDC to an address you read from GET /account.
Every monetary value on the wire is a full-precision plain decimal string in USD (
"12.50",
never a number, never raw base units, never scientific notation). Parse with a decimal library;
round only for display. See Money & precision.Identity — GET /me
The bootstrap call. It echoes the user behind the credential, key metadata (never the secret), and your rate budget. Nothing financial lives here — for balances and the deposit address use GET /account.
Response
| Field | Type | Notes |
|---|---|---|
userId | string | The user ID behind the credential. |
authMethod | "apiKey" | "jwt" | null | How this request authenticated. |
apiKey | object | null | Present for API-key auth; metadata only, never the secret. |
apiKey.id | string | Key ID (not the key itself). |
apiKey.label | string | null | Human label set in the app. |
apiKey.prefix | string | First chars of the key (e.g. murmo_froc) — enough to identify it in logs. |
apiKey.lastUsedAt | date-time | null | Last time this key was used. |
apiKey.expiresAt | date-time | null | Expiry, or null if non-expiring. |
rateLimit | object | null | { limit, windowSeconds } — currently 1,200 requests / 60 s for API keys. |
Account summary and the deposit address
GET /api/v1/account gives you both your wallet’s headline value and the address to fund it.
Response
| Field | Type | Notes |
|---|---|---|
totalValueUsd | money string | Total wallet value in USD. |
cashBalanceUsd | money string | USDC cash balance in USD. |
deposit.walletAddress | string | Send USDC here on Solana to fund the account. |
deposit.token | string | Always "USDC". |
deposit.tokenMint | string | The USDC mint to send — don’t send other tokens. |
deposit.chain | string | Always "solana". |
Fund and check your account
Read the deposit address
GET /api/v1/account and read data.deposit.walletAddress. Check tokenMint to confirm
you’re sending the right token — USDC.Send USDC on Solana
Transfer USDC to that address on Solana. This is an on-chain transfer you make from your
own wallet or exchange — it is not an API call. There is no API path that pulls funds for you.
Poll until the balance lands
Re-
GET /api/v1/account (or /account/balances) until cashBalanceUsd reflects the deposit.
Settlement follows Solana confirmation, so allow a few seconds.Balances — GET /account/balances
Cash and token balances held in the main wallet. Each row is a WalletBalance; the response wraps them in a balances array.
Response
WalletBalance fields:
| Field | Type | Notes |
|---|---|---|
tokenAddress | string | The token’s mint address. |
tokenSymbol | string | Symbol, e.g. USDC. |
tokenName | string | Display name. |
balance | decimal string | Token quantity (already humanized, not base units). |
value | money string | USD value of the holding. No Usd suffix — upstream name. |
price | money string | USD price per token. No Usd suffix. |
chainId | string | Chain, e.g. solana. |
decimals | integer | Token decimals — a plain JSON number, not a string. |
currency | string | Quote currency, e.g. usd. |
lastUpdated | date-time | When the balance/valuation was last refreshed. |
Spot holdings — GET /account/positions
Token holdings (spot positions) in the main wallet — the same WalletBalance shape as /balances, plus a nextCursor for pagination.
Response
nextCursor is null when there are no more pages. When it is a string, pass it back to fetch the next page.
Portfolio value and 24h change — GET /account/portfolio
Aggregate portfolio value plus 24-hour change, with the underlying positions inline.
Response
| Field | Type | Notes |
|---|---|---|
walletAddress | string | The main wallet. |
totalValue | money string | Total value (USD). No Usd suffix — upstream name. |
absoluteChange24h | money string | Absolute 24h change in USD. No Usd suffix. |
percentChange24h | decimal string | 24h change as a percent, e.g. "6.25" = 6.25%. |
positions | WalletBalance[] | The holdings behind the total (same shape as /balances). |
lastUpdated | date-time | When the valuation was last refreshed. |
PnL — GET /account/pnl
Just the 24h change numbers, when you don’t need the full portfolio body.
Response
Cross-vertical positions and trades
Three endpoints give you everything you hold and everything you’ve traded across all groups in one call, without iterating group by group.Open positions — GET /positions
Open positions across perps, spot, and predictions in every group.
Response
perps[]→PerpPosition(theidis theassignmentId; reduce/claim via the perps endpoints). All...Usdfields and PnL are decimal strings; base-lot quantities are quantity strings.spot[]→SpotProposalWithPosition({ proposal, userPosition, participantCount, participantAvatars }). NoteuserPosition.currentTokenAmountRawis a base-unit quantity — humanize with the token’sdecimals.predictions[]→PredictionWithPosition({ proposal, market, userPosition, remainingTokenAmount, createdBy }).tokenAmount/remainingTokenAmountare already humanized.
Past positions — GET /positions/past
Identical { perps, spot, predictions } shape, but for closed/resolved positions across all three verticals.
Trade history — GET /trades
Executed trade history for spot + predictions. Perp fills are not here — surface those via GET /api/v1/perps/positions.
Response
limit is optional (default 50, max 200; out-of-range values are clamped). tokenAmount is an already-humanized decimal-string quantity; every ...Usd / pnl* field is a USD or percent decimal string (pnl* is null on opening buys).
data envelope cheat-sheet
Every response is wrapped in a top-level { "data": ... }, but the shape inside data varies. Here’s every endpoint on this page:
| Endpoint | data shape | How to read it |
|---|---|---|
GET /me | object (Me) | data.userId, data.apiKey, data.rateLimit |
GET /account | object (AccountSummary) | data.totalValueUsd, data.deposit.walletAddress |
GET /account/balances | named key → array | data.balances is WalletBalance[] |
GET /account/positions | named key → array + cursor | data.positions is WalletBalance[]; data.nextCursor |
GET /account/portfolio | object (Portfolio) | data.totalValue, data.positions[] |
GET /account/pnl | object | data.absoluteChange24h, data.percentChange24h |
GET /positions | object keyed by vertical | data.perps[], data.spot[], data.predictions[] |
GET /positions/past | object keyed by vertical | data.perps[], data.spot[], data.predictions[] |
GET /trades | object keyed by vertical | data.spot[], data.predictions[] |
Errors
All four standard error statuses apply.401 means a missing or invalid Authorization header or key; 404 on GET /account means the wallet couldn’t be resolved for the credential. Error bodies come in two shapes — coded business errors { message, code } and generic framework errors { statusCode, message, error }. See Errors.
Where to next
Money & precision
Why every value is a decimal string, and how to parse it.
Authentication
The Bearer header, what a key can and can’t do, and rate limits.
Groups & proposals
Why positions live as proposals inside groups — the model behind the arrays.
API Reference
Full schemas for
Me, AccountSummary, WalletBalance, Portfolio, and cross-vertical positions.