Skip to main content
Prediction markets let your bot take a YES/NO position on a real-world event — a game, an election, a price level. Markets are Kalshi-backed: you browse Kalshi events, pick an outcome, and the position lives as a proposal inside a group, exactly like spot and perps. The full lifecycle is: discover an event → create a proposal (your opening prediction) → predict more or sell → the market resolves → claim winnings.
Every monetary value in requests and responses is a full-precision plain decimal string in USD ("10.00", not 10, not 10000000). That covers request fields like amountUsd and response fields like totalCostUsd. See Money & precision.
Event-contract trading is restricted in some jurisdictions and may require identity verification done in the app. If a call returns 403, check your account eligibility — see Eligibility & geo restrictions.
Set up your environment before starting:
export MURMO_API_KEY="murmo_your_key_here"
export MURMO_BASE="https://api.alpha-labs.trade"

How a market is identified

You reference a market with three fields. The backend resolves eventTitle, marketTitle, and the outcome mint server-side — you never send those yourself.
FieldWhat it isExample
eventIdThe Kalshi event ticker (the matchup or question)."KXNFLGAME-25SB"
marketIdThe Kalshi market ID — the specific outcome within that event."KXNFLGAME-25SB-KC"
isYesSide: true buys YES, false buys NO.true
isYes is a boolean, not a string. isYes: true is the YES side; isYes: false is the NO side. A missing or non-boolean isYes is rejected with 400.
Get eventId and marketId from the event-discovery endpoints below. The event payload lists its markets with Kalshi tickers; use the event’s ticker as eventId and the chosen market’s ticker as marketId.

The full lifecycle

1

Discover an event

Browse or search the event endpoints to find an eventId (event ticker) and the marketId (the specific outcome) you want. Decide your side (isYes). Prices in these Kalshi-native payloads are already human dollar strings.
2

Create the proposal (opening prediction)

POST /api/v1/predictions/proposals with groupId, eventId, marketId, isYes, and amountUsd. Leaders only. You get back the proposal and its opening trade.
3

Predict more or sell

Add with POST .../{id}/predict (amountUsd). Trim or exit with POST .../{id}/sellamountUsd for an approximate target, or max: true to close your whole position.
4

Resolution

When Kalshi settles the market, the proposal’s status flips to RESOLVED and result / didWin are filled in. A leader can also close a proposal early to put it in sell-only mode.
5

Claim

If you won (didWin: true), POST .../{id}/claim redeems your tokens for USDC and returns the CLAIM trade plus amountClaimedUsd.

Discovering events

Event reads are Kalshi-native passthroughs: prices in their payloads are already human dollar strings. Each returns { "data": ... } wrapping the Kalshi-shaped response — treat the internals as Kalshi’s, not Murmo’s.

Browse

GET /api/v1/predictions/events/browse returns the trending feed by default. Narrow it with optional query params:
  • seriesTickers — comma-separated Kalshi series tickers to scope to.
  • status, limit, cursor — passthrough filters and paging for the trending path.
  • category (with optional tag, page) — when present, switches to the paginated category browse.
# Trending
curl "$MURMO_BASE/api/v1/predictions/events/browse" \
  -H "Authorization: Bearer $MURMO_API_KEY"

# Scoped to series tickers
curl "$MURMO_BASE/api/v1/predictions/events/browse?seriesTickers=KXNFLGAME,KXNBA&limit=20" \
  -H "Authorization: Bearer $MURMO_API_KEY"

# Paginated category browse
curl "$MURMO_BASE/api/v1/predictions/events/browse?category=Sports&page=1" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Response (shape)
{
  "data": {
    "events": [
      {
        "event_ticker": "KXNFLGAME-25SB",
        "title": "Super Bowl LIX winner",
        "markets": [
          { "ticker": "KXNFLGAME-25SB-KC", "yes_sub_title": "Kansas City", "yes_bid": "0.55", "yes_ask": "0.57" },
          { "ticker": "KXNFLGAME-25SB-PHI", "yes_sub_title": "Philadelphia", "yes_bid": "0.43", "yes_ask": "0.45" }
        ]
      }
    ]
  }
}
The exact keys inside a Kalshi event or market object are defined by Kalshi and may evolve. The example shows the fields you need: event_ticker becomes your eventId and a market ticker becomes your marketId.
GET /api/v1/predictions/events/search — fuzzy-search events. q is required (a missing or blank q is a 400). Optional: sort, order, limit, cursor.
curl "$MURMO_BASE/api/v1/predictions/events/search?q=super%20bowl&limit=10" \
  -H "Authorization: Bearer $MURMO_API_KEY"

