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

# Spot trading

> Discover tokens and trade group spot proposals.

Spot trading on Murmo happens through **group spot proposals**: a shared token idea inside a group that
a leader opens with a buy and other members can follow. Slippage and the wallet id are always
resolved for you (never accepted from the caller).

Everything lives under `/api/v1/spot`. Tokens are addressed by their **Solana mint address**, or the
literal string `"USDC"`.

<Note>
  Every monetary value — in requests and responses — is a **full-precision plain
  decimal string in USD** (`"12.50"`, not `12.5`, not `12500000`, never
  `"1.25e1"`). Token **quantities** in base units are the one exception and are
  always named with a `...Raw` suffix. See [Money &
  precision](/concepts/money-and-precision).
</Note>

Set up your environment the same way as the [Quickstart](/quickstart):

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

## Find a token

`GET /api/v1/spot/tokens/search` is a Jupiter-backed search over Solana tokens. Both `q` (a symbol,
name, or mint) and `limit` (default `20`) are optional.

<CodeGroup>
  ```bash curl theme={null}
  curl "$MURMO_BASE/api/v1/spot/tokens/search?q=bonk&limit=5" \
    -H "Authorization: Bearer $MURMO_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    `${process.env.MURMO_BASE}/api/v1/spot/tokens/search?q=bonk&limit=5`,
    { headers: { Authorization: `Bearer ${process.env.MURMO_API_KEY}` } },
  );
  const { data } = await res.json();
  console.log(data.map((t) => t.symbol));
  ```

  ```python Python theme={null}
  res = requests.get(
      f"{base}/api/v1/spot/tokens/search",
      params={"q": "bonk", "limit": 5},
      headers={"Authorization": f"Bearer {key}"},
  )
  print(res.json()["data"])
  ```
</CodeGroup>

`data` is an array of token objects. The shape passes through from Jupiter/CoinGecko, so treat the
keys as opaque — but any price/volume floats are rendered as decimal strings, never JS numbers.

<Tip>
  Search is for discovery. Once you have a candidate mint, fetch its canonical
  price and `decimals` with the by-mint endpoint below before you trade.
</Tip>

## Get price + metadata (and `decimals`)

`GET /api/v1/spot/tokens/{mint}` returns price and metadata for one token by its mint address. This is
**how you get a token's `decimals`** — the number you need to humanize any `...Raw` quantity returned
elsewhere.

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

  ```javascript JavaScript theme={null}
  const mint = "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263";
  const res = await fetch(
    `${process.env.MURMO_BASE}/api/v1/spot/tokens/${mint}`,
    {
      headers: { Authorization: `Bearer ${process.env.MURMO_API_KEY}` },
    },
  );
  const { data } = await res.json();
  console.log(data.decimals); // structural integer, e.g. 5
  ```

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

`data` is a single token object (opaque, pass-through shape). Price fields are decimal strings;
`decimals` is a plain integer you reuse to convert base units to human amounts.

## Group spot proposals

A spot **proposal** is a token idea inside a group: a leader opens it with a buy, and other members
buy in, sell out, and follow along. Each member manages their own position; the creator can close the
whole proposal. See [Groups & proposals](/concepts/groups-and-proposals) for the social model.

<Warning>
  Every proposal endpoint is **members-only**. Reading or trading a proposal in
  a group you don't belong to returns **`403`** with `code: NOT_GROUP_MEMBER`.
  Creating a proposal additionally requires a leader/admin role. See
  [Errors](/concepts/errors).
</Warning>

### List a group's proposals

`GET /api/v1/spot/proposals?groupId=...` returns every spot proposal in a group, each paired with
**your** position on it. `groupId` is required (a missing/blank value is a clean `400`).

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

  ```javascript JavaScript theme={null}
  const groupId = "1a9d212a-de67-45f4-88f5-6e9f41e78dc0";
  const res = await fetch(
    `${process.env.MURMO_BASE}/api/v1/spot/proposals?groupId=${groupId}`,
    { headers: { Authorization: `Bearer ${process.env.MURMO_API_KEY}` } },
  );
  const { data } = await res.json(); // array of SpotProposalWithPosition
  ```

  ```python Python theme={null}
  res = requests.get(
      f"{base}/api/v1/spot/proposals",
      params={"groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0"},
      headers={"Authorization": f"Bearer {key}"},
  )
  print(res.json()["data"])
  ```
