> ## Documentation Index
> Fetch the complete documentation index at: https://docs.murmo.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Perpetuals

> Open leveraged LONG/SHORT positions on Phoenix RISE perp markets, monitor live PnL, and reduce, close, or claim them.

Perpetuals let you take a **leveraged** position on a market's price without an expiry. On Murmo they live
as **proposals** inside a [group](/concepts/groups-and-proposals): 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 multiplier, and the position tracks the market with live mark price,
unrealized PnL, and funding.

<Warning>
  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`.
</Warning>

<Note>
  Perpetuals are restricted in some jurisdictions and may require identity verification. If a call
  returns `403`, see [Eligibility & geo restrictions](/concepts/geo-restrictions).
</Note>

## Two IDs: proposalId vs assignmentId

This is the one thing to get straight before you start. Perp routes are keyed by **one of two IDs**,
and they are not interchangeable.

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

<Info>
  **CREATE, JOIN, and CLOSE-proposal** are keyed by `proposalId`. **REDUCE and CLAIM** act on a single
  position and are keyed by `assignmentId`. A `PerpPosition.id` and its assignment id are the same
  value — use it wherever a route says `{assignmentId}`.
</Info>

| Route                                         | Keyed by        | Action                                              |
| --------------------------------------------- | --------------- | --------------------------------------------------- |
| `POST /perps/proposals`                       | — (creates one) | Open a new proposal + 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. |

## Setup

Same base URL, key, and money rules as everywhere else in the API.

```bash theme={null}
export MURMO_API_KEY="murmo_your_key_here"
export MURMO_BASE="https://api.alpha-labs.trade"
```

<Note>
  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.
  Base-lot quantities are strings too. See [Money & precision](/concepts/money-and-precision).
</Note>

## Lifecycle

<Steps>
  <Step title="Pick a market">
    List the tradable perp markets and read a live price to size your entry.
    `GET /api/v1/perps/markets` (or `/markets/{symbol}` for one).
  </Step>

  <Step title="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, `POST /perps/proposals/{id}/increase` instead.
  </Step>

  <Step title="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](/websockets/market-data).
  </Step>

  <Step title="Reduce or close">
    `POST /api/v1/perps/positions/{assignmentId}/reduce` trims or fully closes your position
    (`reduceFraction` in `(0, 1]`, `isFullClose`). The proposal creator can close the whole proposal
    with `POST /perps/proposals/{id}/close`.
  </Step>

  <Step title="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.
  </Step>
</Steps>

## Browse markets

`GET /api/v1/perps/markets` returns every tradable perp market; `GET /api/v1/perps/markets/{symbol}`
returns one (and `data: null` if the symbol is unknown).

<CodeGroup>
  ```bash curl theme={null}
  curl "$MURMO_BASE/api/v1/perps/markets/BTC" \
    -H "Authorization: Bearer $MURMO_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(`${process.env.MURMO_BASE}/api/v1/perps/markets/BTC`, {
    headers: { Authorization: `Bearer ${process.env.MURMO_API_KEY}` },
  });
  const { data } = await res.json();
  console.log(data.symbol, data.markPriceUsd, data.fundingRatePercentage);
  ```

  ```python Python theme={null}
  res = requests.get(
      f"{base}/api/v1/perps/markets/BTC",
      headers={"Authorization": f"Bearer {key}"},
  )
  print(res.json()["data"])
  ```
</CodeGroup>

```json Response theme={null}
{
  "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):

| 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 funding 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 ints (plain JSON numbers).                               |
| `leverageTiersJson`, `riskFactorsJson`           | string                | JSON-encoded leverage tiers / risk factors.                         |
| `fundingIntervalSeconds`, `fundingPeriodSeconds` | integer               | Funding schedule.                                                   |

<Tip>
  The `market_tick` WebSocket stream sends these prices as **numbers**, not decimal strings, for
  speed. For exact money math (entry sizing, accounting) read prices from `GET /perps/markets`.
  See [Market data](/websockets/market-data).
</Tip>

## 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).

```bash theme={null}
curl "$MURMO_BASE/api/v1/perps/proposals?groupId=1a9d212a-de67-45f4-88f5-6e9f41e78dc0" \
  -H "Authorization: Bearer $MURMO_API_KEY"
```

```json Response theme={null}
{
  "data": [
    {
      "id": "b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30",
      "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
      "createdByUserDynamicId": "usr_9f1c...",
      "marketSymbol": "BTC",
      "side": "LONG",
      "reason": "Bullish into the halving",
      "creatorLeverage": "5",
      "stopLossPct": null,
      "takeProfitPct": "100",
      "currentPnlPct": "12.4",
      "closedAt": null,
      "exitPnlUsd": null,
      "exitPnlPct": null,
      "participantCount": 3,
      "totalParticipantCount": 3,
      "participantAvatars": ["https://...", "https://..."],
      "createdAt": "2026-06-02T18:55:00.000Z"
    }
  ]
}
```

`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 of the idea. 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.                                 |
| `participantAvatars`                         | string\[]                           | Avatar URLs of participants.                             |

## Open a position (new proposal)

`POST /api/v1/perps/proposals` creates the proposal and opens your position atomically. The wallet is
resolved for you — you never pass one.

| Field           | Required | Type                  | Notes                                                |
| --------------- | -------- | --------------------- | ---------------------------------------------------- |
| `groupId`       | yes      | string                | Group to open the idea in. You must be a member.     |
| `marketSymbol`  | yes      | string                | A `symbol` from `GET /perps/markets`, e.g. `BTC`.    |
| `side`          | yes      | `"LONG"` \| `"SHORT"` | Direction. Must be exactly one of these.             |
| `collateralUsd` | yes      | MoneyString           | USD you put up, as a decimal string, e.g. `"25.00"`. |
| `leverage`      | yes      | DecimalString         | Multiplier as a numeric string, e.g. `"5"`.          |
| `reason`        | no       | string                | Your thesis, shown to the group.                     |
| `stopLossPct`   | no       | DecimalString         | % collateral-ROI stop-loss (see below).              |
| `takeProfitPct` | no       | DecimalString         | % collateral-ROI take-profit (see below).            |

<Warning>
  `side` must be exactly `"LONG"` or `"SHORT"`. Anything else is rejected with `400` — the API never
  silently coerces a bad value, which would otherwise open a reversed position.
</Warning>

<CodeGroup>
  ```bash curl theme={null}
  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"
    }'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(`${process.env.MURMO_BASE}/api/v1/perps/proposals`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MURMO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      groupId: "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
      marketSymbol: "BTC",
      side: "LONG",
      collateralUsd: "25.00",
      leverage: "5",
      reason: "Bullish into the halving",
      takeProfitPct: "100",
    }),
  });
  const { data } = await res.json();
  console.log(data.assignmentId, data.proposalId, data.txSignature);
  ```

  ```python Python theme={null}
  res = requests.post(
      f"{base}/api/v1/perps/proposals",
      headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
      json={
          "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
          "marketSymbol": "BTC",
          "side": "LONG",
          "collateralUsd": "25.00",
          "leverage": "5",
          "reason": "Bullish into the halving",
          "takeProfitPct": "100",
      },
  )
  print(res.json()["data"])
  ```
</CodeGroup>

```json Response theme={null}
{
  "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're
populated 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 token 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** (account P\&L),
not as a price move in the underlying.

<Note>
  `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 corresponding trigger prices come back on the position as `stopLossPriceUsd`
  and `takeProfitPriceUsd`.
</Note>

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

| Field           | Required | Type          | Notes                           |
| --------------- | -------- | ------------- | ------------------------------- |
| `collateralUsd` | yes      | MoneyString   | USD you put up, e.g. `"25.00"`. |
| `leverage`      | yes      | DecimalString | Your multiplier, e.g. `"5"`.    |

```bash theme={null}
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).

