Every monetary value on the wire is a full-precision decimal string in USD.
collateralUsd
and leverage are sent as numeric strings ("25.00", "5") — never numbers, never raw base
units. See Money & precision.Two IDs: proposalId vs assignmentId
Get this straight before you start — these two IDs are not interchangeable, and mixing them up is the most common mistake when working with perps.
| ID | What it is | Where it comes from |
|---|---|---|
proposalId | The shared trade idea (the LONG/SHORT on a market). | The id field of a PerpProposal. |
assignmentId | Your position under a proposal. | The id field of a PerpPosition — it is the assignment ID. |
| Route | Keyed by | Action |
|---|---|---|
POST /perps/proposals | — (creates one) | Open a new proposal and your first position. |
POST /perps/proposals/{id}/increase | proposalId | Join an existing proposal (inherits its side). |
POST /perps/proposals/{id}/close | proposalId | Creator closes the proposal. |
POST /perps/positions/{assignmentId}/reduce | assignmentId | Reduce or fully close your position. |
POST /perps/positions/{assignmentId}/claim | assignmentId | Acknowledge a take-profit close and drain proceeds. |
Lifecycle
Pick a market
List the tradable perp markets and read a live price to size your entry.
Use
GET /api/v1/perps/markets or GET /api/v1/perps/markets/{symbol} for one market.Open a position
POST /api/v1/perps/proposals creates a proposal and opens your position in one call — pick
side, collateralUsd, leverage, and optional stopLossPct / takeProfitPct brackets.
To back an idea someone else posted, use POST /perps/proposals/{id}/increase instead.Monitor PnL
GET /api/v1/perps/positions?filter=active returns your open positions with live
markPrice-derived value, unrealizedPnlUsd, funding, and liquidationPriceUsd. For
low-latency price ticks, subscribe to market data over WebSocket.Reduce or close
POST /api/v1/perps/positions/{assignmentId}/reduce trims or fully closes your position
(send reduceFraction in (0, 1] and isFullClose). The proposal creator can close the
whole proposal with POST /perps/proposals/{id}/close.Browse markets
GET /api/v1/perps/markets returns every tradable perp market. GET /api/v1/perps/markets/{symbol} returns one market by symbol (data: null if the symbol is unknown).
Response
PerpAsset selected fields:
| Field | Type | Notes |
|---|---|---|
symbol | string | Market symbol, e.g. BTC. Use this as marketSymbol when opening. |
marketStatus | string | Whether the market is tradable. |
markPriceUsd | MoneyString | null | Mark price (USD) — the position’s reference price. |
midPriceUsd / oraclePriceUsd | MoneyString | null | Mid and oracle prices (USD). |
fundingRatePercentage | DecimalString | null | Funding rate per interval as a percent. |
volume24hUsd | MoneyString | null | 24h notional volume (USD). |
priceChange24hPct | DecimalString | null | 24h price change as a percent. |
takerFeeBps / makerFeeBps | DecimalString | Fees in basis points. |
tickSize, baseLotsDecimals, assetId | integer | Structural integers. |
Open a position (new proposal)
POST /api/v1/perps/proposals creates the proposal and opens your position atomically. The wallet is resolved server-side — never pass one yourself.
The group to open the idea in. You must be a member.
A
symbol from GET /perps/markets, e.g. "BTC".Direction: exactly
"LONG" or "SHORT". Anything else is rejected with 400.USD you put up as a decimal string, e.g.
"25.00".Multiplier as a numeric string, e.g.
"5".Your thesis, shown to the group (optional).
Stop-loss as % collateral ROI (optional). See note below.
Take-profit as % collateral ROI (optional). See note below.
Response
PerpPositionResult. On an open (or increase) the close-side fields are null — they populate only when a reduce fully closes the position.
| Field | Type | Notes |
|---|---|---|
assignmentId | string | Your position’s ID — pass to /reduce and /claim. |
proposalId | string | The proposal this position belongs to. |
subaccountIndex | integer | The Phoenix subaccount holding this position. |
txSignature | string | Solana signature of the opening transaction. |
marketSymbol | string | Market traded. |
side | "LONG" | "SHORT" | Direction. |
closePnlUsd | MoneyString | null | Realized PnL — only on a full close. |
closePnlPct | DecimalString | null | Realized PnL % — only on a full close. |
closeProceedsUsd | MoneyString | null | USD returned to the wallet — only on a full close. |
closedBaseUnits | string | null | Base-unit quantity closed (a quantity, not money). |
isFullClose | boolean | null | Whether the action fully closed the position. |
Stop-loss and take-profit brackets
stopLossPct and takeProfitPct are optional and expressed as % collateral ROI, not as a price move in the underlying.
takeProfitPct: "100" means “close when the position is up 100% of collateral” — i.e. you’d
roughly double your stake. stopLossPct: "50" means “close when down 50% of collateral.”
Because ROI is on collateral, these scale with leverage: at higher leverage a smaller price move
hits the same ROI bracket. The trigger prices come back on the position as stopLossPriceUsd
and takeProfitPriceUsd.Join a proposal (increase)
To back an idea that already exists,POST /api/v1/perps/proposals/{id}/increase opens a new position under that proposal. The side is inherited from the proposal — you only send your own collateralUsd and leverage. You must be a member of the proposal’s group.
PerpPositionResult with your new assignmentId — same shape as opening above.
Monitor your positions
GET /api/v1/perps/positions?filter=active returns your positions with live mark/PnL/funding fields. filter is active (default), past, or all.
Response
PerpPosition selected fields:
| Field | Type | Notes |
|---|---|---|
id | string | = assignmentId — pass to /reduce and /claim. |
proposalId | string | Proposal this position belongs to. |
marketSymbol / side | string / enum | Market and direction. |
status | string | OPEN, CLOSED, LIQUIDATED, or ADL_CLOSED. |
initialCollateralUsdc | MoneyString | Collateral you put up. |
initialLeverage | DecimalString | Leverage at open. |
currentSizeBaseLots | string | null | Current size in base lots (a quantity, not money). |
positionValueUsd | MoneyString | null | Live notional value (USD). |
entryPriceUsd / exitPriceUsd | MoneyString | null | Entry and (on close) exit price. |
liquidationPriceUsd | MoneyString | null | Price at which the position is liquidated. |
stopLossPriceUsd / takeProfitPriceUsd | MoneyString | null | Bracket trigger prices. |
unrealizedPnlUsd | MoneyString | null | Live PnL on an open position. |
unsettledFundingUsd / accumulatedFundingUsd | MoneyString | null | Pending / total funding. |
isClaimable | boolean | true after a take-profit close, until you /claim. |
Reduce or close your position
POST /api/v1/perps/positions/{assignmentId}/reduce trims or fully closes your position, keyed by assignmentId (the position’s id).
Fraction of current size to close, in
(0, 1], e.g. "0.5" for half or "1" for all.Set
true when this action fully closes the position.Response (full close)
Close the whole proposal (creator only)
POST /api/v1/perps/proposals/{id}/close closes the proposal, keyed by proposalId. Only the creator can do this — it closes the creator’s own open positions and locks out new joiners. Other members’ positions are left untouched; they manage their own exits via /reduce.
Response
If you’re not the creator, this returns
403. To exit a position you joined, use
/positions/{assignmentId}/reduce instead.Claim a take-profit close
When atakeProfitPct bracket fires, the position closes automatically and becomes claimable (isClaimable: true). POST /api/v1/perps/positions/{assignmentId}/claim acknowledges that close and drains the proceeds to your wallet.
Response
PerpClaimResult fields:
| Field | Type | Notes |
|---|---|---|
assignmentId | string | The claimed position. |
proposalId | string | Its proposal. |
marketSymbol / side | string / enum | Market and direction. |
closePnlUsd | MoneyString | Realized PnL (USD). |
closePnlPct | DecimalString | Realized PnL as a percent. |
closeProceedsUsd | MoneyString | USD drained to your wallet. |
closedBaseUnits | string | Base-unit quantity closed (a quantity, not money). |
claimedAt | date-time | When the claim settled. |
See proposals in a group
A proposal is a shared LONG/SHORT idea. Reads are members only — you’ll get403 NOT_GROUP_MEMBER for a group you don’t belong to.
GET /api/v1/perps/proposals?groupId=... lists a group’s perp proposals; GET /api/v1/perps/proposals/{id} returns one (data: null if not found).
PerpProposal selected fields:
| Field | Type | Notes |
|---|---|---|
id | string | The proposalId — pass to /increase and /close. |
groupId | string | Owning group. |
marketSymbol | string | The market this idea is on. |
side | "LONG" | "SHORT" | Direction. Joiners inherit it. |
reason | string | The creator’s thesis. |
creatorLeverage | DecimalString | null | The creator’s leverage. |
stopLossPct / takeProfitPct | DecimalString | null | The creator’s bracket settings (% collateral ROI). |
currentPnlPct | DecimalString | null | Live PnL on the idea as a percent. |
closedAt | date-time | null | Set when the creator closes the proposal. |
exitPnlUsd / exitPnlPct | MoneyString / DecimalString | null | Realized PnL after close. |
participantCount / totalParticipantCount | integer | How many members are in. |
Errors you’ll hit
| Status / code | Cause | Fix |
|---|---|---|
400 | Bad side, non-positive collateralUsd/leverage, reduceFraction out of (0, 1], missing isFullClose, groupId, or marketSymbol. | Fix the request body. |
401 | Missing or invalid key. | Send Authorization: Bearer murmo_.... |
403 NOT_GROUP_MEMBER | Reading or joining a proposal in a group you’re not in. | Join the group first. |
403 | Closing a proposal you didn’t create, or a geo/eligibility block. | Use /reduce for your own position; see geo restrictions. |
code reference.
Where to next
Money & precision
Why
collateralUsd is "25.00" and not 25.Groups & proposals
The social model: groups, proposals, positions.
Copy Trading
Auto-follow a group’s proposals at a fixed size.
API Reference
Every Perpetuals endpoint, field by field.