</CodeGroup>

`data` is an array of `SpotProposalWithPosition`:

| Field                | Meaning                                                             |
| -------------------- | ------------------------------------------------------------------- |
| `proposal`           | The `SpotProposal` (token, creator, prices, lifecycle — see below). |
| `userPosition`       | Your `SpotPositionSummary` on this proposal.                        |
| `participantCount`   | How many members hold a position (nullable).                        |
| `participantAvatars` | Avatar URLs for participants (nullable).                            |

### Proposal detail

`GET /api/v1/spot/proposals/{id}` returns the same `SpotProposalWithPosition` shape, and additionally
populates `proposal.trades` — **the caller's own trades** on this proposal. If the proposal doesn't
exist, `data` is `null`.

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

  ```javascript JavaScript theme={null}
  const res = await fetch(
    `${process.env.MURMO_BASE}/api/v1/spot/proposals/PROPOSAL_ID`,
    { headers: { Authorization: `Bearer ${process.env.MURMO_API_KEY}` } },
  );
  const { data } = await res.json();
  if (data) console.log(data.proposal.trades);
  ```

  ```python Python theme={null}
  res = requests.get(
      f"{base}/api/v1/spot/proposals/PROPOSAL_ID",
      headers={"Authorization": f"Bearer {key}"},
  )
  data = res.json()["data"]
  print(data and data["proposal"]["trades"])
  ```
</CodeGroup>

#### `SpotProposal`

