Quickstart

This guide walks you through trading Kalshi prediction market positions using Bebop API. An API key and basic understanding of EVM wallets and token approvals is required.

1

Discovering Available Markets

You can get the list of supported markets by querying Bebop API on Base:

curl -X GET "https://api.bebop.xyz/prediction/base/v1/events"

Response

{
  "events": [
   {
      "ticker": "KXLLM1-25DEC31",
      "markets": [
        {
          "ticker": "KXLLM1-25DEC31-GOOG",
          "yes_token_address": "0xbffd09A68059A40Aa738FA77698d2f62EA7F10cb",
          "no_token_address": "0xB097564D3f9d59BD42a468833b7EB5b3815EF0FE"
        },
        {
          "ticker": "KXLLM1-25DEC31-OAI",
          "yes_token_address": "0xee5D2513a8629ee880FeACa24eEabd3B4409a5B7",
          "no_token_address": "0x31aa33Cf8D2A45b3398A457703f59Adc4354aF98"
        },
        {
          "ticker": "KXLLM1-25DEC31-XAI",
          "yes_token_address": "0x241166f441e1b076F7Ae9F907A81524964F45b51",
          "no_token_address": "0x7cBaE26090f42E71A39964645aE61392745C0B5f"
        }
      ]
    },
  ]
}

For complete market details, rules and resolution criteria, please refer to the Kalshi API directly:

curl -X GET "https://api.elections.kalshi.com/trade-api/v2/markets/KXLLM1-25DEC31-GOOG"

Response (abridged for brevity)

{
  "market": {
    "ticker": "KXLLM1-25DEC31-GOOG",
    "title": "Best AI at year end?",
    "custom_strike": {
      "Organization": "Google"
    },
    "event_ticker": "KXLLM1-25DEC31",
    "expected_expiration_time": "2025-12-31T15:00:00Z",
    "last_price": 89,
    "last_price_dollars": "0.8900",
    "latest_expiration_time": "2026-01-31T15:00:00Z",
    "liquidity": 25644820,
    "liquidity_dollars": "256448.2000",
    "market_type": "binary",
    "rules_primary": "If Google has the top-ranked LLM on Dec 31, 2025, then the market resolves to Yes.",
    "rules_secondary": "If two models are tied under Rank (UB), then all the strikes for this market will resolve to No. This event is not affected by the amendment that is effective in April 2025.",
    "settlement_timer_seconds": 3600,
    "strike_type": "custom",
    "subtitle": "Gemini:: Google",
    ...
  }
}
2

Opening a Position

Each market is represented by two or more ERC-20 tokens on Base (i.e., one per outcome), for example:

Market: Best AI at the end of 2025 - Google Gemini? (event link)

Position
Token Address
Link

Under the hood, buying a position involves swapping USDC ( 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 on Base) for the corresponding outcome token. The /quote endpoint abstracts all of this — just request what you need, and we return a ready-to-sign order.

Request a Quote

To invest 10 USDC in YES contracts (i.e., betting GOOG will be best LLM):


curl -X GET "https://api.bebop.xyz/prediction/base/v1/quote" \
  -G \
  --data-urlencode "market=KXLLM1-25DEC31-GOOG" \
  --data-urlencode "action=buy" \
  --data-urlencode "side=yes" \
  --data-urlencode "taker=<your wallet address>" \
  --data-urlencode "tokens=10" \
  --data-urlencode "quoteToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" \
  --data-urlencode "apiKey=<your api key>"

Prefer dealing in contracts? Use the contracts parameter instead of tokens, whole numbers only.

Quote Response