<Tip>
  `{id}` here is the **`proposalId`**. This is the only join path on REST — a position's own
  `assignmentId` is for `/reduce` and `/claim`, not for joining.
</Tip>

## Monitor your positions

`GET /api/v1/perps/positions?filter=active` returns your positions, with live mark/PnL/funding fields
plus realized fields once closed. `filter` is `active` (default), `past`, or `all`.

```bash theme={null}
curl "$MURMO_BASE/api/v1/perps/positions?filter=active" \
  -H "Authorization: Bearer $MURMO_API_KEY"
```

```json Response theme={null}
{
  "data": [
    {
      "id": "f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55",
      "userId": "usr_9f1c...",
      "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
      "proposalId": "b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30",
      "subaccountIndex": 0,
      "marketSymbol": "BTC",
      "side": "LONG",
      "status": "OPEN",
      "openedAt": "2026-06-02T18:55:01.000Z",
      "closedAt": null,
      "initialCollateralUsdc": "25.00",
      "initialLeverage": "5",
      "currentSizeBaseLots": "18420",
      "positionValueUsd": "126.10",
      "entryPriceUsd": "68110.0",
      "liquidationPriceUsd": "55230.4",
      "stopLossPriceUsd": null,
      "takeProfitPriceUsd": "81732.0",
      "unrealizedPnlUsd": "1.10",
      "unsettledFundingUsd": "-0.02",
      "accumulatedFundingUsd": "-0.05",
      "isClaimable": false,
      "participantCount": 3,
      "participantAvatars": ["https://..."]
    }
  ]
}
```

