Skip to main content
Perpetuals let you take a leveraged position on a market’s price without an expiry. On Murmo they live as proposals inside a group: a proposal is a single LONG or SHORT idea on a Phoenix RISE perp market, and each member who joins runs their own position under it. You put up USD collateral, pick a leverage multiplier, and the position tracks the market with live mark price, unrealized PnL, and funding.
Perpetuals are restricted in some jurisdictions and may require identity verification done in the app. If a call returns 403, check your account eligibility before retrying — see Eligibility & geo restrictions.
Leverage cuts both ways. At 5×, a −20% move in the underlying wipes out your collateral and the position can be liquidated — you lose what you put in. Size positions you can afford to lose and watch liquidationPriceUsd.
Set up your environment before starting:
export MURMO_API_KEY="murmo_your_key_here"
export MURMO_BASE="https://api.alpha-labs.trade"
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.
IDWhat it isWhere it comes from
proposalIdThe shared trade idea (the LONG/SHORT on a market).The id field of a PerpProposal.
assignmentIdYour position under a proposal.The id field of a PerpPosition — it is the assignment ID.
RouteKeyed byAction
POST /perps/proposals— (creates one)Open a new proposal and your first position.
POST /perps/proposals/{id}/increaseproposalIdJoin an existing proposal (inherits its side).
POST /perps/proposals/{id}/closeproposalIdCreator closes the proposal.
POST /perps/positions/{assignmentId}/reduceassignmentIdReduce or fully close your position.
POST /perps/positions/{assignmentId}/claimassignmentIdAcknowledge a take-profit close and drain proceeds.

Lifecycle

1

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.
2

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.
3

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.
4

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.
5

Claim a take-profit close

If a takeProfitPct bracket fired, the position closes automatically and becomes claimable. POST /api/v1/perps/positions/{assignmentId}/claim acknowledges it and drains the proceeds to your wallet.

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).
curl "$MURMO_BASE/api/v1/perps/markets/BTC" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Response
{
  "data": {
    "symbol": "BTC",
    "assetId": 1,
    "baseAsset": "BTC",
    "name": "Bitcoin",
    "marketStatus": "ACTIVE",
    "markPriceUsd": "68250.5",
    "midPriceUsd": "68249.0",
    "oraclePriceUsd": "68251.2",
    "fundingRatePercentage": "0.0042",
    "volume24hUsd": "91234567.8",
    "priceChange24hPct": "1.85",
    "prevDayPriceUsd": "67010.0",
    "tickSize": 1,
    "baseLotsDecimals": 5,
    "takerFeeBps": "4",
    "makerFeeBps": "2",
    "isolatedOnly": true
  }
}
PerpAsset selected fields:
FieldTypeNotes
symbolstringMarket symbol, e.g. BTC. Use this as marketSymbol when opening.
marketStatusstringWhether the market is tradable.
markPriceUsdMoneyString | nullMark price (USD) — the position’s reference price.
midPriceUsd / oraclePriceUsdMoneyString | nullMid and oracle prices (USD).
fundingRatePercentageDecimalString | nullFunding rate per interval as a percent.
volume24hUsdMoneyString | null24h notional volume (USD).
priceChange24hPctDecimalString | null24h price change as a percent.
takerFeeBps / makerFeeBpsDecimalStringFees in basis points.
tickSize, baseLotsDecimals, assetIdintegerStructural integers.
The market_tick WebSocket stream sends prices as numbers (not decimal strings) for speed. For exact money math — entry sizing, accounting — read prices from GET /perps/markets.

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.
groupId
string
required
The group to open the idea in. You must be a member.
marketSymbol
string
required
A symbol from GET /perps/markets, e.g. "BTC".
side
string
required
Direction: exactly "LONG" or "SHORT". Anything else is rejected with 400.
collateralUsd
string
required
USD you put up as a decimal string, e.g. "25.00".
leverage
string
required
Multiplier as a numeric string, e.g. "5".
reason
string
Your thesis, shown to the group (optional).
stopLossPct
string
Stop-loss as % collateral ROI (optional). See note below.
takeProfitPct
string
Take-profit as % collateral ROI (optional). See note below.
side must be exactly "LONG" or "SHORT". The API never silently coerces a bad value — anything else is rejected with 400, which would otherwise open a reversed position.
curl -X POST "$MURMO_BASE/api/v1/perps/proposals" \
  -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
    "marketSymbol": "BTC",
    "side": "LONG",
    "collateralUsd": "25.00",
    "leverage": "5",
    "reason": "Bullish into the halving",
    "takeProfitPct": "100"
  }'