{
  "quoteId": "9bac05c2-4974-4d04-9bd6-9723e678c2c8",
  "requestId": "0cf5d553-8261-42d5-b4ef-74d4a9256a1b",
  "action": "buy",
  "side": "yes",
  "taker": "<your wallet address>",
  "marketToken": "0xbffd09A68059A40Aa738FA77698d2f62EA7F10cb",
  "quoteToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "price": "0.9091",
  "request": {
    "type": "tokens",
    "amount": "10"
  },
  "quote": {
    "contracts": "11",
    "contractsMin": "10.67"
  },
  "toSign": {
    "permitted": [
      {
        "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "amount": "10000000"
      }
    ],
    "spender": "0xC5a350853E4e36b73EB0C24aaA4b8816C9A3579a",
    "nonce": "206923531211374501497099925755897889480",
    "deadline": 1764944094,
    "witness": {
      "taker": "<your wallet address>",
      "receiver": "<your wallet address>",
      "expiry": 1764944094,
      "exclusivityDeadline": 1764944094,
      "nonce": "206923531211374501497099925755897889480",
      "executor": "0x34CFAC845AfB89d62d0937931b1C9d54618e8303",
      "partnerInfo": "0",
      "sellTokens": [
        "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
      ],
      "buyTokens": [
        "0xbffd09A68059A40Aa738FA77698d2f62EA7F10cb"
      ],
      "sellAmounts": [
        "10000000"
      ],
      "buyAmounts": [
        "10670000000000000000"
      ],
      "hooksHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
    }
  },
  "gbop": "😎"
}

  • quoteId - Include this when submitting your signed order or monitoring the settlement process

  • price - Current price of the requested option

  • quote.contracts /quote.contractsMin - How many requested contracts you will get for the set sell amount of USDC, and expected number of contracts after 3% slippage (round down, 10.67 to 10.00)

  • toSign - Key transaction information you are signing, with amounts and settlement instructions

  • toSign.witness.expiry - Unix timestamp; order invalid after this time

  • toSign.spender - Contract that needs token approval, Bebop's Balance Manager.

3

Token Approval

Bebop prediction market orders utilise permit2 for approvals.

Before submitting your order, you need to ensure that the Permit2 Contract has sufficient approvals for the token you are trading.

The message signed (toSign in the quote response) gives a permit to the Bebop Balance Manager which is a dedicated contract that uses your token approvals. It only grants the settlement contract access to your funds for the duration of each transaction - your approval is never exposed directly to the settlement logic.

Check Existing Allowance

Coming Soon - Code samples for checking ERC-20 allowances. If you're familiar with standard token approvals, query allowance(owner, spender) where spender is the approvalTarget from the quote response.

Approve if Needed

Coming Soon - Code samples for approving the Balance Manager. Use the standard ERC-20 approve(spender, amount)pattern with the approvalTarget address.

4

Signing and Submitting the Order

Sign the Order

The toSign object from the quote response must be signed using EIP-712 typed data. Currently, only Permit2 approval is supported.

Coming Soon - Code samples for EIP-712 signing. The toSign object contains a JamOrder struct — sign it with your wallet using the settlementAddress as the verifying contract. In the meantime, check out this tutorial.

Submit the Order

curl -X POST "https://api.bebop.xyz/prediction/base/v1/order" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteId": "9bac05c2-4974-4d04-9bd6-9723e678c2c8",
    "signature": "0xYourSignature..."
  }'

Order Response

{
    "status": "Pending",
    "txHash": null
}

Check Order Status

curl "https://api.bebop.xyz/prediction/base/v1/order-status?quoteId=9bac05c2-4974-4d04-9bd6-9723e678c2c8"

Order Statuses:

Status
Description

Pending

Order submitted, awaiting execution

Success

Order executed successfully

Failed

Order execution failed

5

Closing a Position

To exit before resolution, sell your position tokens back using the same flow, just use sell action.

6

Resolution

When a market resolves:

  • winning position (e.g., you hold YES tokens and the outcome is YES), your tokens are burned and you receive 1 USDC per token

  • losing position, the tokens expire with no payout.

7

Important Notes

Whole Contracts Only

Prediction market positions can only be traded in whole contract units. Fractional contracts are not supported.

Since you specify the tokens parameter (i.e., how much USDC to spend), Bebop calculates the maximum whole contacts you can buy and returns the change, for example:

  • You spend: 10 USDC

  • Price per contract: 0.47 USDC

  • Maximum possible: 21.27 contracts → rounded down to 21 contracts

  • Actual cost: 21 × 0.47 = 9.87 USDC

  • Change returned: 10 - 9.87 = 0.13 USDC

Quote Expiry

Quotes have a limited validity window (check the expiry field in the quote response). If you don't submit before expiry, request a fresh quote.

To ensure the highest possible fill rate, we recommend to update quotes every 5-15 seconds.

Slippage

By default, slippage equals to 3%.

Gasless Execution

All orders are executed gaslessly.

8

End-to-end Example

Coming Soon - A full end-to-end code sample covering quote request, approval, signing, submission, and status polling.

9

Got it working?

Great! Check out JAM API Reference for more info.

Last updated