`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`.                                                                                                            |
| `subaccountIndex`                                   | integer                  | Phoenix subaccount.                                                                                                                                         |
| `initialCollateralUsdc`                             | MoneyString              | Collateral you put up.                                                                                                                                      |
| `initialLeverage`                                   | DecimalString            | Leverage at open.                                                                                                                                           |
| `currentSizeBaseLots`                               | string \| null           | Current size in base lots (a quantity, not money).                                                                                                          |
| `currentSizeBaseUnits`                              | DecimalString \| null    | Current size in base units.                                                                                                                                 |
| `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.                                                                                                                                    |
| `collateralBalanceUsdc` / `effectiveCollateralUsdc` | MoneyString \| null      | Collateral balances.                                                                                                                                        |
| `isClaimable`                                       | boolean                  | `true` after a take-profit close, until you `/claim`.                                                                                                       |
| `closeReason` / `claimedAt`                         | enum / date-time \| null | Why it closed (`USER_FULL_CLOSE`, `LIQUIDATION`, `BACKSTOP_LIQUIDATION`, `ADL`, `STOP_LOSS_TRIGGERED`, `TAKE_PROFIT_TRIGGERED`, `ADMIN`), and when claimed. |

When closed, the realized fields populate: `priceRealizedPnlUsd`, `fundingRealizedUsd`,
`totalFeesUsd`, `liquidationPenaltyUsd`, `netRealizedPnlUsd`, and `finalCollateralReturned` — all
MoneyString. Use `filter=past` or `filter=all` to see them.

<Tip>
  `currentSizeBaseLots` / `currentSizeBaseUnits` are **quantities**, not USD. Everything ending in
  `...Usd` (and prices/PnL/percent) is a human decimal string. See
  [Money & precision → Raw vs. human quantities](/concepts/money-and-precision).
</Tip>

## Reduce or close your position

`POST /api/v1/perps/positions/{assignmentId}/reduce` trims or fully closes **your** position. It's
keyed by `assignmentId` (the position's `id`).

| Field            | Required | Type          | Notes                                                         |
| ---------------- | -------- | ------------- | ------------------------------------------------------------- |
| `reduceFraction` | yes      | DecimalString | Fraction of current size to close, in `(0, 1]`, e.g. `"0.5"`. |
| `isFullClose`    | yes      | boolean       | Set `true` when this fully closes the position.               |

<CodeGroup>
  ```bash curl theme={null}
  # 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 }'
  ```

  ```javascript JavaScript theme={null}
  // Fully close
  const res = await fetch(
    `${process.env.MURMO_BASE}/api/v1/perps/positions/${assignmentId}/reduce`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.MURMO_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ reduceFraction: "1", isFullClose: true }),
    },
  );
  const { data } = await res.json();
  console.log(data.closePnlUsd, data.closeProceedsUsd);
  ```

  ```python Python theme={null}
  # Fully close
  res = requests.post(
      f"{base}/api/v1/perps/positions/{assignment_id}/reduce",
      headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
      json={"reduceFraction": "1", "isFullClose": True},
  )
  print(res.json()["data"])
  ```
</CodeGroup>

```json Response (full close) theme={null}
{
  "data": {
    "assignmentId": "f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55",
    "proposalId": "b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30",
    "subaccountIndex": 0,
    "txSignature": "3Kp...solana_sig",
    "marketSymbol": "BTC",
    "side": "LONG",
    "closePnlUsd": "4.20",
    "closePnlPct": "16.8",
    "closeProceedsUsd": "29.20",
    "closedBaseUnits": "18420",
    "isFullClose": true
  }
}
```

The response is a `PerpPositionResult` (table above). On a full close, `closePnlUsd`, `closePnlPct`,
`closeProceedsUsd`, and `closedBaseUnits` are populated.

<Warning>
  `reduceFraction` must be in `(0, 1]` — a value `> 1`, `0`, or non-numeric is rejected with `400`,
  as is a missing `isFullClose`. To close everything, send `reduceFraction: "1"` with
  `isFullClose: true`.
</Warning>

## 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 (enforced); it closes the creator's own open position(s) and locks
out new joiners. Other members' positions are left untouched — they manage their own exits via
`/reduce`.

```bash theme={null}
curl -X POST "$MURMO_BASE/api/v1/perps/proposals/b2c7f0e1-4d3a-4f9c-9a21-7e8d6c5b4a30/close" \
  -H "Authorization: Bearer $MURMO_API_KEY"