Response
{
  "data": {
    "assignmentId": "f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55",
    "proposalId": "b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30",
    "subaccountIndex": 0,
    "txSignature": "5Jx...solana_sig",
    "marketSymbol": "BTC",
    "side": "LONG",
    "closePnlUsd": null,
    "closePnlPct": null,
    "closeProceedsUsd": null,
    "closedBaseUnits": null,
    "isFullClose": null
  }
}
This is a PerpPositionResult. On an open (or increase) the close-side fields are null — they populate only when a reduce fully closes the position.
FieldTypeNotes
assignmentIdstringYour position’s ID — pass to /reduce and /claim.
proposalIdstringThe proposal this position belongs to.
subaccountIndexintegerThe Phoenix subaccount holding this position.
txSignaturestringSolana signature of the opening transaction.
marketSymbolstringMarket traded.
side"LONG" | "SHORT"Direction.
closePnlUsdMoneyString | nullRealized PnL — only on a full close.
closePnlPctDecimalString | nullRealized PnL % — only on a full close.
closeProceedsUsdMoneyString | nullUSD returned to the wallet — only on a full close.
closedBaseUnitsstring | nullBase-unit quantity closed (a quantity, not money).
isFullCloseboolean | nullWhether 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.
curl -X POST "$MURMO_BASE/api/v1/perps/proposals/b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30/increase" \
  -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
  -d '{ "collateralUsd": "25.00", "leverage": "5" }'
The response is a PerpPositionResult with your new assignmentId — same shape as opening above.
{id} here is the proposalId. A position’s assignmentId is for /reduce and /claim only, not for joining.

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.
curl "$MURMO_BASE/api/v1/perps/positions?filter=active" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Response
{
  "data": [
    {
      "id": "f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55",
      "proposalId": "b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30",
      "marketSymbol": "BTC",
      "side": "LONG",
      "status": "OPEN",
      "initialCollateralUsdc": "25.00",
      "initialLeverage": "5",
      "positionValueUsd": "126.10",
      "entryPriceUsd": "68110.0",
      "liquidationPriceUsd": "55230.4",
      "takeProfitPriceUsd": "81732.0",
      "stopLossPriceUsd": null,
      "unrealizedPnlUsd": "1.10",
      "unsettledFundingUsd": "-0.02",
      "accumulatedFundingUsd": "-0.05",
      "isClaimable": false
    }
  ]
}
PerpPosition selected fields:
FieldTypeNotes
idstring= assignmentId — pass to /reduce and /claim.
proposalIdstringProposal this position belongs to.
marketSymbol / sidestring / enumMarket and direction.
statusstringOPEN, CLOSED, LIQUIDATED, or ADL_CLOSED.
initialCollateralUsdcMoneyStringCollateral you put up.
initialLeverageDecimalStringLeverage at open.
currentSizeBaseLotsstring | nullCurrent size in base lots (a quantity, not money).
positionValueUsdMoneyString | nullLive notional value (USD).
entryPriceUsd / exitPriceUsdMoneyString | nullEntry and (on close) exit price.
liquidationPriceUsdMoneyString | nullPrice at which the position is liquidated.
stopLossPriceUsd / takeProfitPriceUsdMoneyString | nullBracket trigger prices.
unrealizedPnlUsdMoneyString | nullLive PnL on an open position.
unsettledFundingUsd / accumulatedFundingUsdMoneyString | nullPending / total funding.
isClaimablebooleantrue after a take-profit close, until you /claim.
currentSizeBaseLots / currentSizeBaseUnits are quantities, not USD. Everything ending in ...Usd (prices, PnL, percent) is a human decimal string.

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).
reduceFraction
string
required
Fraction of current size to close, in (0, 1], e.g. "0.5" for half or "1" for all.
isFullClose
boolean
required
Set true when this action fully closes the position.
# Trim 50%
curl -X POST "$MURMO_BASE/api/v1/perps/positions/f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55/reduce" \
  -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
  -d '{ "reduceFraction": "0.5", "isFullClose": false }'