Live

GET /api/v1/predictions/events/live — the live sports feed. Optional: limit, cursor, category, subcategory, competition.
curl "$MURMO_BASE/api/v1/predictions/events/live?category=Basketball" \
  -H "Authorization: Bearer $MURMO_API_KEY"

Event by ticker

GET /api/v1/predictions/events/{ticker} — one event by its Kalshi ticker, with its markets filtered for liquidity.
curl "$MURMO_BASE/api/v1/predictions/events/KXNFLGAME-25SB" \
  -H "Authorization: Bearer $MURMO_API_KEY"
GET /api/v1/predictions/events/{ticker}/related — sibling markets for the same matchup (spread, total, props). seriesTicker is required — a missing or blank value is a 400.
curl "$MURMO_BASE/api/v1/predictions/events/KXNFLGAME-25SB/related?seriesTicker=KXNFLGAME" \
  -H "Authorization: Bearer $MURMO_API_KEY"

Creating a proposal (with the opening prediction)

POST /api/v1/predictions/proposals opens a proposal and places the creator’s first prediction in one call. Group leaders only — non-leaders get 403.
groupId
string
required
The group to open the proposal in.
eventId
string
required
The Kalshi event ticker, e.g. "KXNFLGAME-25SB".
marketId
string
required
The Kalshi market ID for the specific outcome, e.g. "KXNFLGAME-25SB-KC".
isYes
boolean
required
true to buy YES, false to buy NO. Must be a boolean, not a string.
amountUsd
string
required
Opening prediction size as a USD decimal string, e.g. "10.00".
reason
string
Optional thesis, shown to group members.
curl -X POST "$MURMO_BASE/api/v1/predictions/proposals" \
  -H "Authorization: Bearer $MURMO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
    "eventId": "KXNFLGAME-25SB",
    "marketId": "KXNFLGAME-25SB-KC",
    "isYes": true,
    "amountUsd": "10.00",
    "reason": "KC value"
  }'
Response
{
  "data": {
    "proposal": {
      "id": "f0c1...e9",
      "groupId": "1a9d212a-de67-45f4-88f5-6e9f41e78dc0",
      "createdById": "user_abc",
      "eventId": "KXNFLGAME-25SB",
      "marketId": "KXNFLGAME-25SB-KC",
      "outcomeMint": "Es9v...YES",
      "eventTitle": "Super Bowl LIX winner",
      "marketTitle": "Kansas City",
      "isYes": true,
      "status": "ACTIVE",
      "result": null,
      "didWin": null,
      "reason": "KC value",
      "resolvedAt": null,
      "createdAt": "2026-01-20T18:04:11.000Z"
    },
    "trade": {
      "id": "trd_001",
      "proposalId": "f0c1...e9",
      "tradeType": "BUY",
      "tokenAmount": "17.857142",
      "tokenDecimals": 6,
      "pricePerTokenUsd": "0.56",
      "totalCostUsd": "10",
      "pnlPct": null,
      "pnlUsd": null,
      "txSignature": "4nP...sig"
    }
  }
}
tokenAmount is the count of outcome tokens you hold, already humanized using tokenDecimals. On an opening BUY, pnlPct and pnlUsd are null.

Predicting more

POST /api/v1/predictions/proposals/{id}/predict adds to your position on an existing proposal. Any group member can predict — not just the creator.
curl -X POST "$MURMO_BASE/api/v1/predictions/proposals/f0c1...e9/predict" \
  -H "Authorization: Bearer $MURMO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amountUsd": "5.00" }'
Response
{
  "data": {
    "trade": {
      "id": "trd_002",
      "proposalId": "f0c1...e9",
      "tradeType": "BUY",
      "tokenAmount": "8.928571",
      "tokenDecimals": 6,
      "pricePerTokenUsd": "0.56",
      "totalCostUsd": "5",
      "pnlPct": null,
      "pnlUsd": null,
      "txSignature": "5aB...sig"
    }
  }
}