```

```json Response theme={null}
{ "data": { "success": true } }
```

<Note>
  If you're not the creator, this returns `403`. To exit a position you joined, use
  `/positions/{assignmentId}/reduce` instead.
</Note>

## 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. It's keyed by `assignmentId`.

```bash theme={null}
curl -X POST "$MURMO_BASE/api/v1/perps/positions/f3a1c9d2-1b44-4e77-8c0a-2d9e6b1f7a55/claim" \
  -H "Authorization: Bearer $MURMO_API_KEY"
```

```json Response theme={null}
{
  "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`:

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

<Tip>
  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.
</Tip>

## Errors you'll hit

| Status / code          | Cause                                                                                                                                  | Fix                                                                                      |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `400`                  | Bad `side`, non-positive `collateralUsd`/`leverage`, `reduceFraction` out of `(0, 1]`, missing `isFullClose`/`groupId`/`marketSymbol`. | Fix the request body.                                                                    |
| `401`                  | Missing or invalid key.                                                                                                                | Send `Authorization: Bearer murmo_...`.                                                  |
| `403 NOT_GROUP_MEMBER` | Reading/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](/concepts/geo-restrictions). |

See [Errors](/concepts/errors) for the full status-code and `code` reference and a retry pattern.

## Next

<CardGroup cols={2}>
  <Card title="Perps bot" icon="robot" href="/examples/perps-bot">
    Open, monitor, and close a position in one script.
  </Card>

  <Card title="Money & precision" icon="coins" href="/concepts/money-and-precision">
    Why `collateralUsd` is `"25.00"` and not `25`.
  </Card>

  <Card title="Groups & proposals" icon="people-group" href="/concepts/groups-and-proposals">
    The social model: groups, proposals, positions.
  </Card>

  <Card title="Market data (WebSocket)" icon="bolt" href="/websockets/market-data">
    Live per-symbol perp ticks for low-latency monitoring.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference">
    Every Perpetuals endpoint, field by field.
  </Card>
</CardGroup>
