Your account and every sub-account in it
Start here — every other path needs a subAccountId from this response.
Programmatic read access to a MoonUp account, plus the ability to withdraw USDC to an external wallet.
Everything the app shows you about your account is available here: balances, token holdings, structured trades and their performance, and the activity feed. Writes are limited to withdrawals.
https://api.moonup.io/v1
Every request carries an API key as a bearer token:
Authorization: Bearer mu_live_7Kd2...
Keys are created in Settings → API keys, shown once, and can be revoked at any time. Each key carries a set of scopes; a key issued without write:withdraw cannot move funds, which is the recommended default for anything that only needs to read.
Basket endpoints need no key — they return the same catalogue for everyone.
Tokens and basket constituents are identified by their CAIP-19 id, which encodes the chain and the token address. symbol and ticker are display labels: they are neither unique nor stable, so never use them as a key.
USD and USDC amounts are JSON numbers in display units — 118.42 means 118.42 USDC, never base units. Token quantities are lots, also in display units, and may be fractional.
An account can hold several sub-accounts, and every account-scoped path is addressed by subAccountId. A sub-account is either live, settling on Solana, or paper (isPaper: true), which simulates execution against a play balance. Both expose the identical shape; only isPaper and the source of the cash differ. Withdrawals are rejected on paper sub-accounts.
Errors return the matching HTTP status and a JSON body with a stable machine-readable code. Read code, not message — messages may be reworded.
Rate limits apply per key. A throttled request returns 429 with code rate_limited and a Retry-After header.
| Server | Environment |
|---|---|
| https://api.moonup.io/v1 | Production |
| http://localhost:8911/v1 | Local mock server |
An API key created in Settings → API keys, sent as a bearer token.
Scopes:
| Scope | Grants |
|---|---|
read:account | /me, balances, token holdings |
read:trades | Structured trades, NAV, lots |
read:activity | The activity feed |
write:withdraw | POST /withdrawals |
A key without write:withdraw is rejected on the withdrawal path with 403 insufficient_scope.
Who you are and which accounts you hold.
Start here — every other path needs a subAccountId from this response.
Balances and holdings for one sub-account.
| Parameter | In | Type | Description |
|---|---|---|---|
| subAccountIdrequired | path | string (uuid) | From GET /me. |
Everything the sub-account holds, both loose in the wallet and working inside trades.
| Parameter | In | Type | Description |
|---|---|---|---|
| subAccountIdrequired | path | string (uuid) | From GET /me. |
| heldVia | query | WALLET | TRADE | Return only wallet-held or only trade-held tokens. |
Structured trades and their performance.
| Parameter | In | Type | Description |
|---|---|---|---|
| subAccountIdrequired | path | string (uuid) | From GET /me. |
| status | query | ACTIVE | PAUSED | CLOSED | UNWOUND | |
| includeCash | query | boolean | Also return the cash ledger, which records deposits and withdrawals. default false |
| Parameter | In | Type | Description |
|---|---|---|---|
| tradeIdrequired | path | string (uuid) |
Value, protection floor and accumulated gain at each point in the period.
| Parameter | In | Type | Description |
|---|---|---|---|
| tradeIdrequired | path | string (uuid) | |
| period | query | 1D | 1W | 1M | ALL | default 1M |
The account's activity feed.
Newest first, cursor-paginated. The same feed the app shows.
| Parameter | In | Type | Description |
|---|---|---|---|
| subAccountIdrequired | path | string (uuid) | From GET /me. |
| cursor | query | string | Opaque cursor from a previous response's nextCursor. |
| limit | query | integer | default 50 |
| since | query | string (date-time) | Only return activity at or after this time. |
The catalogue of baskets available to trade. No key required.
Catalogue data, the same for everyone. No API key required.
| Parameter | In | Type | Description |
|---|---|---|---|
| type | query | Equity | Yield |
| Status | Description | Body |
|---|---|---|
| 200 | OK | object |
| Parameter | In | Type | Description |
|---|---|---|---|
| basketIdrequired | path | string |
Moving USDC out to an external wallet.
Sends available USDC from a live sub-account to an external Solana address. Requires the write:withdraw scope.
You name a destination, never a source — funds always come from the wallet belonging to the key's own account.
The amount is checked against availableUsd: cash committed to a trade change that has not finished settling cannot be withdrawn.
Idempotency-Key is required. Repeating a request with the same key within 24 hours returns the original result instead of sending twice — retry safely on a timeout.
Returns as soon as the transfer is submitted to the network. Poll GET /withdrawals/{withdrawalId} for confirmation.
| Parameter | In | Type | Description |
|---|---|---|---|
| Idempotency-Keyrequired | header | string | A unique string you choose per withdrawal. Reuse it when retrying. |
{
"subAccountId": "6b0c1d2e-3f40-4a5b-8c6d-7e8f90a1b2c3",
"destinationAddress": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"amountUsd": 250
}{
"subAccountId": "6b0c1d2e-3f40-4a5b-8c6d-7e8f90a1b2c3",
"destinationAddress": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"max": true
}| Status | Description | Body |
|---|---|---|
| 202 | Submitted to the network. | Withdrawal |
| 400 | The request cannot be carried out. | Error |
| 401 | The API key is missing, malformed, revoked, or expired. | Error |
| 403 | The key is valid but lacks the scope this operation needs. | Error |
| 429 | Too many requests for this key. | Error |
| Parameter | In | Type | Description |
|---|---|---|---|
| withdrawalIdrequired | path | string (uuid) |
| Status | Description | Body |
|---|---|---|
| 200 | OK | Withdrawal |
| 401 | The API key is missing, malformed, revoked, or expired. | Error |
| 404 | No such resource on this account. | Error |
| 429 | Too many requests for this key. | Error |
| Field | Type | Description |
|---|---|---|
| errorrequired | object |
| Field | Type | Description |
|---|---|---|
| id | string | |
| string (email) | ||
| handle | string | null | |
| signupDate | string (date-time) |
The wallet that settles a live account's trades and holds its USDC.
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | |
| publicAddress | string | |
| chain | string | CAIP-2 chain id. |
| createdDate | string (date-time) | |
| lastTransactionDate | string (date-time) |
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | |
| label | string | |
| isPaper | boolean | true = simulated against a play balance; false = settles on-chain. |
| created | string (date-time) |
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | |
| label | string | null | |
| wallet | Wallet | null | Null on paper accounts, which hold no wallet. |
| subAccounts | SubAccount[] |
What one sub-account is worth right now, broken down by how the money is being used. totalUsd = availableUsd + allocatedUsd, and allocatedUsd = protectedUsd + atRiskUsd.
| Field | Type | Description |
|---|---|---|
| subAccountId | string (uuid) | |
| isPaper | boolean | |
| currency | "USDC" | |
| totalUsd | number | |
| availableUsd | number | Settled cash not committed to any trade. This is the most you can withdraw. |
| committedUsd | number | Cash reserved by a trade change that has not finished settling. |
| allocatedUsd | number | Cash working inside active trades. |
| protectedUsd | number | The part of allocated capital covered by the trades' protection floors. |
| atRiskUsd | number | The part of allocated capital exposed to market moves. |
| pnl | map<string, object> | Gain or loss by period, keyed 1D, 1W, 1M, ALL. |
| asOf | string (date-time) |
One holding. Identified by caip19 alone.
| Field | Type | Description |
|---|---|---|
| caip19 | string | |
| symbol | string | Display only. Not unique |
| ticker | string | null | Display only. The underlying equity ticker, where one exists. |
| name | string | null | |
| imageUrl | string | null | |
| lots | number | Quantity in display units. May be fractional. |
| priceUsd | number | null | |
| valueUsd | number | null | |
| assetClass | CASH | EQUITY | YIELD | |
| heldVia | WALLET | TRADE | WALLET = sitting loose in the wallet. TRADE = working inside a structured trade. |
| tradeId | string (uuid) | null | Set when heldVia is TRADE. |
One change to a trade, in the order it happened.
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | |
| eventType | CREATED | REBALANCED | CUSHION_ADJUSTED | UPSIZED | DOWNSIZED | PAUSED | CLOSED | DEPOSIT | WITHDRAWAL | |
| triggerSource | USER | AUTOMATED | Whether you asked for this change or the strategy made it on its own. |
| status | PENDING | EXECUTED | ABORTED | PARTIAL | EXECUTED = fully settled. PENDING = still settling. ABORTED = nothing moved, the trade is unchanged. PARTIAL = the change went through incompletely and is being resolved. |
| capitalChangedUsd | number | null | Positive when money went in, negative when it came out. Null when the event moved no money. |
| scheduledFor | string (date-time) | null | When a deferred change is expected to run, e.g. one waiting on market hours. |
| executedAt | string (date-time) |
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | |
| subAccountId | string (uuid) | |
| tradeType | CPPI | USDC_CASH | CPPI = a protected basket position. USDC_CASH = the cash ledger, which records deposits and withdrawals rather than a market position. |
| status | ACTIVE | PAUSED | CLOSED | UNWOUND | |
| basketId | string | null | Null on the cash ledger. |
| basketName | string | null | |
| floorPct | number | null | The protection floor, as a fraction of the trade's value. |
| multiplier | number | How aggressively the strategy uses the cushion above the floor. |
| notionalUsd | number | |
| protectedUsd | number | |
| nav | NavPoint | |
| createdAt | string (date-time) | |
| closedAt | string (date-time) | null | |
| events | TradeEvent[] | Returned by GET /trades/{tradeId} only. |
| Field | Type | Description |
|---|---|---|
| timestampMs | number | |
| nav | number | The trade's total value at this moment. |
| equityNav | number | The part held in the equity basket. |
| yieldNav | number | The part held in the yield sleeve. |
| accPnlUsd | number | Gain or loss since the trade opened. |
| floorUsd | number | The protected value at this moment. |
| notionalUsd | number | Capital put in |
One row of the activity feed — the same feed the app shows. It lists the moments that matter: opening a trade, adding to it, reducing it, changing its protection, and withdrawing cash. Routine automated rebalances are left out; read GET /trades/{tradeId} for the full event history of a trade.
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | |
| tradeId | string (uuid) | |
| kind | trade | deposit | withdrawal | |
| eventType | CREATED | UPSIZED | DOWNSIZED | CUSHION_ADJUSTED | WITHDRAWAL | |
| title | string | |
| subtitle | string | |
| amountUsd | number | null | |
| amountVariant | cash | cashChg | cash = an absolute amount, cashChg = a signed change. |
| basketImageUrl | string | null | |
| executedAt | string (date-time) |
| Field | Type | Description |
|---|---|---|
| caip19 | string | |
| symbol | string | |
| ticker | string | |
| weightPct | number | |
| lots | number | |
| priceUsd | number |
| Field | Type | Description |
|---|---|---|
| basketId | string | |
| displayName | string | |
| description | string | null | |
| ticker | string | null | |
| image | string | null | |
| type | Equity | Yield | Equity baskets carry market exposure; yield baskets are the safe sleeve. |
| category | string | null | |
| volatility | string | null | |
| tokenCount | integer | null | |
| lastUpdated | string | null | |
| strategyOverview | string | null | |
| sectorAllocation | object[] | |
| weights | BasketWeight[] | Returned by GET /baskets/{basketId} only. |
| Field | Type | Description |
|---|---|---|
| subAccountIdrequired | string (uuid) | |
| destinationAddressrequired | string | The external Solana address to send to. Check it carefully — transfers cannot be reversed. |
| amountUsd | number | In USDC. Required unless max is true. |
| max | boolean | Send the entire available balance, sized so no dust is left behind. Also the only way to withdraw an amount below the minimum. |
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | |
| signature | string | The Solana transaction signature. |
| status | SUBMITTED | CONFIRMED | FAILED | |
| amountUsd | number | |
| destinationAddress | string | |
| submittedAt | string (date-time) |