Selling (cashing out)

POST /api/v1/predictions/proposals/{id}/sell sells part or all of your position. Send exactly one of:
FieldEffect
amountUsdThe desired USDC value to sell. The server converts it to outcome-token amount at the current price and caps it at your position.
max: trueSell your entire position on this proposal. When max is true, amountUsd is ignored.
amountUsd on a sell is an approximate target, not a guarantee. The server sizes the sell from the current price, and the realized USDC is determined at execution — it can differ from amountUsd as the price moves. To exit cleanly and avoid dust, prefer max: true.
curl -X POST "$MURMO_BASE/api/v1/predictions/proposals/f0c1...e9/sell" \
  -H "Authorization: Bearer $MURMO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amountUsd": "3.00" }'
Response
{
  "data": {
    "trade": {
      "id": "trd_003",
      "proposalId": "f0c1...e9",
      "tradeType": "SELL",
      "tokenAmount": "5.172413",
      "tokenDecimals": 6,
      "pricePerTokenUsd": "0.58",
      "totalCostUsd": "3",
      "pnlPct": "3.57",
      "pnlUsd": "0.1034",
      "txSignature": "6cD...sig"
    }
  }
}
On a SELL, pnlPct and pnlUsd are populated. Here "3.57" means +3.57%. Percentages are full-precision decimal strings expressed as a percent.

Closing a proposal

POST /api/v1/predictions/proposals/{id}/close is creator-only. It sells the creator’s entire position and moves the proposal into a sell-only (CLOSED) state so members can exit but not add. If there was nothing to sell, trade is null.
curl -X POST "$MURMO_BASE/api/v1/predictions/proposals/f0c1...e9/close" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Response
{
  "data": {
    "proposal": { "id": "f0c1...e9", "status": "CLOSED", "result": null, "didWin": null },
    "trade": {
      "id": "trd_004",
      "tradeType": "SELL",
      "totalCostUsd": "12.04",
      "pnlPct": "0.33",
      "pnlUsd": "0.04"
    }
  }
}

Claiming winnings

When the market resolves, the proposal’s status becomes RESOLVED, result is set, and didWin tells you the outcome. On a winning position, POST /api/v1/predictions/proposals/{id}/claim redeems your winning outcome tokens (each worth $1) for USDC.
curl -X POST "$MURMO_BASE/api/v1/predictions/proposals/f0c1...e9/claim" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Response
{
  "data": {
    "trade": {
      "id": "trd_005",
      "proposalId": "f0c1...e9",
      "tradeType": "CLAIM",
      "tokenAmount": "21.857142",
      "tokenDecimals": 6,
      "pricePerTokenUsd": "1",
      "totalCostUsd": "21.857142",
      "pnlPct": "78.57",
      "pnlUsd": "9.61",
      "txSignature": "7eF...sig"
    },
    "amountClaimedUsd": "21.857142"
  }
}
The claim response carries the trade plus a top-level amountClaimedUsd — the USD redeemed as a full-precision decimal string. On a CLAIM, pricePerTokenUsd is "1" (winning tokens settle at one dollar each).

Reading proposals and positions

These reads are members-only: a non-member gets 403 NOT_GROUP_MEMBER.

List a group’s proposals

GET /api/v1/predictions/proposals?groupId=... returns the group’s prediction proposals, each with your position. Optional status filter — one of ACTIVE, CLOSED, or RESOLVED (unknown values are 400). data is an array of PredictionWithPosition.
curl "$MURMO_BASE/api/v1/predictions/proposals?groupId=1a9d212a-...&status=ACTIVE" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Each PredictionWithPosition item:
FieldTypeNotes
proposalPredictionProposalThe proposal metadata.
marketobject | nullThe Kalshi-native market (dollar strings); null if unavailable.
userPositionPredictionPositionYour stake on this proposal.
remainingTokenAmountstring | nullYour per-proposal FIFO remaining outcome tokens, humanized.
createdByUserRefWho created the proposal.

One proposal’s detail