Response (full close)
{
  "data": {
    "assignmentId": "f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55",
    "proposalId": "b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30",
    "txSignature": "3Kp...solana_sig",
    "marketSymbol": "BTC",
    "side": "LONG",
    "closePnlUsd": "4.20",
    "closePnlPct": "16.8",
    "closeProceedsUsd": "29.20",
    "closedBaseUnits": "18420",
    "isFullClose": true
  }
}
reduceFraction must be in (0, 1] — a value greater than 1, equal to 0, or non-numeric is rejected with 400, as is a missing isFullClose. To close everything, send reduceFraction: "1" with isFullClose: true.

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.
curl -X POST "$MURMO_BASE/api/v1/perps/proposals/b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30/close" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Response
{ "data": { "success": true } }
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 a takeProfitPct 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.
curl -X POST "$MURMO_BASE/api/v1/perps/positions/f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55/claim" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Response
{
  "data": {
    "assignmentId": "f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55",
    "proposalId": "b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30",
    "marketSymbol": "BTC",
    "side": "LONG",
    "closePnlUsd": "25.00",
    "closePnlPct": "100.0",
    "closeProceedsUsd": "50.00",
    "closedBaseUnits": "18420",
    "claimedAt": "2026-06-03T01:12:00.000Z"
  }
}
PerpClaimResult fields:
FieldTypeNotes
assignmentIdstringThe claimed position.
proposalIdstringIts proposal.
marketSymbol / sidestring / enumMarket and direction.
closePnlUsdMoneyStringRealized PnL (USD).
closePnlPctDecimalStringRealized PnL as a percent.
closeProceedsUsdMoneyStringUSD drained to your wallet.
closedBaseUnitsstringBase-unit quantity closed (a quantity, not money).
claimedAtdate-timeWhen the claim settled.
Claim is only for take-profit-triggered closes. Positions you close yourself via /reduce return proceeds directly in that call — there’s nothing to claim afterward.

See proposals in a group

A proposal is a shared LONG/SHORT idea. Reads are members only — you’ll get 403 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).
curl "$MURMO_BASE/api/v1/perps/proposals?groupId=1a9d212a-de67-45f4-88f5-6e9f41e78dc0" \
  -H "Authorization: Bearer $MURMO_API_KEY"
PerpProposal selected fields:
FieldTypeNotes
idstringThe proposalId — pass to /increase and /close.
groupIdstringOwning group.
marketSymbolstringThe market this idea is on.
side"LONG" | "SHORT"Direction. Joiners inherit it.
reasonstringThe creator’s thesis.
creatorLeverageDecimalString | nullThe creator’s leverage.
stopLossPct / takeProfitPctDecimalString | nullThe creator’s bracket settings (% collateral ROI).
currentPnlPctDecimalString | nullLive PnL on the idea as a percent.
closedAtdate-time | nullSet when the creator closes the proposal.
exitPnlUsd / exitPnlPctMoneyString / DecimalString | nullRealized PnL after close.
participantCount / totalParticipantCountintegerHow many members are in.

Errors you’ll hit

Status / codeCauseFix
400Bad side, non-positive collateralUsd/leverage, reduceFraction out of (0, 1], missing isFullClose, groupId, or marketSymbol.Fix the request body.
401Missing or invalid key.Send Authorization: Bearer murmo_....
403 NOT_GROUP_MEMBERReading or joining a proposal in a group you’re not in.Join the group first.
403Closing a proposal you didn’t create, or a geo/eligibility block.Use /reduce for your own position; see geo restrictions.
See Errors for the full status-code and 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.