| Field                     | Type                                                               | Meaning                                                          |
| ------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------- |
| `id`                      | string                                                             | Proposal id (use it in `/buy`, `/sell`, `/close`).               |
| `groupId`                 | string                                                             | The group this proposal belongs to.                              |
| `createdByUserDynamicId`  | string                                                             | The creator's user id.                                           |
| `tokenMetadataId`         | string                                                             | Internal token metadata id.                                      |
| `reason`                  | string \| null                                                     | The thesis the creator gave when opening it.                     |
| `initialPriceUsd`         | [MoneyString](/concepts/money-and-precision) \| null               | Token price (USD) when the proposal opened.                      |
| `exitPriceUsd`            | MoneyString \| null                                                | Token price (USD) when the proposal closed.                      |
| `exitPnlPct`              | [DecimalString](/concepts/money-and-precision#percentages) \| null | Realized PnL percent at close (e.g. `"12.3"` = 12.3%).           |
| `exitPnlUsd`              | MoneyString \| null                                                | Realized PnL in USD at close.                                    |
| `closedAt`                | date-time \| null                                                  | When it was closed (null while open).                            |
| `createdAt` / `updatedAt` | date-time                                                          | Timestamps.                                                      |
| `token`                   | `TokenRef` \| null                                                 | `{ contractAddress, symbol, name, logoUrl, verified, ... }`.     |
| `group`                   | `GroupRef` \| null                                                 | `{ uniqueId, name, image }`.                                     |
| `createdBy`               | `UserRef` \| null                                                  | `{ dynamicId, username }`.                                       |
| `trades`                  | `SpotTrade[]` \| null                                              | **Detail endpoint only** — the caller's trades on this proposal. |

#### `SpotPositionSummary` (`userPosition`)

| Field                                   | Type                                | Meaning                                                                      |
| --------------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------- |
| `hasPosition`                           | boolean                             | Whether you currently hold this proposal.                                    |
| `currentTokenAmountRaw`                 | string \| null                      | Your token holding in **base units** — humanize with the token's `decimals`. |
| `totalCostUsd`                          | MoneyString \| null                 | What you've spent into the position, in USD.                                 |
| `avgEntryPriceUsd` / `avgExitPriceUsd`  | MoneyString \| null                 | Average entry / exit price (USD).                                            |
| `unrealizedPnlUsd` / `unrealizedPnlPct` | MoneyString / DecimalString \| null | Open PnL, in USD and percent.                                                |
| `realizedPnlUsd` / `realizedPnlPct`     | MoneyString / DecimalString \| null | Closed PnL, in USD and percent.                                              |
| `currentValueUsd`                       | MoneyString \| null                 | Current mark value of your holding (USD).                                    |
| `currentPriceUsd`                       | MoneyString \| null                 | Current token price (USD).                                                   |
| `userExitedAt`                          | date-time \| null                   | When you fully exited (null if still in).                                    |

<Note>
  `currentTokenAmountRaw` is the only quantity here in base units (note the
  `...Raw` suffix). Every other field is a human USD or percent string. To get a
  human token count, divide by `10 ** decimals`.
</Note>

### The proposal lifecycle

Open a proposal, scale your position with buys and sells, then close it. Buy, sell, and close all
return the executed [`SpotTrade`](#spottrade-buy-/-sell-/-close).

<Steps>
  <Step title="Create with an opening buy">
    `POST /api/v1/spot/proposals` creates the proposal **and** places the proposer's opening buy in a
    single call. Leader/admin only.

    | Field             | Type                   | Notes                                        |
    | ----------------- | ---------------------- | -------------------------------------------- |
    | `groupId`         | string (required)      | The group to open the proposal in.           |
    | `contractAddress` | string (required)      | The token's Solana mint.                     |
    | `reason`          | string (optional)      | Your thesis, shown to the group.             |
    | `amountUsd`       | MoneyString (required) | The opening buy size in USDC (human string). |

    <CodeGroup>
      ```bash curl theme={null}
      curl -X POST "$MURMO_BASE/api/v1/spot/proposals" \
        -H "Authorization: Bearer $MURMO_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
          "contractAddress": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
          "reason": "Momentum breakout",
          "amountUsd": "50.00"
        }'
      ```

      ```javascript JavaScript theme={null}
      const res = await fetch(`${process.env.MURMO_BASE}/api/v1/spot/proposals`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.MURMO_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          groupId: "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
          contractAddress: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
          reason: "Momentum breakout",
          amountUsd: "50.00",
        }),
      });
      const { data } = await res.json();
      console.log(data.proposal.id, data.trade.txSignature);
      ```

      ```python Python theme={null}
      res = requests.post(
          f"{base}/api/v1/spot/proposals",
          headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
          json={
              "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
              "contractAddress": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
              "reason": "Momentum breakout",
              "amountUsd": "50.00",
          },
      )
      print(res.json()["data"]["proposal"]["id"])
      ```
    </CodeGroup>

    Returns `{ data: { proposal, trade } }` — a `SpotProposal` and the opening `SpotTrade`. Keep
    `proposal.id` for the calls below.

    ```json Response theme={null}
    {
      "data": {
        "proposal": { "id": "prop_abc123", "groupId": "1a9d212a-...", "reason": "Momentum breakout", "...": "..." },
        "trade": {
          "tradeType": "BUY",
          "tokenAmount": "1380000",
          "tokenDecimals": 5,
          "pricePerTokenUsd": "0.0000362",
          "totalCostUsd": "50",
          "alphaFeeUsd": "0.10",
          "pnlUsd": null
        }
      }
    }
    ```
  </Step>

  <Step title="Buy in">
    `POST /api/v1/spot/proposals/{id}/buy` adds to your position. Send `amountUsd` (USDC to spend), or
    `max: true` to spend your full USDC balance (then `amountUsd` is ignored).

    <CodeGroup>
      ```bash curl theme={null}
      # Buy a fixed $20
      curl -X POST "$MURMO_BASE/api/v1/spot/proposals/PROPOSAL_ID/buy" \
        -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
        -d '{ "amountUsd": "20.00" }'

      # Or go all-in on available USDC
      curl -X POST "$MURMO_BASE/api/v1/spot/proposals/PROPOSAL_ID/buy" \
        -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
        -d '{ "max": true }'
      ```

      ```javascript JavaScript theme={null}
      const res = await fetch(
        `${process.env.MURMO_BASE}/api/v1/spot/proposals/PROPOSAL_ID/buy`,
        {
          method: "POST",
          headers: {
            Authorization: `Bearer ${process.env.MURMO_API_KEY}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ amountUsd: "20.00" }), // or { max: true }
        }
      );
      const { data } = await res.json();
      console.log(data.trade.tradeType, data.trade.totalCostUsd);
      ```

      ```python Python theme={null}
      res = requests.post(
          f"{base}/api/v1/spot/proposals/PROPOSAL_ID/buy",
          headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
          json={"amountUsd": "20.00"},  # or {"max": True}
      )
      print(res.json()["data"]["trade"])
      ```
    </CodeGroup>

    Returns `{ data: { trade } }` (a `SpotTradeEnvelope`).
  </Step>

  <Step title="Sell out">
    `POST /api/v1/spot/proposals/{id}/sell` trims or exits your position. Here `amountUsd` is your
    **desired USDC output** (how much cash you want back), or `max: true` to sell the **full token
    position**.

    <CodeGroup>
      ```bash curl theme={null}
      # Take $10 of USDC back out
      curl -X POST "$MURMO_BASE/api/v1/spot/proposals/PROPOSAL_ID/sell" \
        -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
        -d '{ "amountUsd": "10.00" }'

      # Or exit the whole position
      curl -X POST "$MURMO_BASE/api/v1/spot/proposals/PROPOSAL_ID/sell" \
        -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
        -d '{ "max": true }'
      ```

      ```javascript JavaScript theme={null}
      const res = await fetch(
        `${process.env.MURMO_BASE}/api/v1/spot/proposals/PROPOSAL_ID/sell`,
        {
          method: "POST",
          headers: {
            Authorization: `Bearer ${process.env.MURMO_API_KEY}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ amountUsd: "10.00" }), // or { max: true }
        }
      );
      const { data } = await res.json();
      console.log(data.trade.pnlUsd);
      ```

      ```python Python theme={null}
      res = requests.post(
          f"{base}/api/v1/spot/proposals/PROPOSAL_ID/sell",
          headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
          json={"amountUsd": "10.00"},  # or {"max": True}
      )
      print(res.json()["data"]["trade"])
      ```
    </CodeGroup>

    Returns `{ data: { trade } }` (a `SpotTradeEnvelope`).

    <Tip>
      Buy `amountUsd` is **USDC spent**; sell `amountUsd` is **USDC received**. Use `max: true` on
      either side to skip sizing math — full balance on buy, full position on sell.
    </Tip>
  </Step>

  <Step title="Close (creator only)">
    `POST /api/v1/spot/proposals/{id}/close` is for the proposal's creator. It sells the creator's
    full position and moves the proposal into a closed state.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X POST "$MURMO_BASE/api/v1/spot/proposals/PROPOSAL_ID/close" \
        -H "Authorization: Bearer $MURMO_API_KEY"
      ```

      ```javascript JavaScript theme={null}
      const res = await fetch(
        `${process.env.MURMO_BASE}/api/v1/spot/proposals/PROPOSAL_ID/close`,
        {
          method: "POST",
          headers: { Authorization: `Bearer ${process.env.MURMO_API_KEY}` },
        }
      );
      const { data } = await res.json();
      console.log(data.proposal.closedAt, data.proposal.exitPnlUsd);
      ```

      ```python Python theme={null}
      res = requests.post(
          f"{base}/api/v1/spot/proposals/PROPOSAL_ID/close",
          headers={"Authorization": f"Bearer {key}"},
      )
      print(res.json()["data"]["proposal"]["exitPnlUsd"])
      ```
    </CodeGroup>

    Returns `{ data: { proposal, trade } }` — the now-closed `SpotProposal` (with `closedAt`,
    `exitPriceUsd`, `exitPnlUsd`, `exitPnlPct`) and the closing `SpotTrade`. Other members keep their
    own positions and exit them with `/sell`.
  </Step>
</Steps>

### `SpotTrade` (buy / sell / close)

Every executed trade — the opening buy on create, each `/buy` and `/sell`, and the closing trade —
returns a `SpotTrade`. Unlike position quantities, `tokenAmount` here is **already humanized** (it uses
`tokenDecimals`), so you don't divide it yourself.

| Field               | Type                                                       | Meaning                                                     |
| ------------------- | ---------------------------------------------------------- | ----------------------------------------------------------- |
| `id`                | string                                                     | Trade id.                                                   |
| `tradingProposalId` | string                                                     | The proposal this trade belongs to.                         |
| `groupId`           | string                                                     | The group.                                                  |
| `walletAddress`     | string                                                     | The wallet that executed the trade.                         |
| `tradeType`         | `"BUY"` \| `"SELL"`                                        | Direction.                                                  |
| `tokenAmount`       | [DecimalString](/concepts/money-and-precision#percentages) | Token quantity, **already humanized** with `tokenDecimals`. |
| `tokenDecimals`     | integer                                                    | The token's decimals (structural integer).                  |
| `pricePerTokenUsd`  | [MoneyString](/concepts/money-and-precision) \| null       | Execution price per token (USD).                            |
| `totalCostUsd`      | MoneyString                                                | USD value of the trade.                                     |
| `alphaFeeUsd`       | MoneyString                                                | Alpha fee for this trade (USD).                             |
| `pnlUsd`            | MoneyString \| null                                        | Realized PnL on a sell (USD); null on buys.                 |
| `pnlPct`            | DecimalString \| null                                      | Realized PnL percent on a sell; null on buys.               |
| `txSignature`       | string \| null                                             | Solana transaction signature.                               |
| `createdAt`         | date-time                                                  | When it executed.                                           |

<Note>
  Two quantity conventions live side by side: a **trade's** `tokenAmount` is
  already humanized (uses `tokenDecimals`), while a **position's**
  `currentTokenAmountRaw` is raw base units you humanize with `decimals`. The
  `...Raw` suffix is your signal. See [Money & precision → Raw vs. human
  quantities](/concepts/money-and-precision#raw-vs-human-quantities).
</Note>

## Tokenized stocks (by ticker)

Murmo lists **Ondo Global Markets** tokenized stocks and ETFs (e.g. `NVDA`, `AAPL`). They trade
through the exact same group/proposal flow as any other spot token — position tracking and `max`
semantics are identical — but a dedicated `/api/v1/spot/stocks` surface lets you
trade by **ticker** instead of a mint, and tells you what's supported and whether the market is open.

<Note>
  The tradeable universe is the Ondo catalog only. A `ticker` is the clean
  symbol (`"NVDA"`, case-insensitive); resolution also accepts the raw on-chain
  symbol (`"NVDAON"`) or the mint. Stocks observe **market hours** — trades
  outside them are rejected up front (see below).
</Note>

### List supported stocks

`GET /api/v1/spot/stocks` returns the full catalog plus the shared market status. There are no
parameters.

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

  ```javascript JavaScript theme={null}
  const res = await fetch(`${process.env.MURMO_BASE}/api/v1/spot/stocks`, {
    headers: { Authorization: `Bearer ${process.env.MURMO_API_KEY}` },
  });
  const { data } = await res.json();
  console.log(data.marketStatus, data.nextOpen); // e.g. "CLOSED" "2026-06-17T13:30:00.000Z"
  console.log(data.stocks.map((s) => s.ticker));
  ```
</CodeGroup>

Returns `{ data: { marketStatus, nextOpen, stocks } }`. `marketStatus` is `OPEN`, `PAUSED`, or
`CLOSED`; `nextOpen` is the ISO instant trading resumes (`null` when open). Each `stocks[]` entry:

| Field            | Type                                                               | Meaning                              |
| ---------------- | ------------------------------------------------------------------ | ------------------------------------ |
| `ticker`         | string                                                             | The symbol you trade by (`"NVDA"`).  |
| `name`           | string                                                             | Display name (`"NVIDIA"`).           |
| `mint`           | string                                                             | Underlying Solana (Token-2022) mint. |
| `kind`           | `"stock"` \| `"etf"`                                               | Catalog category.                    |
| `price`          | [MoneyString](/concepts/money-and-precision) \| null               | Real underlying equity price (USD).  |
| `priceChange24h` | [DecimalString](/concepts/money-and-precision#percentages) \| null | 24h change percent.                  |
| `decimals`       | integer                                                            | Token decimals (structural).         |
| `minTradeUsd`    | MoneyString \| null                                                | Minimum opening-buy size (USD).      |
| `imageUrl`       | string \| null                                                     | Logo.                                |

### Open and trade by ticker

`POST /api/v1/spot/stocks/proposals` opens a position by `ticker` (everything else matches
[Create with an opening buy](#the-proposal-lifecycle) — `groupId`, optional `reason`, `amountUsd`).
Follow-on `POST /api/v1/spot/stocks/proposals/{id}/buy` and `/sell` take the same
`{ amountUsd | max }` body as the mint-based endpoints and return a `SpotTradeEnvelope`.

<CodeGroup>
  ```bash curl theme={null}
  # Open a $50 NVDA position in a group
  curl -X POST "$MURMO_BASE/api/v1/spot/stocks/proposals" \
    -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
    -d '{ "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0", "ticker": "NVDA", "amountUsd": "50.00" }'

  # Add $20, then exit fully

  curl -X POST "$MURMO_BASE/api/v1/spot/stocks/proposals/PROPOSAL_ID/buy" \
   -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
   -d '{ "amountUsd": "20.00" }'

  curl -X POST "$MURMO_BASE/api/v1/spot/stocks/proposals/PROPOSAL_ID/sell" \
   -H "Authorization: Bearer $MURMO_API_KEY" -H "Content-Type: application/json" \
   -d '{ "max": true }'

  ```

  ```javascript JavaScript theme={null}
  const open = await fetch(`${process.env.MURMO_BASE}/api/v1/spot/stocks/proposals`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MURMO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ groupId: GROUP_ID, ticker: "NVDA", amountUsd: "50.00" }),
  });
  const { data } = await open.json();
  console.log(data.proposal.id, data.trade.txSignature);
  ```
</CodeGroup>

<Warning>
  Stock-specific errors on these endpoints: **`404` `TOKEN_NOT_FOUND`** (ticker
  not in the catalog — check `GET /spot/stocks`), **`409` `MARKET_CLOSED`**
  (market paused/closed; `details.nextOpenAt` carries the next open instant),
  and **`422` `ORDER_BELOW_MIN_SIZE`** (opening buy under the token's
  `minTradeUsd`). Membership/role rules (`403 NOT_GROUP_MEMBER`) apply exactly
  as for any proposal.
</Warning>

## Errors you'll hit

| Status / code                | When                                                                                 | What to do                                          |
| ---------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------- |
| `400`                        | Missing/invalid body or `groupId`, or an unroutable trade.                           | Fix the request; read `message`/`code`.             |
| `401`                        | Missing or invalid key.                                                              | Check the `Authorization: Bearer murmo_...` header. |
| `403` `NOT_GROUP_MEMBER`     | Reading/trading a proposal in a group you're not in (or not leader/admin on create). | Don't retry as-is.                                  |
| `404` `TOKEN_NOT_FOUND`      | Stock ticker not in the Ondo catalog.                                                | List `GET /spot/stocks` first.                      |
| `409` `MARKET_CLOSED`        | Stock market paused/closed.                                                          | Wait until `details.nextOpenAt`.                    |
| `422` `ORDER_BELOW_MIN_SIZE` | Opening buy under the stock's `minTradeUsd`.                                         | Increase `amountUsd`.                               |
| `422` `ROUTE_NOT_FOUND`      | No swap route / no quote for this size right now.                                    | Often transient — retry or adjust size.             |
| `502` `UPSTREAM_REJECTED`    | The swap venue rejected the trade (`details.upstream` carries the raw reason).       | Don't auto-retry; inspect and adjust.               |

See [Errors](/concepts/errors) for the full list, status-code semantics, and a ready-made handler. Note
that proposal detail returns `data: null` for an unknown id.

## Where to next

<CardGroup cols={2}>
  <Card title="Spot momentum bot" icon="robot" href="/examples/spot-bot">
    The whole flow as one copy-pasteable script.
  </Card>

  <Card title="Money & precision" icon="coins" href="/concepts/money-and-precision">
    Decimal strings, and humanizing `...Raw` quantities.
  </Card>

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

  <Card title="Errors" icon="triangle-exclamation" href="/concepts/errors">
    Error shapes, status codes, and the codes worth handling.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference">
    Every Spot endpoint, parameter, and response schema.
  </Card>
</CardGroup>