GET /api/v1/predictions/proposals/{id} returns { proposal, position }. position is null when you hold nothing on this proposal. A non-member gets 403; an unknown ID gets 404.
curl "$MURMO_BASE/api/v1/predictions/proposals/f0c1...e9" \
  -H "Authorization: Bearer $MURMO_API_KEY"
Response
{
  "data": {
    "proposal": { "id": "f0c1...e9", "isYes": true, "status": "ACTIVE", "marketTitle": "Kansas City" },
    "position": {
      "tokenAmount": "26.785713",
      "tokenDecimals": 6,
      "totalCostUsd": "15",
      "avgCostBasisUsd": "0.56",
      "unrealizedPnlPct": "3.57",
      "unrealizedPnlUsd": "0.5357",
      "currentValueUsd": "15.5357",
      "currentPriceUsd": "0.58"
    }
  }
}
The list endpoint nests your stake under userPosition, while the single-proposal detail endpoint nests it under position (and it’s null when you hold nothing). Both are the same PredictionPosition shape.

Field reference

PredictionProposal

FieldTypeNotes
idstringProposal ID.
groupIdstringGroup the proposal belongs to.
createdByIdstringCreator (a group leader).
eventIdstringKalshi event ticker.
marketIdstringKalshi market ID (the chosen outcome).
outcomeMintstringThe YES/NO outcome token mint, resolved server-side.
eventTitlestring | nullResolved event title.
marketTitlestring | nullResolved market/outcome title.
eventImageUrlstring | nullEvent image URL.
isYesbooleantrue = YES side, false = NO side.
statusstringACTIVE, CLOSED, or RESOLVED.
resultstring | nullResolution outcome once settled (e.g. YES, NO, INVALID, CANCELLED).
didWinboolean | nullnull until resolved; true won, false lost.
reasonstring | nullOptional note from the creator.
resolvedAtdate-time | nullWhen it resolved.
createdAt / updatedAtdate-timeTimestamps.

PredictionTrade

FieldTypeNotes
idstringTrade ID.
proposalIdstringParent proposal.
groupIdstringGroup ID.
walletAddressstringWallet the trade executed from.
tradeTypestringBUY, SELL, CLAIM, or LOST.
tokenAmountDecimalStringOutcome tokens, humanized with tokenDecimals (not raw).
tokenDecimalsintegerDecimals for the outcome token.
pricePerTokenUsdMoneyStringPer-token price in USD. "1" on a CLAIM.
totalCostUsdMoneyStringUSD value of the trade.
pnlPctDecimalString | nullPercent PnL (null on opening BUYs).
pnlUsdMoneyString | nullUSD PnL (null on opening BUYs).
txSignaturestring | nullOn-chain signature, when present.
createdAtdate-timeWhen the trade executed.

PredictionPosition

Your stake on a proposal. Every ...Usd value is a MoneyString; every percent is a DecimalString; all are nullable.
FieldTypeNotes
tokenAmountDecimalStringOutcome tokens held (humanized).
tokenDecimalsintegerDecimals for the outcome token.
totalCostUsdMoneyString | nullTotal cost basis in USD.
avgCostBasisUsdMoneyString | nullAverage entry price per token.
avgExitPriceUsdMoneyString | nullAverage realized exit price.
unrealizedPnlPct / unrealizedPnlUsdDecimalString / MoneyString | nullOpen PnL.
realizedPnlPct / realizedPnlUsdDecimalString / MoneyString | nullClosed PnL.
currentValueUsdMoneyString | nullMark-to-market value now.
currentPriceUsdMoneyString | nullCurrent per-token price.

Errors you’ll see

StatusWhen
400Missing required field (q, seriesTicker, groupId, amountUsd), non-boolean isYes, bad money string, or unknown status value.
401Missing or invalid API key.
403Not a member of the group (NOT_GROUP_MEMBER), not a leader on create, not the creator on close, or product not available for your account/region.
404Proposal ID not found.
Business errors carry a stable code (e.g. NOT_GROUP_MEMBER, NO_MARKET_PRICE, MARKET_MAINTENANCE). See Errors for the two error shapes and full handling.

Where to next

Money & precision

Why every amount is a decimal string, and how to parse it.

Groups & proposals

The shared social model behind every proposal.

Errors

The two error shapes and stable codes.

API Reference

Every Predictions endpoint, parameter, and schema.