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.How a market is identified
You reference a market with three fields. The backend resolveseventTitle, marketTitle, and the outcome mint server-side — you never send those yourself.
| Field | What it is | Example |
|---|---|---|
eventId | The Kalshi event ticker (the matchup or question). | "KXNFLGAME-25SB" |
marketId | The Kalshi market ID — the specific outcome within that event. | "KXNFLGAME-25SB-KC" |
isYes | Side: true buys YES, false buys NO. | true |
The full lifecycle
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.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.Predict more or sell
Add with
POST .../{id}/predict (amountUsd). Trim or exit with POST .../{id}/sell —
amountUsd for an approximate target, or max: true to close your whole position.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.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 optionaltag,page) — when present, switches to the paginated category browse.
Response (shape)
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.Search
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.
Live
GET /api/v1/predictions/events/live — the live sports feed. Optional: limit, cursor, category, subcategory, competition.
Event by ticker
GET /api/v1/predictions/events/{ticker} — one event by its Kalshi ticker, with its markets filtered for liquidity.
Related events
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.
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.
The group to open the proposal in.
The Kalshi event ticker, e.g.
"KXNFLGAME-25SB".The Kalshi market ID for the specific outcome, e.g.
"KXNFLGAME-25SB-KC".true to buy YES, false to buy NO. Must be a boolean, not a string.Opening prediction size as a USD decimal string, e.g.
"10.00".Optional thesis, shown to group members.
Response
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.
Response
Selling (cashing out)
POST /api/v1/predictions/proposals/{id}/sell sells part or all of your position. Send exactly one of:
| Field | Effect |
|---|---|
amountUsd | The desired USDC value to sell. The server converts it to outcome-token amount at the current price and caps it at your position. |
max: true | Sell your entire position on this proposal. When max is true, amountUsd is ignored. |
Response
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.
Response
Claiming winnings
When the market resolves, the proposal’sstatus 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.
Response
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 gets403 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.
PredictionWithPosition item:
| Field | Type | Notes |
|---|---|---|
proposal | PredictionProposal | The proposal metadata. |
market | object | null | The Kalshi-native market (dollar strings); null if unavailable. |
userPosition | PredictionPosition | Your stake on this proposal. |
remainingTokenAmount | string | null | Your per-proposal FIFO remaining outcome tokens, humanized. |
createdBy | UserRef | Who 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.
Response
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
| Field | Type | Notes |
|---|---|---|
id | string | Proposal ID. |
groupId | string | Group the proposal belongs to. |
createdById | string | Creator (a group leader). |
eventId | string | Kalshi event ticker. |
marketId | string | Kalshi market ID (the chosen outcome). |
outcomeMint | string | The YES/NO outcome token mint, resolved server-side. |
eventTitle | string | null | Resolved event title. |
marketTitle | string | null | Resolved market/outcome title. |
eventImageUrl | string | null | Event image URL. |
isYes | boolean | true = YES side, false = NO side. |
status | string | ACTIVE, CLOSED, or RESOLVED. |
result | string | null | Resolution outcome once settled (e.g. YES, NO, INVALID, CANCELLED). |
didWin | boolean | null | null until resolved; true won, false lost. |
reason | string | null | Optional note from the creator. |
resolvedAt | date-time | null | When it resolved. |
createdAt / updatedAt | date-time | Timestamps. |
PredictionTrade
| Field | Type | Notes |
|---|---|---|
id | string | Trade ID. |
proposalId | string | Parent proposal. |
groupId | string | Group ID. |
walletAddress | string | Wallet the trade executed from. |
tradeType | string | BUY, SELL, CLAIM, or LOST. |
tokenAmount | DecimalString | Outcome tokens, humanized with tokenDecimals (not raw). |
tokenDecimals | integer | Decimals for the outcome token. |
pricePerTokenUsd | MoneyString | Per-token price in USD. "1" on a CLAIM. |
totalCostUsd | MoneyString | USD value of the trade. |
pnlPct | DecimalString | null | Percent PnL (null on opening BUYs). |
pnlUsd | MoneyString | null | USD PnL (null on opening BUYs). |
txSignature | string | null | On-chain signature, when present. |
createdAt | date-time | When the trade executed. |
PredictionPosition
Your stake on a proposal. Every ...Usd value is a MoneyString; every percent is a DecimalString; all are nullable.
| Field | Type | Notes |
|---|---|---|
tokenAmount | DecimalString | Outcome tokens held (humanized). |
tokenDecimals | integer | Decimals for the outcome token. |
totalCostUsd | MoneyString | null | Total cost basis in USD. |
avgCostBasisUsd | MoneyString | null | Average entry price per token. |
avgExitPriceUsd | MoneyString | null | Average realized exit price. |
unrealizedPnlPct / unrealizedPnlUsd | DecimalString / MoneyString | null | Open PnL. |
realizedPnlPct / realizedPnlUsd | DecimalString / MoneyString | null | Closed PnL. |
currentValueUsd | MoneyString | null | Mark-to-market value now. |
currentPriceUsd | MoneyString | null | Current per-token price. |
Errors you’ll see
| Status | When |
|---|---|
400 | Missing required field (q, seriesTicker, groupId, amountUsd), non-boolean isYes, bad money string, or unknown status value. |
401 | Missing or invalid API key. |
403 | Not 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. |
404 | Proposal ID not found. |
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.