# Get Account API Limits Source: https://docs.kalshi.com/api-reference/account/get-account-api-limits /openapi.yaml get /account/limits Endpoint to retrieve the API tier limits associated with the authenticated user. # List Non-Default Endpoint Costs Source: https://docs.kalshi.com/api-reference/account/list-non-default-endpoint-costs /openapi.yaml get /account/endpoint_costs Lists API v2 endpoints whose configured token cost differs from the default cost. Endpoints that use the default cost are omitted. # Create API Key Source: https://docs.kalshi.com/api-reference/api-keys/create-api-key /openapi.yaml post /api_keys Endpoint for creating a new API key with a user-provided public key. This endpoint allows users with Premier or Market Maker API usage levels to create API keys by providing their own RSA public key. The platform will use this public key to verify signatures on API requests. # Delete API Key Source: https://docs.kalshi.com/api-reference/api-keys/delete-api-key /openapi.yaml delete /api_keys/{api_key} Endpoint for deleting an existing API key. This endpoint permanently deletes an API key. Once deleted, the key can no longer be used for authentication. This action cannot be undone. # Generate API Key Source: https://docs.kalshi.com/api-reference/api-keys/generate-api-key /openapi.yaml post /api_keys/generate Endpoint for generating a new API key with an automatically created key pair. This endpoint generates both a public and private RSA key pair. The public key is stored on the platform, while the private key is returned to the user and must be stored securely. The private key cannot be retrieved again. # Get API Keys Source: https://docs.kalshi.com/api-reference/api-keys/get-api-keys /openapi.yaml get /api_keys Endpoint for retrieving all API keys associated with the authenticated user. API keys allow programmatic access to the platform without requiring username/password authentication. Each key has a unique identifier and name. # Accept Quote Source: https://docs.kalshi.com/api-reference/communications/accept-quote /openapi.yaml put /communications/quotes/{quote_id}/accept Endpoint for accepting a quote. This will require the quoter to confirm # Confirm Quote Source: https://docs.kalshi.com/api-reference/communications/confirm-quote /openapi.yaml put /communications/quotes/{quote_id}/confirm Endpoint for confirming a quote. This will start a timer for order execution # Create Quote Source: https://docs.kalshi.com/api-reference/communications/create-quote /openapi.yaml post /communications/quotes Endpoint for creating a quote in response to an RFQ **Rate limit:** 2 tokens per request. Other endpoints use the default cost of 10 tokens per request unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Create RFQ Source: https://docs.kalshi.com/api-reference/communications/create-rfq /openapi.yaml post /communications/rfqs Endpoint for creating a new RFQ. You can have a maximum of 100 open RFQs at a time. # Delete Quote Source: https://docs.kalshi.com/api-reference/communications/delete-quote /openapi.yaml delete /communications/quotes/{quote_id} Endpoint for deleting a quote, which means it can no longer be accepted. **Rate limit:** 2 tokens per request. Other endpoints use the default cost of 10 tokens per request unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Delete RFQ Source: https://docs.kalshi.com/api-reference/communications/delete-rfq /openapi.yaml delete /communications/rfqs/{rfq_id} Endpoint for deleting an RFQ by ID # Get Communications ID Source: https://docs.kalshi.com/api-reference/communications/get-communications-id /openapi.yaml get /communications/id Endpoint for getting the communications ID of the logged-in user. # Get Quote Source: https://docs.kalshi.com/api-reference/communications/get-quote /openapi.yaml get /communications/quotes/{quote_id} Endpoint for getting a particular quote # Get Quotes Source: https://docs.kalshi.com/api-reference/communications/get-quotes /openapi.yaml get /communications/quotes Endpoint for getting quotes # Get RFQ Source: https://docs.kalshi.com/api-reference/communications/get-rfq /openapi.yaml get /communications/rfqs/{rfq_id} Endpoint for getting a single RFQ by id # Get RFQs Source: https://docs.kalshi.com/api-reference/communications/get-rfqs /openapi.yaml get /communications/rfqs Endpoint for getting RFQs # Get Event Source: https://docs.kalshi.com/api-reference/events/get-event /openapi.yaml get /events/{event_ticker} Endpoint for getting data about an event by its ticker. An event represents a real-world occurrence that can be traded on, such as an election, sports game, or economic indicator release. Events contain one or more markets where users can place trades on different outcomes. All events are accessible through this endpoint, even if their associated markets are older than the historical cutoff. # Get Event Candlesticks Source: https://docs.kalshi.com/api-reference/events/get-event-candlesticks /openapi.yaml get /series/{series_ticker}/events/{ticker}/candlesticks End-point for returning aggregated data across all markets corresponding to an event. # Get Event Forecast Percentile History Source: https://docs.kalshi.com/api-reference/events/get-event-forecast-percentile-history /openapi.yaml get /series/{series_ticker}/events/{ticker}/forecast_percentile_history Endpoint for getting the historical raw and formatted forecast numbers for an event at specific percentiles. # Get Event Metadata Source: https://docs.kalshi.com/api-reference/events/get-event-metadata /openapi.yaml get /events/{event_ticker}/metadata Endpoint for getting metadata about an event by its ticker. Returns only the metadata information for an event. # Get Events Source: https://docs.kalshi.com/api-reference/events/get-events /openapi.yaml get /events Get all events. This endpoint excludes multivariate events. To retrieve multivariate events, use the GET /events/multivariate endpoint. All events are accessible through this endpoint, even if their associated markets are older than the historical cutoff. # Get Multivariate Events Source: https://docs.kalshi.com/api-reference/events/get-multivariate-events /openapi.yaml get /events/multivariate Retrieve multivariate (combo) events. These are dynamically created events from multivariate event collections. Supports filtering by series and collection ticker. # Get Exchange Announcements Source: https://docs.kalshi.com/api-reference/exchange/get-exchange-announcements /openapi.yaml get /exchange/announcements Endpoint for getting all exchange-wide announcements. # Get Exchange Schedule Source: https://docs.kalshi.com/api-reference/exchange/get-exchange-schedule /openapi.yaml get /exchange/schedule Endpoint for getting the exchange schedule. # Get Exchange Status Source: https://docs.kalshi.com/api-reference/exchange/get-exchange-status /openapi.yaml get /exchange/status Endpoint for getting the exchange status. # Get Series Fee Changes Source: https://docs.kalshi.com/api-reference/exchange/get-series-fee-changes /openapi.yaml get /series/fee_changes # Get User Data Timestamp Source: https://docs.kalshi.com/api-reference/exchange/get-user-data-timestamp /openapi.yaml get /exchange/user_data_timestamp There is typically a short delay before exchange events are reflected in the API endpoints. Whenever possible, combine API responses to PUT/POST/DELETE requests with websocket data to obtain the most accurate view of the exchange state. This endpoint provides an approximate indication of when the data from the following endpoints was last validated: GetBalance, GetOrder(s), GetFills, GetPositions # Get FCM Orders Source: https://docs.kalshi.com/api-reference/fcm/get-fcm-orders /openapi.yaml get /fcm/orders Endpoint for FCM members to get orders filtered by subtrader ID. This endpoint requires FCM member access level and allows filtering orders by subtrader ID. # Get FCM Positions Source: https://docs.kalshi.com/api-reference/fcm/get-fcm-positions /openapi.yaml get /fcm/positions Endpoint for FCM members to get market positions filtered by subtrader ID. This endpoint requires FCM member access level and allows filtering positions by subtrader ID. # Get Historical Cutoff Timestamps Source: https://docs.kalshi.com/api-reference/historical/get-historical-cutoff-timestamps /openapi.yaml get /historical/cutoff Returns the cutoff timestamps that define the boundary between **live** and **historical** data. ## Cutoff fields - `market_settled_ts` : Markets that **settled** before this timestamp, and their candlesticks, must be accessed via `GET /historical/markets` and `GET /historical/markets/{ticker}/candlesticks`. - `trades_created_ts` : Trades that were **filled** before this timestamp must be accessed via `GET /historical/fills`. - `orders_updated_ts` : Orders that were **canceled or fully executed** before this timestamp must be accessed via `GET /historical/orders`. Resting (active) orders are always available in `GET /portfolio/orders`. # Get Historical Fills Source: https://docs.kalshi.com/api-reference/historical/get-historical-fills /openapi.yaml get /historical/fills Endpoint for getting all historical fills for the member. A fill is when a trade you have is matched. # Get Historical Market Source: https://docs.kalshi.com/api-reference/historical/get-historical-market /openapi.yaml get /historical/markets/{ticker} Endpoint for getting data about a specific market by its ticker from the historical database. # Get Historical Market Candlesticks Source: https://docs.kalshi.com/api-reference/historical/get-historical-market-candlesticks /openapi.yaml get /historical/markets/{ticker}/candlesticks Endpoint for fetching historical candlestick data for markets that have been archived from the live data set. Time period length of each candlestick in minutes. Valid values: 1 (1 minute), 60 (1 hour), 1440 (1 day). # Get Historical Markets Source: https://docs.kalshi.com/api-reference/historical/get-historical-markets /openapi.yaml get /historical/markets Endpoint for getting markets that have been archived to the historical database. Filters are mutually exclusive. # Get Historical Orders Source: https://docs.kalshi.com/api-reference/historical/get-historical-orders /openapi.yaml get /historical/orders Endpoint for getting orders that have been archived to the historical database. # Get Historical Trades Source: https://docs.kalshi.com/api-reference/historical/get-historical-trades /openapi.yaml get /historical/trades Endpoint for getting all historical trades for all markets. Trades that were filled before the historical cutoff are available via this endpoint. See [Historical Data](https://docs.kalshi.com/getting_started/historical_data) for details. # Get Incentives Source: https://docs.kalshi.com/api-reference/incentive-programs/get-incentives /openapi.yaml get /incentive_programs List incentives with optional filters. Incentives are rewards programs for trading activity on specific markets. # Get Game Stats Source: https://docs.kalshi.com/api-reference/live-data/get-game-stats /openapi.yaml get /live_data/milestone/{milestone_id}/game_stats Get play-by-play game statistics for a specific milestone. Supported sports: Pro Football, College Football, Pro Basketball, College Men's Basketball, College Women's Basketball, WNBA, Soccer, Pro Hockey, and Pro Baseball. Returns null for unsupported milestone types or milestones without a Sportradar ID. # Get Live Data Source: https://docs.kalshi.com/api-reference/live-data/get-live-data /openapi.yaml get /live_data/milestone/{milestone_id} Get live data for a specific milestone. # Get Live Data (with type) Source: https://docs.kalshi.com/api-reference/live-data/get-live-data-with-type /openapi.yaml get /live_data/{type}/milestone/{milestone_id} Get live data for a specific milestone. This is the legacy endpoint that requires a type path parameter. Prefer using `/live_data/milestone/{milestone_id}` instead. # Get Multiple Live Data Source: https://docs.kalshi.com/api-reference/live-data/get-multiple-live-data /openapi.yaml get /live_data/batch Get live data for multiple milestones # Batch Get Market Candlesticks Source: https://docs.kalshi.com/api-reference/market/batch-get-market-candlesticks /openapi.yaml get /markets/candlesticks Endpoint for retrieving candlestick data for multiple markets. - Accepts up to 100 market tickers per request - Returns up to 10,000 candlesticks total across all markets - Returns candlesticks grouped by market_id - Optionally includes a synthetic initial candlestick for price continuity (see `include_latest_before_start` parameter) # Get Market Source: https://docs.kalshi.com/api-reference/market/get-market /openapi.yaml get /markets/{ticker} Endpoint for getting data about a specific market by its ticker. A market represents a specific binary outcome within an event that users can trade on (e.g., "Will candidate X win?"). Markets have yes/no positions, current prices, volume, and settlement rules. # Get Market Candlesticks Source: https://docs.kalshi.com/api-reference/market/get-market-candlesticks /openapi.yaml get /series/{series_ticker}/markets/{ticker}/candlesticks Time period length of each candlestick in minutes. Valid values: 1 (1 minute), 60 (1 hour), 1440 (1 day). Candlesticks for markets that settled before the historical cutoff are only available via `GET /historical/markets/{ticker}/candlesticks`. See [Historical Data](https://docs.kalshi.com/getting_started/historical_data) for details. # Get Market Orderbook Source: https://docs.kalshi.com/api-reference/market/get-market-orderbook /openapi.yaml get /markets/{ticker}/orderbook Endpoint for getting the current order book for a specific market. The order book shows all active bid orders for both yes and no sides of a binary market. It returns yes bids and no bids only (no asks are returned). This is because in binary markets, a bid for yes at price X is equivalent to an ask for no at price (100-X). For example, a yes bid at 7¢ is the same as a no ask at 93¢, with identical contract sizes. Each side shows price levels with their corresponding quantities and order counts, organized from best to worst prices. # Get Markets Source: https://docs.kalshi.com/api-reference/market/get-markets /openapi.yaml get /markets Filter by market status. Possible values: `unopened`, `open`, `closed`, `settled`. Leave empty to return markets with any status. - Only one `status` filter may be supplied at a time. - Timestamp filters will be mutually exclusive from other timestamp filters and certain status filters. | Compatible Timestamp Filters | Additional Status Filters| Extra Notes | |------------------------------|--------------------------|-------------| | min_created_ts, max_created_ts | `unopened`, `open`, *empty* | | | min_close_ts, max_close_ts | `closed`, *empty* | | | min_settled_ts, max_settled_ts | `settled`, *empty* | | | min_updated_ts | *empty* | Incompatible with all filters besides `mve_filter=exclude` | Markets that settled before the historical cutoff are only available via `GET /historical/markets`. See [Historical Data](https://docs.kalshi.com/getting_started/historical_data) for details. # Get Multiple Market Orderbooks Source: https://docs.kalshi.com/api-reference/market/get-multiple-market-orderbooks /openapi.yaml get /markets/orderbooks Endpoint for getting the current order books for multiple markets in a single request. The order book shows all active bid orders for both yes and no sides of a binary market. It returns yes bids and no bids only (no asks are returned). This is because in binary markets, a bid for yes at price X is equivalent to an ask for no at price (100-X). For example, a yes bid at 7¢ is the same as a no ask at 93¢, with identical contract sizes. Each side shows price levels with their corresponding quantities and order counts, organized from best to worst prices. Returns one orderbook per requested market ticker. # Get Series Source: https://docs.kalshi.com/api-reference/market/get-series /openapi.yaml get /series/{series_ticker} Endpoint for getting data about a specific series by its ticker. A series represents a template for recurring events that follow the same format and rules (e.g., "Monthly Jobs Report", "Weekly Initial Jobless Claims", "Daily Weather in NYC"). Series define the structure, settlement sources, and metadata that will be applied to each recurring event instance within that series. # Get Series List Source: https://docs.kalshi.com/api-reference/market/get-series-list /openapi.yaml get /series Endpoint for getting data about multiple series with specified filters. A series represents a template for recurring events that follow the same format and rules (e.g., "Monthly Jobs Report", "Weekly Initial Jobless Claims", "Daily Weather in NYC"). This endpoint allows you to browse and discover available series templates by category. # Get Trades Source: https://docs.kalshi.com/api-reference/market/get-trades /openapi.yaml get /markets/trades Endpoint for getting all trades for all markets. A trade represents a completed transaction between two users on a specific market. Each trade includes the market ticker, price, quantity, and timestamp information. This endpoint returns a paginated response. Use the 'limit' parameter to control page size (1-1000, defaults to 100). The response includes a 'cursor' field - pass this value in the 'cursor' parameter of your next request to get the next page. An empty cursor indicates no more pages are available. # Get Milestone Source: https://docs.kalshi.com/api-reference/milestone/get-milestone /openapi.yaml get /milestones/{milestone_id} Endpoint for getting data about a specific milestone by its ID. # Get Milestones Source: https://docs.kalshi.com/api-reference/milestone/get-milestones /openapi.yaml get /milestones Minimum start date to filter milestones. Format: RFC3339 timestamp # Create Market In Multivariate Event Collection Source: https://docs.kalshi.com/api-reference/multivariate/create-market-in-multivariate-event-collection /openapi.yaml post /multivariate_event_collections/{collection_ticker} Endpoint for creating an individual market in a multivariate event collection. This endpoint must be hit at least once before trading or looking up a market. Users are limited to 5000 creations per week. # Get Multivariate Event Collection Source: https://docs.kalshi.com/api-reference/multivariate/get-multivariate-event-collection /openapi.yaml get /multivariate_event_collections/{collection_ticker} Endpoint for getting data about a multivariate event collection by its ticker. # Get Multivariate Event Collection Lookup History Source: https://docs.kalshi.com/api-reference/multivariate/get-multivariate-event-collection-lookup-history /openapi.yaml get /multivariate_event_collections/{collection_ticker}/lookup DEPRECATED: This endpoint predates RFQs and should not be used for new integrations. Endpoint for retrieving which markets in an event collection were recently looked up. This endpoint is deprecated and predates RFQs. Do not use it for new integrations. # Get Multivariate Event Collections Source: https://docs.kalshi.com/api-reference/multivariate/get-multivariate-event-collections /openapi.yaml get /multivariate_event_collections Endpoint for getting data about multivariate event collections. # Lookup Tickers For Market In Multivariate Event Collection Source: https://docs.kalshi.com/api-reference/multivariate/lookup-tickers-for-market-in-multivariate-event-collection /openapi.yaml put /multivariate_event_collections/{collection_ticker}/lookup DEPRECATED: This endpoint predates RFQs and should not be used for new integrations. Endpoint for looking up an individual market in a multivariate event collection. If CreateMarketInMultivariateEventCollection has never been hit with that variable combination before, this will return a 404. This endpoint is deprecated and predates RFQs. Do not use it for new integrations. **Rate limit:** 2 tokens per request. Other endpoints use the default cost of 10 tokens per request unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Create Order Group Source: https://docs.kalshi.com/api-reference/order-groups/create-order-group /openapi.yaml post /portfolio/order_groups/create Creates a new order group with a contracts limit measured over a rolling 15-second window. When the limit is hit, all orders in the group are cancelled and no new orders can be placed until reset. # Delete Order Group Source: https://docs.kalshi.com/api-reference/order-groups/delete-order-group /openapi.yaml delete /portfolio/order_groups/{order_group_id} Deletes an order group and cancels all orders within it. This permanently removes the group. # Get Order Group Source: https://docs.kalshi.com/api-reference/order-groups/get-order-group /openapi.yaml get /portfolio/order_groups/{order_group_id} Retrieves details for a single order group including all order IDs and auto-cancel status. # Get Order Groups Source: https://docs.kalshi.com/api-reference/order-groups/get-order-groups /openapi.yaml get /portfolio/order_groups Retrieves all order groups for the authenticated user. # Reset Order Group Source: https://docs.kalshi.com/api-reference/order-groups/reset-order-group /openapi.yaml put /portfolio/order_groups/{order_group_id}/reset Resets the order group's matched contracts counter to zero, allowing new orders to be placed again after the limit was hit. # Trigger Order Group Source: https://docs.kalshi.com/api-reference/order-groups/trigger-order-group /openapi.yaml put /portfolio/order_groups/{order_group_id}/trigger Triggers the order group, canceling all orders in the group and preventing new orders until the group is reset. # Update Order Group Limit Source: https://docs.kalshi.com/api-reference/order-groups/update-order-group-limit /openapi.yaml put /portfolio/order_groups/{order_group_id}/limit Updates the order group contracts limit (rolling 15-second window). If the updated limit would immediately trigger the group, all orders in the group are canceled and the group is triggered. # Amend Order Source: https://docs.kalshi.com/api-reference/orders/amend-order /openapi.yaml post /portfolio/orders/{order_id}/amend Endpoint for amending the max number of fillable contracts and/or price in an existing order. Max fillable contracts is `remaining_count` + `fill_count`. # Amend Order (V2) Source: https://docs.kalshi.com/api-reference/orders/amend-order-v2 /openapi.yaml post /portfolio/events/orders/{order_id}/amend Endpoint for amending the price and/or max fillable count of an existing event-market order using the V2 request/response shape. The request `count` is the updated total/max fillable count, equal to already filled count plus desired resting remaining count. This behavior matches the v1 amend endpoints; only the request/response shape differs. # Batch Cancel Orders Source: https://docs.kalshi.com/api-reference/orders/batch-cancel-orders /openapi.yaml delete /portfolio/orders/batched Endpoint for cancelling a batch of orders. The maximum batch size scales with your tier's write budget — see [Rate Limits and Tiers](/getting_started/rate_limits). **Rate limit:** 2 tokens per order in the batch — billed per item, so total cost for a batch of N cancels is N × 2. Other endpoints cost 10 tokens per request unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Batch Cancel Orders (V2) Source: https://docs.kalshi.com/api-reference/orders/batch-cancel-orders-v2 /openapi.yaml delete /portfolio/events/orders/batched Endpoint for cancelling a batch of event-market orders using the V2 response shape. The maximum batch size scales with your tier's write budget — see [Rate Limits and Tiers](/getting_started/rate_limits). **Rate limit:** 2 tokens per order in the batch — billed per item, so total cost for a batch of N cancels is N × 2. Other endpoints cost 10 tokens per request unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Batch Create Orders Source: https://docs.kalshi.com/api-reference/orders/batch-create-orders /openapi.yaml post /portfolio/orders/batched Endpoint for submitting a batch of orders. The maximum batch size scales with your tier's write budget — see [Rate Limits and Tiers](/getting_started/rate_limits). **Rate limit:** 10 tokens per order in the batch — billed per item, so total cost for a batch of N orders is N × 10. Other endpoints cost 10 tokens per request (not per item) unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Batch Create Orders (V2) Source: https://docs.kalshi.com/api-reference/orders/batch-create-orders-v2 /openapi.yaml post /portfolio/events/orders/batched Endpoint for submitting a batch of event-market orders using the V2 request/response shape. The maximum batch size scales with your tier's write budget — see [Rate Limits and Tiers](/getting_started/rate_limits). **Rate limit:** 10 tokens per order in the batch — billed per item, so total cost for a batch of N orders is N × 10. Other endpoints cost 10 tokens per request (not per item) unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Cancel Order Source: https://docs.kalshi.com/api-reference/orders/cancel-order /openapi.yaml delete /portfolio/orders/{order_id} Endpoint for canceling orders. The value for the orderId should match the id field of the order you want to decrease. Commonly, DELETE-type endpoints return 204 status with no body content on success. But we can't completely delete the order, as it may be partially filled already. Instead, the DeleteOrder endpoint reduce the order completely, essentially zeroing the remaining resting contracts on it. The zeroed order is returned on the response payload as a form of validation for the client. **Rate limit:** 2 tokens per request. Other endpoints use the default cost of 10 tokens per request unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Cancel Order (V2) Source: https://docs.kalshi.com/api-reference/orders/cancel-order-v2 /openapi.yaml delete /portfolio/events/orders/{order_id} Endpoint for cancelling event-market orders using the V2 response shape. Returns `{order_id, client_order_id, reduced_by}` rather than a full order object. # Create Order Source: https://docs.kalshi.com/api-reference/orders/create-order /openapi.yaml post /portfolio/orders Endpoint for submitting orders in a market. Each user is limited to 200 000 open orders at a time. # Create Order (V2) Source: https://docs.kalshi.com/api-reference/orders/create-order-v2 /openapi.yaml post /portfolio/events/orders Endpoint for submitting event-market orders using the V2 request/response shape (single-book `bid`/`ask` side and fixed-point dollar prices). The legacy `/portfolio/orders` endpoint will be deprecated no earlier than May 6, 2026 — clients should migrate to this path. # Decrease Order Source: https://docs.kalshi.com/api-reference/orders/decrease-order /openapi.yaml post /portfolio/orders/{order_id}/decrease Endpoint for decreasing the number of contracts in an existing order. This is the only kind of edit available on order quantity. Cancelling an order is equivalent to decreasing an order amount to zero. # Decrease Order (V2) Source: https://docs.kalshi.com/api-reference/orders/decrease-order-v2 /openapi.yaml post /portfolio/events/orders/{order_id}/decrease Endpoint for decreasing the remaining count of an existing event-market order using the V2 request/response shape. Exactly one of `reduce_by` or `reduce_to` must be provided. # Get Order Source: https://docs.kalshi.com/api-reference/orders/get-order /openapi.yaml get /portfolio/orders/{order_id} Endpoint for getting a single order. **Rate limit:** 2 tokens per request. Other endpoints use the default cost of 10 tokens per request unless noted on their own page. See [Rate Limits and Tiers](/getting_started/rate_limits). # Get Order Queue Position Source: https://docs.kalshi.com/api-reference/orders/get-order-queue-position /openapi.yaml get /portfolio/orders/{order_id}/queue_position Endpoint for getting an order's queue position in the order book. This represents the amount of orders that need to be matched before this order receives a partial or full match. Queue position is determined using a price-time priority. # Get Orders Source: https://docs.kalshi.com/api-reference/orders/get-orders /openapi.yaml get /portfolio/orders Restricts the response to orders that have a certain status: resting, canceled, or executed. Orders that have been canceled or fully executed before the historical cutoff are only available via `GET /historical/orders`. Resting orders will always be available through this endpoint. See [Historical Data](https://docs.kalshi.com/getting_started/historical_data) for details. # Get Queue Positions for Orders Source: https://docs.kalshi.com/api-reference/orders/get-queue-positions-for-orders /openapi.yaml get /portfolio/orders/queue_positions Endpoint for getting queue positions for all resting orders. Queue position represents the number of contracts that need to be matched before an order receives a partial or full match, determined using price-time priority. # Create Subaccount Source: https://docs.kalshi.com/api-reference/portfolio/create-subaccount /openapi.yaml post /portfolio/subaccounts Creates a new subaccount for the authenticated user. This endpoint is currently only available to institutions and market makers. Subaccounts are numbered sequentially starting from 1. Maximum 32 subaccounts per user. # Get All Subaccount Balances Source: https://docs.kalshi.com/api-reference/portfolio/get-all-subaccount-balances /openapi.yaml get /portfolio/subaccounts/balances Gets balances for all subaccounts including the primary account. # Get Balance Source: https://docs.kalshi.com/api-reference/portfolio/get-balance /openapi.yaml get /portfolio/balance Endpoint for getting the balance and portfolio value of a member. Both values are returned in cents. # Get Deposits Source: https://docs.kalshi.com/api-reference/portfolio/get-deposits /openapi.yaml get /portfolio/deposits Endpoint for getting the member's deposit history. # Get Fills Source: https://docs.kalshi.com/api-reference/portfolio/get-fills /openapi.yaml get /portfolio/fills Endpoint for getting all fills for the member. A fill is when a trade you have is matched. Fills that occurred before the historical cutoff are only available via `GET /historical/fills`. See [Historical Data](https://docs.kalshi.com/getting_started/historical_data) for details. # Get Positions Source: https://docs.kalshi.com/api-reference/portfolio/get-positions /openapi.yaml get /portfolio/positions Restricts the positions to those with any of following fields with non-zero values, as a comma separated list. The following values are accepted: position, total_traded # Get Settlements Source: https://docs.kalshi.com/api-reference/portfolio/get-settlements /openapi.yaml get /portfolio/settlements Endpoint for getting the member's settlements historical track. # Get Subaccount Netting Source: https://docs.kalshi.com/api-reference/portfolio/get-subaccount-netting /openapi.yaml get /portfolio/subaccounts/netting Gets the netting enabled settings for all subaccounts. # Get Subaccount Transfers Source: https://docs.kalshi.com/api-reference/portfolio/get-subaccount-transfers /openapi.yaml get /portfolio/subaccounts/transfers Gets a paginated list of all transfers between subaccounts for the authenticated user. # Get Total Resting Order Value Source: https://docs.kalshi.com/api-reference/portfolio/get-total-resting-order-value /openapi.yaml get /portfolio/summary/total_resting_order_value Endpoint for getting the total value, in cents, of resting orders. This endpoint is only intended for use by FCM members (rare). Note: If you're uncertain about this endpoint, it likely does not apply to you. # Get Withdrawals Source: https://docs.kalshi.com/api-reference/portfolio/get-withdrawals /openapi.yaml get /portfolio/withdrawals Endpoint for getting the member's withdrawal history. # Transfer Between Subaccounts Source: https://docs.kalshi.com/api-reference/portfolio/transfer-between-subaccounts /openapi.yaml post /portfolio/subaccounts/transfer Transfers funds between the authenticated user's subaccounts. Use 0 for the primary account, or 1-32 for numbered subaccounts. # Update Subaccount Netting Source: https://docs.kalshi.com/api-reference/portfolio/update-subaccount-netting /openapi.yaml put /portfolio/subaccounts/netting Updates the netting enabled setting for a specific subaccount. Use 0 for the primary account, or 1-32 for numbered subaccounts. # Get Filters for Sports Source: https://docs.kalshi.com/api-reference/search/get-filters-for-sports /openapi.yaml get /search/filters_by_sport Retrieve available filters organized by sport. This endpoint returns filtering options available for each sport, including scopes and competitions. It also provides an ordered list of sports for display purposes. # Get Tags for Series Categories Source: https://docs.kalshi.com/api-reference/search/get-tags-for-series-categories /openapi.yaml get /search/tags_by_categories Retrieve tags organized by series categories. This endpoint returns a mapping of series categories to their associated tags, which can be used for filtering and search functionality. # Get Structured Target Source: https://docs.kalshi.com/api-reference/structured-targets/get-structured-target /openapi.yaml get /structured_targets/{structured_target_id} Endpoint for getting data about a specific structured target by its ID. # Get Structured Targets Source: https://docs.kalshi.com/api-reference/structured-targets/get-structured-targets /openapi.yaml get /structured_targets Page size (min: 1, max: 2000) # API Changelog Source: https://docs.kalshi.com/changelog/index Stay updated with API changes and version history You can subscribe to the RSS changelog at `/changelog/rss.xml` if you'd like to stay ahead of breaking changes. This changelog is a work in progress. As always, we welcome any feedback in our Discord #dev channel! ## Recent Updates `POST /trade-api/v2/portfolio/events/orders/{order_id}/decrease` now accepts `reduce_by` (fixed-point contract count) in addition to `reduce_to`. Exactly one of the two must be provided. Subaccount creation now supported for all direct members with advanced API access. The WebSocket docs now include the current public error code list with each code's name, message, description, and user-error classification. WebSocket error code `25` is now returned as `Subscription buffer overflow` when a subscription's event buffer overflows during a message burst. When this happens, subscribe to a smaller subset of data, or ensure that your connection read throughput is optimized. See the [WebSocket error messages](/websockets/websocket-connection#error-messages) section for the full list. Cancelled quotes are now automatically deleted 14 days after cancellation. Previously, only quotes associated with closed RFQs were cleaned up. This applies to all cancelled quotes regardless of their parent RFQ status. Affected endpoint: `GET /communications/quotes`. `GET /trade-api/v2/margin/fee_tiers` now returns `maker_fee_rates` and `taker_fee_rates`. Each is a map from market ticker to the fee rate as a decimal fraction of notional (e.g. `0.0008` = 0.08% = 8 bps). Compute the expected fee directly as `notional * rate`. The previous `maker_fee_tiers` and `taker_fee_tiers` tier-name maps have been removed from the response. **Affected endpoints:** * `GET /trade-api/v2/margin/fee_tiers` The `metadata_updated` event on the `market_lifecycle_v2` websocket channel now includes `yes_sub_title` as a top-level field when a market's yes subtitle changes. **Affected channels:** * `market_lifecycle_v2` `CreateOrderGroup` now returns `subaccount`, the subaccount number that owns the created order group. The value is `0` for the primary account and `1-32` for subaccounts. Affected endpoint: `POST /portfolio/order_groups/create`. Added `rfq_user_filter` to `GetQuotes` for filtering by quotes in response to RFQs created by the authenticated user. Affected endpoint: `GET /communications/quotes`. Order, Fill, and Trade responses now include two new normalized direction fields. Each carries the full directional bit on its own — combining `action` with `side` is no longer required to know what the user is positioned for. The two fields encode the same bit in two vocabularies: `bid` is equivalent to `yes`, `ask` is equivalent to `no`. * `outcome_side` (`yes` | `no`) — the outcome the user profits from. Buy-yes and sell-no produce `yes`; buy-no and sell-yes produce `no`. * `book_side` (`bid` | `ask`) — same bit in book vocabulary. Affected REST responses (`svc-api2`): * `Order` (GetOrders, GetOrder, GetHistoricalOrders, and order-write responses) * `Fill` (GetFills, GetFillsHistorical) * `Trade` (public) — fields are named `taker_outcome_side` and `taker_book_side` to match the existing `taker_side` Affected WebSocket channels (`svc-apiexternal-ws`): * `user_orders` * `fill` * `trade` — `taker_outcome_side` and `taker_book_side` `outcome_side` describes directional exposure only; it does not change the order's price. An order at price `p` with `outcome_side=no` is matched by an order at the same price `p` with `outcome_side=yes` — both parties trade at the same price, just on opposite directions. Existing `action`, `side`, `is_yes`, `purchased_side`, and `taker_side` fields are now marked deprecated. `outcome_side` and `book_side` are the canonical way to determine order/trade direction going forward. The legacy fields **will not be removed before May 28, 2026** — please migrate to the new fields when integrating against these endpoints. See the [Order direction](/getting_started/order_direction) reference page for the full migration table and equivalence rules. Added the dedicated external Trade API hosts to the docs and examples: * Production REST: `https://external-api.kalshi.com/trade-api/v2` * Production WebSocket: `wss://external-api-ws.kalshi.com/trade-api/ws/v2` * Demo REST: `https://external-api.demo.kalshi.co/trade-api/v2` * Demo WebSocket: `wss://external-api-ws.demo.kalshi.co/trade-api/ws/v2` Existing shared hosts remain supported for compatibility. Request signing is unchanged: sign the full request path from the API root, without the hostname or query string. The `market_lifecycle_v2` websocket channel now supports a new event type `metadata_updated`. Initially this will only be triggered by a floor strike update, but may expand to more fields in the future. The message contains the updated `floor_strike` as a top-level field. **Affected channels:** * `market_lifecycle_v2` Added `post_only` as an option when creating a quote. If the quote is marked post-only, it will never take resting orders on the book or be subject to a taker fee: it will be automatically cancelled at the normal execution if it were to match with a resting order. Added `GET /trade-api/v2/portfolio/deposits` and `GET /trade-api/v2/portfolio/withdrawals` endpoints. * Query deposit/withdrawal history for the authenticated user * Cursor-based pagination via `limit` and `cursor` parameters **New endpoints:** * `GET /trade-api/v2/portfolio/deposits` * `GET /trade-api/v2/portfolio/withdrawals` V2 order mutating endpoints now include a `ts_ms` field carrying the matching engine's wall-clock timestamp at which the request was processed, as Unix epoch milliseconds: * `POST /trade-api/v2/portfolio/events/orders` * `DELETE /trade-api/v2/portfolio/events/orders/{order_id}` * `POST /trade-api/v2/portfolio/events/orders/{order_id}/decrease` * `POST /trade-api/v2/portfolio/events/orders/{order_id}/amend` * `POST /trade-api/v2/portfolio/events/orders/batched` * `DELETE /trade-api/v2/portfolio/events/orders/batched` The `order_group_updates` WebSocket channel payload now includes a `ts_ms` field with the same matching-engine timestamp, matching the pattern already used by `trades`, `fill`, `user_orders`, and `orderbook_delta`. Added `user_filter=self` to filter RFQs and quotes by the authenticated user. Existing creator user ID filters remain supported temporarily but are considered deprecated. The deprecated `tick_size` field on Market response objects has been deprecated since **Jan 5, 2026** and will be removed on **May 7, 2026**. Use `price_level_structure` and `price_ranges[].step` to determine each market's valid tick sizes. **Affected responses:** * Market response objects returned by REST API v2 endpoints Beginning Apr 30, 2026, `GET /trade-api/v2/account/limits` returns a nested object per bucket with `refill_rate` (tokens added per second) and `bucket_capacity` (max tokens the bucket can hold). When the bucket has no burst headroom, `bucket_capacity` equals `refill_rate` — i.e. one second of budget. ```json theme={null} { "usage_tier": "advanced", "read": {"refill_rate": 200, "bucket_capacity": 200}, "write": {"refill_rate": 100, "bucket_capacity": 200} } ``` See [Rate Limits and Tiers](/getting_started/rate_limits) for budget semantics. **Affected endpoints:** * `GET /trade-api/v2/account/limits` Added a public endpoint to inspect the routes whose configured token cost differs from the default 10-token cost. The response includes `default_cost` for context and lists only the endpoints that do not use that default cost. **Affected endpoints:** * `GET /trade-api/v2/account/endpoint_costs` Write endpoints now allow brief bursts above your per-second budget — when your client is running below its steady rate, the unused capacity accumulates and can be spent in a single pulse. See [Rate Limits and Tiers](/getting_started/rate_limits) for details. **New endpoints:** * `POST /trade-api/v2/portfolio/events/orders` — create * `DELETE /trade-api/v2/portfolio/events/orders/{order_id}` — cancel * `POST /trade-api/v2/portfolio/events/orders/{order_id}/amend` — amend * `POST /trade-api/v2/portfolio/events/orders/{order_id}/decrease` — decrease * `POST /trade-api/v2/portfolio/events/orders/batched` — batch create * `DELETE /trade-api/v2/portfolio/events/orders/batched` — batch cancel **We recommend all clients switch over.** The existing `/portfolio/orders*` endpoints will be marked deprecated no earlier than **May 21, 2026**. Rate-limit costs on the legacy `/portfolio/orders*` endpoints may also increase starting **May 14, 2026** — migrate to the V2 endpoints to avoid disruption. Rolling out a new token-cost rate-limit system with separate read and write budgets and a new **Paragon** tier. All existing tiers get at least as much headroom as before and no client changes are required. See [Rate Limits and Tiers](/getting_started/rate_limits) for full details. In the coming weeks, single-query read endpoints will be priced below the default cost. Added `get_snapshot` action to `update_subscription` on the `orderbook_delta` WebSocket channel. Sends an `orderbook_snapshot` response for the requested markets without adding them to the subscription or affecting the existing delta stream. ```json theme={null} { "cmd": "update_subscription", "params": { "sids": [456], "market_tickers": ["MARKET-1", "MARKET-2"], "action": "get_snapshot" } } ``` Only `market_tickers` is supported (not `market_ticker`, `market_id`, or `market_ids`). **Affected channel:** * `orderbook_delta` The `fractional_trading_enabled` field on `Market` and `EventChildMarket` responses is deprecated. It no longer carries information: * `Market` and `EventChildMarket` responses now support fractional trading unconditionally — the field is always `true`. The `fractional_trading_updated` event on the `market_lifecycle_v2` WebSocket channel is removed, since the underlying state can no longer change. The `fractional_trading_enabled` field will be removed in a future release after a separate pre-announcement that includes the exact removal date. Clients relying on this field should stop reading it; treat every active market returned by these responses as fractional. Added `occurrence_datetime` to API v2 market responses. This field returns the recorded datetime when the underlying event occurred, when that value is available. **Affected endpoints:** * `GET /trade-api/v2/markets` * `GET /trade-api/v2/markets/:ticker` * `GET /trade-api/v2/events` * `GET /trade-api/v2/events/:event_ticker` Added new millisecond Unix timestamp fields to non-margin WebSocket messages while keeping the existing seconds and RFC3339 timestamp fields unchanged for now. ```diff theme={null} + ticker.ts_ms + trade.ts_ms + fill.ts_ms + orderbook_delta.ts_ms + user_order.created_ts_ms + user_order.last_updated_ts_ms + user_order.expiration_ts_ms ``` The older timestamp fields are now deprecated in the AsyncAPI documentation: ```diff theme={null} - ticker.ts - ticker.time - trade.ts - fill.ts - orderbook_delta.ts - user_order.created_time - user_order.last_update_time - user_order.expiration_time ``` These deprecated fields will be removed in a future API version only after a separate pre-announcement that includes the exact removal date. **Affected WebSocket channels:** * `ticker`: added `ts_ms` * `trade`: added `ts_ms` * `fill`: added `ts_ms` * `orderbook_delta`: added optional `ts_ms` * `user_order`: added `created_ts_ms`, `last_updated_ts_ms`, and `expiration_ts_ms` Added `series_ticker` filtering to `GET /trade-api/v2/historical/markets`. This filter follows the existing historical markets behavior and is mutually exclusive with the other primary historical filters (`tickers`, `event_ticker`, and `mve_filter`). **Affected endpoints:** * `GET /trade-api/v2/historical/markets` Removed `client_order_id` from `GET /portfolio/fills` and `GET /portfolio/fills/historical` responses. **Affected endpoints:** * `GET /trade-api/v2/portfolio/fills` * `GET /trade-api/v2/portfolio/fills/historical` Added `GET /trade-api/v2/markets/orderbooks` endpoint. * Accepts a list of market tickers via `tickers` query parameter (up to 100) * Returns one orderbook per requested ticker **Affected endpoints:** * `GET /trade-api/v2/markets/orderbooks` **Effective April 2, 2026** This release removes the last remaining legacy fields: * Removed `yes_total_cost` and `no_total_cost` (integer cents) from `GET /portfolio/settlements`. Use `yes_total_cost_dollars` and `no_total_cost_dollars`. * Removed `yes_price_fixed` and `no_price_fixed` (string aliases) from `GET /portfolio/fills`. Use `yes_price_dollars` and `no_price_dollars`. * Removed `position_cost`, `realized_pnl`, `fees_paid`, and `position_fee_cost` (integer centi-cents) from the `market_positions` WebSocket channel. Use the `_dollars` equivalents. * The `subaccount` field is now returned on **WebSocket** `quote_accepted` and `quote_executed` messages when the quote or RFQ was placed from a subaccount. * The **REST** `Quote` object now includes `creator_subaccount` and `rfq_creator_subaccount` fields, visible to the respective party. Fixed `GET /markets` and `GET /markets/{ticker}` so `custom_strike["Multivariate Event Ticker"]` returns the actual multivariate event ticker instead of the MVE collection ticker. Added a new `multivariate_market_lifecycle` WebSocket channel for multivariate event (MVE) markets. This channel emits MVE lifecycle messages for: * `created` * `activated` * `deactivated` * `close_date_updated` * `determined` * `settled` The existing `market_lifecycle_v2` channel continues to exclude `KXMVE`-prefixed tickers. **Affected channels:** * `multivariate_market_lifecycle` * `market_lifecycle_v2` * `Trade.created_time` and `MarketPosition.last_updated_ts` are now required in the OpenAPI contract. * Deprecated compatibility fields on `Market` and `Settlement` remain available, but are no longer marked as required. * Fixed schema inconsistencies where `Trade.price` and `EventPosition.resting_orders_count` were listed as required without defined properties. * Added semantic deprecation markers for deprecated fields such as `EventData.category` and `MarketPosition.resting_orders_count`. Two new event types added to the `market_lifecycle_v2` WebSocket channel: * **`fractional_trading_updated`**: emitted when a market's fractional trading setting is changed. Includes `fractional_trading_enabled` (boolean). * **`price_level_structure_updated`**: emitted when a market's price level structure is changed. Includes `price_level_structure` (string, e.g. `"linear_cent"`, `"deci_cent"`, `"tapered_deci_cent"`). Additionally, the `created` event now includes `fractional_trading_enabled` and `price_level_structure` fields. **Affected channel:** * `market_lifecycle_v2` When pulling quotes, two new fields return the computed quote size (measured in contracts) derived from the specified prices and the requested notional size in the RFQ. * The following legacy fields are temporarily restored to allow additional migration time. Their `_dollars` equivalents remain the recommended fields: * `market_positions` WebSocket: `position_cost`, `realized_pnl`, `fees_paid`, `position_fee_cost` * `GET /portfolio/settlements`: `yes_total_cost`, `no_total_cost` * `yes_bid_size_fp` and `yes_ask_size_fp` are now correctly populated on nested market responses (`GET /events/{ticker}`). * `Fill` responses now expose `yes_price_dollars` and `no_price_dollars` to align with the API-wide `_dollars` naming convention. Legacy `yes_price_fixed` and `no_price_fixed` remain available for now but are deprecated. * `GET /portfolio/settlements` now exposes `yes_total_cost_dollars` and `no_total_cost_dollars` in fixed-point dollars. * Legacy settlement cent fields `yes_total_cost` and `no_total_cost` remain available for now because these `_dollars` fields were added late in the fixed-point migration, but clients are recommended to migrate now. See [Fixed-Point Migration](/getting_started/fixed_point_migration) for the recommended field mappings. * Legacy integer count fields (with `_fp` equivalents) and integer cents price fields (with `_dollars` equivalents) will be **removed** from all REST and WebSocket response payloads on **March 12, 2026** * Fractional trading will be enabled on 10 additional markets on **March 12** * Subpenny pricing goes live on 2 markets on **March 9**: `KXGREENLAND-29` (deci\_cent) and `KXGDPNOM-RUS26` (tapered\_deci\_cent) See [Fixed-Point Migration](/getting_started/fixed_point_migration) for details. Selected portfolio response `_dollars` fields now emit up to `6` decimal places, using micro\_cent source values from upstream portfolio protos. **Affected endpoints:** * `GET /portfolio/orders` * `GET /portfolio/orders/{order_id}` * `GET /portfolio/fills` * `GET /portfolio/positions` Added `GET /historical/trades` — a public endpoint for querying all trades archived to the historical database. Supports the same filters as `GET /markets/trades`. Use this endpoint for trades that occurred before the `trades_created_ts` cutoff returned by `GET /historical/cutoff`. See [Historical Data](/getting_started/historical_data) for details. * Added `is_yes` (boolean) to the `user_orders` WebSocket channel * `side` (string `"yes"`/`"no"`) remains available for compatibility * Legacy integer count fields (with `_fp` equivalents) and integer cents price fields (with `_dollars` equivalents) will be removed on **March 12, 2026** * Fractional trading will roll out per-market starting the week of **March 9, 2026**; check `fractional_trading_enabled` on Market responses * On fractional-enabled markets, legacy integer fields may be truncated; migrate to `_fp` and `_dollars` to avoid data loss Docs: [Fixed-Point Migration](/getting_started/fixed_point_migration) and [Fee Rounding](/getting_started/fee_rounding). Market responses now include: * `yes_bid_size_fp`: total contract size of orders to buy yes at the best bid price * `yes_ask_size_fp`: total contract size of orders to sell yes at the best ask price Affected endpoints: * `GET /markets` * `GET /markets/{ticker}` New endpoints for managing netting settings on individual subaccounts: * **`GET /portfolio/subaccounts/netting`**: returns the netting enabled status for all subaccounts * **`PUT /portfolio/subaccounts/netting`**: updates the netting enabled status for a specific subaccount (pass `subaccount_number` and `enabled` in the request body) Use `subaccount_number=0` for the primary account or `1`–`32` for numbered subaccounts. New subaccounts inherit the primary account's netting setting at creation time. Fractional share trading is now available for testing in the demo environment on the following markets: * `KXUCL-26-ARS` * `KXUCL-26-AJA` Legacy fields will be deprecated on `March 5, 2026`: * Integer count fields with an `_fp` equivalent will no longer be returned. See [Fixed-Point Contracts](/getting_started/fixed_point_contracts) for migration details. * Integer cents price fields (e.g., `yes_bid`, `no_ask`, `last_price`) will no longer be returned. Their `_dollars` equivalents are already available. See [Subpenny Pricing](/getting_started/subpenny_pricing) for details. More information will be forthcoming on how fee rounding works with fractional contracts. The `market_lifecycle_v2` WebSocket channel now includes a `settlement_value` field (fixed-point dollar string) on `market_determined` events, indicating the settlement price of the market. Expected release date: `February 26, 2026` `GET /portfolio/balance` now accepts an optional `subaccount` query parameter, consistent with other portfolio endpoints (orders, fills, positions, settlements). * **Omitted or `subaccount=0`**: returns balance and portfolio value for the primary account (default) * **`subaccount=N`**: returns balance and portfolio value for that specific subaccount The `liquidity` and `liquidity_dollars` fields on Market responses are deprecated and will return 0. Affected endpoints: * `GET /markets` * `GET /markets/{ticker}` * `GET /events` * `GET /events/{ticker}` * `GET /events/multivariate` The deprecation timeline for non fixed-point count fields has been pushed back. Fields that have a `_fp` equivalent will continue to be returned via API until at least `February 26, 2026`. See [Fixed-Point Contracts](/getting_started/fixed_point_contracts) for updated migration details. Kalshi now partitions exchange data into **live** and **historical** tiers. Historical data must be accessed via the new historical API endpoints. The `GET /historical/cutoff` endpoint returns the cutoff timestamps that define this boundary. **Cutoff timestamps and what they mean:** * `market_settled_ts` — partitioned by **market settlement time**. Markets and their candlesticks that settled before this timestamp are only available via `GET /historical/markets` and `GET /historical/markets/{ticker}/candlesticks`. * `trades_created_ts` — partitioned by **trade fill time**. Fills that occurred before this timestamp are only available via `GET /historical/fills`. * `orders_updated_ts` — partitioned by **order cancellation or execution time**. Orders canceled or fully executed before this timestamp are only available via `GET /historical/orders`. **Resting (active) orders are unaffected** and always appear in `GET /portfolio/orders`. **New endpoints:** * `GET /historical/cutoff` — returns the market, trade, and order cutoff timestamps * `GET /historical/markets` — settled markets older than the cutoff * `GET /historical/markets/{ticker}` — single historical market by ticker * `GET /historical/markets/{ticker}/candlesticks` — candlestick data for historical markets * `GET /historical/fills` — trade fills older than the cutoff * `GET /historical/orders` — canceled/executed orders older than the cutoff **Impacted live endpoints:** * `GET /markets`, `GET /markets/{ticker}` — settled markets older than `market_settled_ts` will not appear * `GET /events` with `with_nested_markets=true` — nested markets older than `market_settled_ts` will not be included * `GET /series/{series_ticker}/markets/{ticker}/candlesticks`, `GET /markets/candlesticks` — candlestick data is tied to the market; historical markets' candlesticks must be fetched from `GET /historical/markets/{ticker}/candlesticks` * `GET /markets/trades`, `GET /portfolio/fills` — fills older than `trades_created_ts` will not appear * `GET /portfolio/orders` — completed/canceled orders older than `orders_updated_ts` will not appear (resting orders are unaffected) `POST /portfolio/orders` removed `type`; `type=market` is no longer offered. The `market_lifecycle_v2` WebSocket channel no longer emits lifecycle messages for multivariate event (MVE) markets and events. All events and markets with `KXMVE` ticker prefix are now filtered from all lifecycle message types on this channel. **Affected channel:** * `market_lifecycle_v2` The `ticker_v2` WebSocket channel has been removed. This was an undocumented experimental channel intended as a v2 iteration of the ticker channel but was rolled back due to user feedback. Users should continue using the standard `ticker` channel for real-time market updates, which includes top-of-book prices, sizes, and last trade information. **Removed channel:** * `ticker_v2` * `ticker` channel now provides high precision `time` field. * `skip_ticker_ack` subscription-level flag supports skipping market tickers sent in the OK message following a channel update. Market response payloads now include `fractional_trading_enabled` consistently across event and market data surfaces. **Affected endpoints:** * `GET /events` * `GET /events/{event_ticker}` * `GET /markets` * `GET /markets/{ticker}` The `GET /incentive_programs` endpoint now returns a `market_id` field containing the market's unique identifier for each incentive program. **Affected endpoint:** * `GET /incentive_programs` Added `user_orders` WebSocket channel to stream real-time order updates (created, updated, canceled, executed) for the authenticated user. Supports optional `market_tickers` filter and dynamic `update_subscription` commands to add or remove markets. **New channel:** * `user_orders` `GET /portfolio/order_groups` and `GET /portfolio/order_groups/{order_group_id}` now accept an optional `subaccount` query parameter. When provided, results are filtered to that specific subaccount. When omitted, results are returned across all subaccounts. **Affected endpoints:** * `GET /portfolio/order_groups` * `GET /portfolio/order_groups/{order_group_id}` The `POST /communications/rfqs` endpoint now accepts an optional `subaccount` parameter to create RFQs on behalf of a subaccount. The `GET /communications/rfqs` endpoint now accepts an optional `subaccount` query parameter to filter RFQs by subaccount. **Affected endpoints:** * `POST /communications/rfqs` * `GET /communications/rfqs` Order queue position returns `queue_position_fp` representing the quantity of shares preceeeding the given order. Note: the new field is 0-indexed, e.g. the first order in the queue returns `0.00`. Affected endpoints: * `GET /portfolio/orders/queue_positions` * `GET /portfolio/orders/{order_id}/queue_position` The `ticker` and `margin_ticker` WebSocket channels now include top-of-book sizes and last trade size: * `yes_bid_size_fp` / `bid_size_fp` — number of contracts at the best bid price * `yes_ask_size_fp` / `ask_size_fp` — number of contracts at the best ask price * `last_trade_size_fp` — number of contracts in the most recent trade Size changes (even without price changes) now trigger ticker updates. All size fields are fixed-point strings supporting fractional contracts. **Affected channels:** * `ticker` * `margin_ticker` Order responses now include `subaccount_number` (0 for primary, 1-32 for subaccounts) for direct users. **Affected endpoints:** * `GET /portfolio/orders` * `GET /portfolio/orders/{order_id}` The `subaccount` query parameter behavior has been updated for orders, fills, and settlements. When `subaccount` is omitted, results are returned across all subaccounts for the authenticated direct member. When `subaccount` is provided (including `0` for primary), results are filtered to that specific subaccount. **Affected endpoints:** * `GET /portfolio/orders` * `GET /portfolio/fills` * `GET /portfolio/settlements` See [Fixed-Point Contracts](/getting_started/fixed_point_contracts) for updated migration details. Fill WebSocket messages now include `fee_cost` as a fixed-point dollars string. **Affected channel:** * `fill` The following endpoints now accept an optional `subaccount` parameter: **Order operations:** * `DELETE /portfolio/orders/{order_id}` - Cancel order * `POST /portfolio/orders/{order_id}/amend` - Amend order * `POST /portfolio/orders/{order_id}/decrease` - Decrease order **Order group operations:** * `POST /portfolio/order_groups` - Create order group * `PUT /portfolio/order_groups/{order_group_id}/limit` - Update order group limit * `PUT /portfolio/order_groups/{order_group_id}/trigger` - Trigger order group * `DELETE /portfolio/order_groups/{order_group_id}` - Delete order group Batch cancel now supports per-order subaccounts while remaining backwards compatible with the existing `ids` payload. **Batch cancel:** * `POST /portfolio/orders/batched/cancel` * New request shape: `orders: [{ order_id, subaccount? }]` (subaccount defaults to `0`) * Legacy `ids` array is still accepted and maps to subaccount `0` Added `target_cost_dollars` (and `rfq_target_cost_dollars` on quotes) as a fixed-point dollar string to RFQ and Quote responses. The `CreateRFQ` endpoint now accepts `target_cost_dollars` as an alternative to `target_cost_centi_cents`. The `target_cost_centi_cents` and `rfq_target_cost_centi_cents` fields are now deprecated. **Affected endpoints:** * `POST /communications/rfqs` * `GET /communications/rfqs` * `GET /communications/rfqs/{rfq_id}` * `GET /communications/quotes` * `GET /communications/quotes/{quote_id}` The subaccount balance field will be represented as a fixed-point dollars string instead of a centicent integer. **Affected endpoint:** * `GET /portfolio/subaccounts/balances` The exhange `fee_cost` will be made available on the Fills API starting `January 28, 2026`. **Affected endpoint:** * `GET /portfolio/fills` Added more specific error codes for order validation failures. These replace the generic `invalid_order` response in certain cases: **New error codes:** * `invalid_order_size` - Order quantity is invalid * `available_balance_too_low` - Insufficient available balance for the order * `order_id_and_client_order_id_mismatch` - OrderID does not match ClOrdID on amend/cancel * `order_side_mismatch` - Order side mismatch on amend/cancel * `order_ticker_mismatch` - Market ticker mismatch on amend/cancel **Affected endpoints:** * `POST /portfolio/orders` * `POST /portfolio/orders/{order_id}/amend` * `DELETE /portfolio/orders/{order_id}` The `POST /communications/quotes` endpoint now accepts an optional `subaccount` parameter to create quotes on behalf of a subaccount. **Affected endpoint:** * `POST /communications/quotes` New endpoint which provides authorized user their api tier and corresponding read and write limits. **New endpoint:** * `GET /account/limits` Release date: `January 28, 2026` Added `order_group_updates` WebSocket channel to stream order group lifecycle updates (created, triggered, reset, deleted, limit\_updated). Payloads include `contracts_limit_fp` for created and limit\_updated events. **New channel:** * `order_group_updates` Release date: `January 29, 2026` The `client_order_id` and `updated_client_order_id` fields in amend order requests are now optional. **Behavior changes:** * You can now amend orders without providing `client_order_id` fields by using only the `order_id` from the URL path * If you provide an `updated_client_order_id`, the order can be found by the exchange and the `client_order_id` updated just on `order_id` alone **Affected endpoint:** * `POST /trade-api/v2/portfolio/orders/{order_id}/amend` **Example:** ```json theme={null} { "ticker": "MARKET-TICKER", "side": "yes", "action": "buy", "count_fp": "50.00", "yes_price": 30 } ``` This will amend the order identified by `order_id` without requiring `client_order_id` fields. Release date: `January 28, 2026` Release date: `January 29, 2026` Added an endpoint to update the contracts limit for an order group (rolling 15-second window). If the updated limit would immediately trigger the group, all orders in the group are canceled and the group is triggered. **New endpoint:** * `PUT /portfolio/order_groups/{order_group_id}/limit` **Response updates:** * `GET /portfolio/order_groups` * `GET /portfolio/order_groups/{order_group_id}` Both now include `contracts_limit` and `contracts_limit_fp`. Release date: `January 29, 2026` Added `*_fp` fixed-point contract count fields in the WebSocket AsyncAPI spec and examples (orderbook, ticker, trades, fills, positions, communications). See the [WebSocket reference](/websockets). Release date: `January 22, 2026` Added `updated_time` to Market responses and `min_updated_ts` filter to `GET /markets`, which filters for only markets updated later than the provided unix ts. Affected endpoints: * `GET /markets/{ticker}` * `GET /markets`. Currently, a market settled to a scalar result will return `""` in the `market_result` field. Starting in the next release, this value will read `"scalar"` instead. Affected endpoints: * `GET /markets/{ticker}` * `GET /markets` Release date: `January 28, 2026` Added manual trigger support for order groups. **New endpoint:** * `PUT /portfolio/order_groups/{order_group_id}/trigger` Release date: `January 22, 2026` Maker RFQ client order IDs now use the format `quote::`, where `hash` is an 8-character hash segment and the maker's quote ID is added as a suffix. Release date: `January 22, 2026` Added `include_latest_before_start` parameter to the single market candlesticks endpoint for price continuity. When set to `true`, prepends a synthetic candlestick that: * Uses the close price from the most recent candlestick before `start_ts` * Sets `previous_price` to enable continuous price charting **Affected endpoint:** * `GET /series/{series_ticker}/markets/{ticker}/candlesticks` Release date: `January 22, 2026` Added `*_fp` string fields for contract counts across REST API requests and responses. **Example order response:** ```json theme={null} { "count": 10, "count_fp": "10.00", "fill_count": 5, "fill_count_fp": "5.00" } ``` See [Fixed-Point Contracts](/getting_started/fixed_point_contracts) for migration details. Release date: `Jan 22, 2026` Settlement value on component legs are now reported when pulling MVEs. Release date: `January 13, 2025` Added sharding support to the `communications` WebSocket channel for high-throughput RFQ/quote consumers. **New subscription parameters:** * `shard_factor` (int): Number of shards to divide messages across (e.g., 4) * `shard_key` (int): Which shard this connection receives (0 to shard\_factor-1) Messages are sharded by `market_ticker` using consistent hashing. Clients can run multiple connections with different `shard_key` values to distribute load while ensuring complete coverage. **Validation:** * `shard_factor` must be > 0 when provided * `shard_key` must be >= 0 and \< `shard_factor` * `shard_key` requires `shard_factor` to be set **Example subscription:** ```json theme={null} { "id": 1, "cmd": "subscribe", "params": { "channels": ["communications"], "shard_factor": 4, "shard_key": 0 } } ``` **No breaking changes:** When these parameters are omitted, all messages are received as before. Existing integrations are unaffected. New endpoints for managing subaccounts within a user's portfolio. **New endpoints:** * `POST /portfolio/subaccounts` - Create a new subaccount * `GET /portfolio/subaccounts/balances` - Get balances for all subaccounts * `POST /portfolio/subaccounts/transfer` - Transfer funds between subaccounts * `GET /portfolio/subaccounts/transfers` - Get paginated history of subaccount transfers **Note:** Transfers require a unique `client_transfer_id` for idempotency. On `GET /markets`, responses may bear `is_provisional: true`, indicating that the market will be removed from the API if it has no activity by settlement time. Notes: * Historical and existing markets are unaffected, this change only applies going forward. * A market will never transition into the provisional state if it was not created as provisional. Expected release date: `January 9, 2025`. Added optional `volume` field to Series responses showing total contracts traded across all events in the series. **Affected endpoints:** * `GET /series` - Added `include_volume` query parameter (default: `false`) * `GET /series/{series_ticker}` - Added `include_volume` query parameter (default: `false`) When `include_volume=true`, the response includes the `volume` field with the total contracts traded. Release date: `January 15, 2026` Cent-denominated price fields will be removed from Market responses. Affected endpoints: * `GET /markets` * `GET /markets/{ticker}` * `GET /events` * `GET /events/{ticker}` Fields to be removed: * `response_price_units`, `notional_value`, `yes_bid`, `yes_ask`, `no_bid`, `no_ask`, `last_price`, `previous_yes_bid`, `previous_yes_ask`, `previous_price`, `liquidity` → Use `*_dollars` equivalents (e.g., `yes_bid_dollars`) * `tick_size` → Use `price_level_structure` and `price_ranges` Release date: `January 15, 2026` The deprecated fields `category` and `risk_limit_cents` will be removed from Market responses. **Affected endpoints:** * `GET /markets` * `GET /markets/{ticker}` Release date: `January 8, 2026` Search endpoints now accept lowercase query parameters for improved flexibility and consistency. Release date: `December 22, 2025` Added `settlement_ts` field to `GET /markets` and `GET /markets/{ticker}` responses. Release date: `December 25, 2025` The `Market` response object now documents all possible `status` values: `initialized`, `inactive`, `active`, `closed`, `determined`, `disputed`, `amended`, `finalized`. In `GET /markets`, markets that have been paused by an administrator will be available under new the `paused` status filter. `GET /portfolio/settlements` will return each settled position's Event Ticker. Release Date: `December 18, 2025` API keys now support a `scopes` field. Valid scopes are `read` and `write`. Keys default to full access if not specified. All existing API keys will have both scopes. Release date: `December 18, 2025` `GET /portfolio/positions` will only return unsettled positions. For fetching settled market positions, switch to `GET /portfolio/settlements`. Release date: December 11, 2025 Breaking Change: `GET /events` excludes multivariate events Release date: December 4, 2025 Release date: `December 4, 2025` `DELETE /portfolio/orders/batched` is now generally available. Advanced API access is no longer required. (The Nov 14th update only applied to `POST`.) Release date: `December 4, 2025` `GET /live_data/{type}/milestone/{milestone_id}` and `GET /live_data/batch` now returns `milestone_id` in the response. Release date: `December 4, 2025` Updates to filtering in `GET /markets` * Inactive markets during tradable hours will returned in the `open` selector. * Inactive markets during tradable hours no longer appear in the `closed` selector. * Restricting to a single status filter allowed per request (previously announced). Release date: `November 27, 2025` Subpenny fields `yes_bid_dollars` and `no_bid_dollars` available on the Get Quote API. Affected endpoints: * `GET /communications/quotes` * `GET /communications/quotes/{quote_id}` Adds new endpoint `GET /markets/candlesticks` Retrieve candlestick data for multiple markets in a single API call. Supports up to 10,000 candlesticks total across all requested markets. Expected release: `November 27, 2025` **Breaking changes to order expiration and immediate-or-cancel (IoC) handling:** 1. **Past expiration timestamps now rejected**: Orders with `expiration_ts` in the past will be rejected with error "Expiration timestamp must be in the future" instead of being automatically converted to IoC orders. 2. **IoC + expiration\_ts combination rejected**: Orders cannot specify both `time_in_force: "immediate_or_cancel"` and `expiration_ts`. This will be rejected at the API level with error "Cannot specify both immediate\_or\_cancel and expiration\_ts". 3. **IoC orders no longer support expiration**: The IoC order type is now independent and does not accept an expiration timestamp. **Migration guide**: If you were previously using past `expiration_ts` values to indicate IoC behavior, you must now explicitly set `time_in_force: "immediate_or_cancel"` instead. Expected release: `TBD` 'Pending' is being removed from the status enum on orders Expected release: `November 27, 2025` `POST /portfolio/orders/batched` will now be generally available. Advanced API access is no longer a prerequisite. Release date: `November 20, 2025` Added `created_time` to `GET /markets` && `GET /market` responses. Release date: `November 20, 2025` Breaking changes planned to `GET /markets` endpoint for performance reasons: Timestamp filters will be mutually exclusive from other timestamp filters and certain status filters. | Compatible Timestamp Filters | Additional Status Filters | | ---------------------------------- | --------------------------- | | min\_created\_ts, max\_created\_ts | `unopened`, `open`, *empty* | | min\_close\_ts, max\_close\_ts | `closed`, *empty* | | min\_settled\_ts, max\_settled\_ts | `settled`, *empty* | Added new timestamp filters for the `GET /markets` endpoint: * `min_created_ts` * `max_created_ts` * `min_settled_ts` * `max_settled_ts` * `GET /portfolio/positions` will no longer return `resting_orders_count` in both the `event_positions` and `market_positions` field. * The `resting_order_count` filter on `GET /portfolio/positions` will no longer be supported. Requests specifying this filter will return a 400 error. Expected release: `November 13, 2025` `GET /portfolio/settlements` now returns the sum of trade fees paid by the user on a settled market position. Fixed two issues with the `GET /events` endpoint's `limit` parameter: * **Default increased**: The default limit is now 200 (previously 100) to return more results per page * **Parameter**: Requests with `with_nested_markets=true` now properly respect `limit=200` instead of being capped at 100 The `GET /portfolio/positions` endpoint now includes `total_cost_shares`, which tracks the total number of shares traded on an event (including both YES and NO contracts). Added comprehensive support for multivariate events (combos) with new API endpoints and enhanced filtering: **New Endpoint and deprecation of multivariate events in GetEvents endpoint** * `GET /events/multivariate` - Retrieve multivariate events with filtering by series and collection ticker. * `GET /events` will EXCLUDE multivariate events upon the next release (November 13th). Please use the new endpoint! **Enhanced Market Filtering:** * `GET /markets` now supports `mve_filter` parameter: * `"only"` - Returns only multivariate events * `"exclude"` - Excludes multivariate events * No parameter - Returns all events (default behavior) Expected release: `November 6th, 2025` Fixed batch order creation to return proper error details when post-only orders cross the market. The response now includes: * Error code: `"invalid order"` * Error details: `"post only cross"` This makes the batch endpoint consistent with single order creation and provides clear feedback on why post-only orders were rejected. The `GET /portfolio/orders` endpoint's `event_ticker` parameter now supports filtering by multiple events using comma-separated values. **Example usage:** ``` GET /portfolio/orders?event_ticker=EVENT1,EVENT2,EVENT3 ``` **Backward Compatible:** * Single event ticker queries continue to work as before * Multiple event tickers return orders from all specified events Fixed missing fields in Quote responses: `rfq_target_cost_centi_cents`, `rfq_creator_order_id`, and `creator_order_id` are now properly included in all Quote-related endpoints. The `GET /events` endpoint now supports an optional flag, `with_milestones`, that includes all milestones related to the returned events. Expected release: `October 16, 2025` The order returned by create order is now the same model as the model returned by get order. The `GET /v2/incentive_programs` and `GET /incentive_programs` endpoints now return a `series_ticker` field for each incentive program. Expected release: `October 13, 2025` The `price_level_structure` field has been moved from the event level to the market level. Each market now has its own `price_level_structure` field. **Affected endpoints:** * `GET /trade-api/v2/events` * `GET /trade-api/v2/events/:event_ticker` * `GET /trade-api/v2/markets` * `GET /trade-api/v2/markets/:ticker` **Note:** The `price_level_structure` field on event objects is now deprecated and will be removed. Please use the field on individual market objects instead. Expected release date: `Oct 15th, 2025` Fixed the `GET /series` endpoint's tags parameter to properly support tags containing spaces. Previously, the parameter would split on both commas AND spaces, breaking searches for tags like "Rotten Tomatoes". **Breaking Change:** * The `tags` query parameter now **only** splits on commas (`,`), not spaces * Tags with spaces (e.g., "Rotten Tomatoes") now work correctly * Multiple tags must be comma-separated: `?tags=Rotten Tomatoes,Television` **Before (broken):** ``` GET /series?tags=Rotten Tomatoes // Was incorrectly parsed as: ["Rotten", "Tomatoes"] // Result: No matches found ``` **After (fixed):** ``` GET /series?tags=Rotten Tomatoes // Correctly parsed as: ["Rotten Tomatoes"] // Result: Returns series with the "Rotten Tomatoes" tag GET /series?tags=Rotten Tomatoes,Television // Correctly parsed as: ["Rotten Tomatoes", "Television"] // Result: Returns series with either tag ``` This change may affect integrations that relied on space-separated tags. Please update to use comma-separated tags only. Fixed routing inconsistency where certain collection endpoints required trailing slashes, causing unnecessary 301 redirects for requests without them. **Endpoints now returning 200 for requests without trailing slash** (previously returned 301): * `GET /milestones` * `GET /structured_targets` * `GET /multivariate_event_collections` * `GET /series` * `GET /api_keys` * `POST /api_keys` **Note:** Requests with trailing slashes (e.g., `/milestones/`) will now receive a 301 redirect to the version without the trailing slash, which is the opposite of the previous behavior. Subpenny fields have been added to orders (`taker_fees_dollars`, `maker_fees_dollars`), as well as to public trades (`yes_price_dollars`, `no_price_dollars`). Endpoints affected: * `GET /trade-api/v2/portfolio/orders` * `GET /trade-api/v2/markets/trades` Fields have been added to all RFQ and quote messages to support subpenny pricing via the dollar normalized price fields. For more info reference: * [Subpenny Pricing](/getting_started/subpenny_pricing) * [Websocket Documentation](/websockets) Enhanced the existing `GET /portfolio/balance` endpoint to include a `portfolio_value` field that provides the total portfolio value (available balance plus current market value of all positions), both in cents. The `GET /series/fee_changes` endpoint now returns user-facing fee type names (`quadratic`, `quadratic_with_maker_fees`, `flat`) instead of internal fee structure names. This change also applies to CustomerIO notifications for scheduled series fee updates. Expected release: `October 1, 2025` Repeated subscriptions on the same websocket call will no longer error. If passing the same market tickers as before, no action will be taken. If passing new market tickers, they will be added to your existing subscription. Additionally, the user may supply WS Command `list_subscriptions` to view their existing subscriptions. Expected release: `October 1, 2025` For optimization purposes, partial fills generated by self-crossing FoK orders are not rolled back. If a FoK order self-crosses, order execution proceeds based on `self_trade_prevention_type`: * `taker_at_cross`: the taker is canceled, execution stops. Any partial fills are executed. * `maker`: the maker is canceled, execution continues. After execution, remaining taker quantity is canceled. Any fills are executed. This fixes a bug where partially filled FoK orders with Maker STP entered into the book after self-crossing. Expected enforced date: `Oct 1, 2025`. User seeking a simple way to determine the direction of their fill should reference purchased\_side. Both BUY YES or SELL NO result in purchased\_side = YES. The addition of this field is the first step in standardizing the fills websocket and REST endpoints, which have different conventions for the interpretation 'side' and 'user\_action'. Expected Enforce Date: deprecation date for existing fields not yet scheduled. Added new public API endpoint for getting all of a series' scheduled fees: * `GET /series/fee_changes` - Get a series' fee changes. If query string parameter show\_historical is set to true, ALL fee changes previous and upcoming will be shown. If set to false, only upcoming fee changes will be shown Specifying `order_type` is no longer required and only `limit` type orders will be supported. Price must be supplied based on the underlying market structure. Example usage: ``` {"yes_price": 99, "side: "yes"} // buy yes or sell no at market price {"no_price": 99, "side: "no"} // buy no or sell yes at market price ``` Expected enforce date: `Sep 25, 2025` WebSocket connections per user are limited by usage tier. The default limit begins at 200 and increases based on API usage tier. A new WS channel is being introduced for streaming information related to pre-trade communications (RFQs and quotes). Additional metadata is being added to RFQs on multivarate events (MVEs) that break down their component parts explicitly. Market payloads are also being expanded with these new optional fields that are filled only for MVE markets. Added new public API endpoint for event candlesticks: * `GET /candlesticks` - Get candlesticks for all markets associated with an event. If the # of candlesticks exceeds 5000, paginate the results and return an adjustedEndTs which should be used as the start\_ts for your next request. The TypeScript SDK is now available through NPM! Install with `npm install kalshi-typescript`. Documentation and examples available at docs.kalshi.com Added new public API endpoint for forecast percentiles history: * `GET /forecast_percentiles_history` - Get percentile history of a event forecast Added new public API endpoint for incentive programs (not yet live): * `GET /incentive_programs` - List incentive programs with filtering options (by market ticker, active status, payout status) Subpenny pricing fields have been added to websocket messages. Any message bearing price in cents will now also bear an equivalent fixed-point dollars field. For more info, see [Subpenny Pricing](/getting_started/subpenny_pricing). Both the individual and batch `GET` events endpoints now also return `available_on_brokers` which indicates that they are available on intermediate platforms/ brokers. The python SDK is being generated from our OpenAPI spec and is available through pip with pip install kalshi-python. Docs for the new SDK are available on docs.kalshi.com/python-sdk. Subpenny pricing fields have been added to APIs involving price, fees, and money in general. E.g. next to a field called `"price": 12` (representing 12 cents), you will also see `"price_dollars": "0.1200"`, which is a string bearing a fixed-point representation of money accuate to at 4 decimal points. For now, this change is read-only, meaning that the minimum allowable tick size for orders is still 1c. Eventually, we will introduce sub-penny pricing on orders. For now, please prepare for an eventual migration to the higher granularity price representation. For more info, see [Subpenny Pricing](/getting_started/subpenny_pricing). The market payload has been updated to include two new fields that describe markets which are part of Multivariate Events. The market payload has been updated to include two new fields that describe markets which are part of Multivariate Events. The MVE payload has been expanded to support more flexible structures. Several fields that are now redundant are deprecated, but not yet removed. The Settlements API now includes the settlement value for a yes contract. The get\_milestones endpoint now uses case-insensitive matching for the category parameter, resolving inconsistent filtering behavior between "Sports" and "sports". Filtering events by close ts and series by tags supported in the API. The batch order endpoints are now available to all API users in the demo environment: **Affected Endpoints:** * `POST /portfolio/orders/batched` (BatchCreateOrders) * `DELETE /portfolio/orders/batched` (BatchCancelOrders) **Changes:** * Basic tier users can now access batch endpoints in demo environment * Production environment remains unchanged - Advanced tier or higher still required * Rate limits still apply based on user tier This change enables developers to test batch order functionality without needing Advanced tier access in the demo environment. The error messages when an incorrect API signature is passed have been improved The OpenAPI specification for the Kalshi API is now available at `https://docs.kalshi.com/openapi.yaml`. This allows developers to easily generate client libraries and integrate with the API using OpenAPI-compatible tools. Added `client_order_id` field to orderbook delta WebSocket messages. This field appears only when you caused the orderbook change and contains the client\_order\_id of your order that triggered the delta. **WebSocket Message Enhancement:** * New field: `client_order_id` (string, optional) * Present only when the authenticated user's order causes the orderbook change * Contains the client-provided order ID of the triggering order See the WebSocket documentation for implementation details. Added `GET /portfolio/orders/queue_positions` endpoint for retrieving queue positions of multiple resting orders. **Request Parameters:** * `market_tickers` (optional): Array of market tickers to filter by * `event_ticker` (optional): Event ticker to filter by Note: You must specify one of `market_tickers` and `event_ticker` in the request. We are migrating our API documentation to a new platform: * **RSS feed moved** from `https://trading-api.readme.io/changelog.rss` to `https://docs.kalshi.com/changelog/rss.xml` * **Documentation site** `trading-api.readme.io` is now deprecated * **New documentation home**: `https://docs.kalshi.com` * Historical changelog entries will not be backfilled to the new RSS feed Please update your bookmarks and RSS subscriptions. The GetEventMetadata endpoint has been expanded to include settlement sources. The GetApiVersion endpoint has been removed. API versioning will not be available for the time being. # Authentication & Sessions Source: https://docs.kalshi.com/fix/authentication API key creation, logon, session lifecycle, and message retransmission ## API Key Setup FIX API keys use the same RSA key pair as the [REST API](/getting_started/api_keys). Generate a 2048-bit RSA key pair and register the public key in your [account profile](https://kalshi.com/account/profile). The resulting API Key ID (UUID) is your `SenderCompID`. ```bash theme={null} openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out kalshi-fix.key openssl rsa -in kalshi-fix.key -pubout -out kalshi-fix.pub ``` ## Logon (35=A) The initiator sends a Logon message. The acceptor responds with either a Logon (success) or Logout (failure). ### Required Fields | Tag | Name | Description | Value | | ---- | ---------------- | ------------------------------ | ------------------------ | | 98 | EncryptMethod | Method of encryption | None\<0> | | 96 | RawData | Client logon message signature | Base64 encoded signature | | 108 | HeartbeatInt | Heartbeat interval (seconds) | N > 3 | | 1137 | DefaultApplVerID | Default application version | FIX50SP2\<9> | ### Optional Fields | Tag | Name | Description | Default | | ----- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ----------------- | | 141 | ResetSeqNumFlag | Reset sequence numbers on logon. **Must be Y for non-retransmission sessions.** | N | | 8013 | CancelOrdersOnDisconnect | Cancel orders on any disconnection (including graceful logout) | N | | 20126 | ListenerSession | Listen-only session. **KalshiNR/RT only, requires SkipPendingExecReports=Y.** | N | | 20127 | ReceiveSettlementReports | Receive settlement reports. **KalshiRT and KalshiPT only. Default to Y on KalshiPT.** | N (Y on KalshiPT) | | 20200 | MessageRetentionPeriod | How long session messages will be stored for retransmission, max of 72 hours. **KalshiRT and KalshiPT only.** | 24 | | 21005 | UseDollars | Enable dollar-based price format for prices, including subpenny precision | N | | 21011 | SkipPendingExecReports | Skip PENDING\_\{NEW\|REPLACE\|CANCEL} execution reports | N | | 21012 | UseExpiredOrdStatus | Emit Expired\ (150/39) for expiry-style system cancellations (CloseCancel and OrderExpiryCancel) instead of Canceled\<4> | N | | 21007 | EnableIocCancelReport | Partially filled IOC orders produce a cancel report | N | | 21008 | PreserveOriginalOrderQty | OrderQty tag 38 always reflects original order quantity across all states | N | | 21026 | AlwaysEmitNewBeforeTrade | Emit a standalone New\<0> execution report before any Trade\ report when both occur in the same matching cycle | N | ### Signature Generation The RawData field must contain a PSS RSA signature of the pre-hash string: ``` PreHashString = SendingTime + SOH + MsgType + SOH + MsgSeqNum + SOH + SenderCompID + SOH + TargetCompID ``` **SendingTime in Signature** The SendingTime in the PreHashString must match **exactly** the value in field 52 of the Logon message. Format: `YYYYMMDD-HH:MM:SS.mmm`. SendingTime must be within 30 seconds of the server's current time, or the message will be rejected with `SessionRejectReason<373>=10`. ```python Python theme={null} from base64 import b64encode from Cryptodome.Signature import pss from Cryptodome.Hash import SHA256 from Cryptodome.PublicKey import RSA private_key = RSA.import_key(open('kalshi-fix.key').read().encode('utf-8')) sending_time = "20230809-05:28:18.035" msg_type = "A" msg_seq_num = "1" sender_comp_id = "your-fix-api-key-uuid" target_comp_id = "KalshiNR" # Must match TargetCompID in tag 56 msg_string = chr(1).join([ sending_time, msg_type, msg_seq_num, sender_comp_id, target_comp_id ]) msg_hash = SHA256.new(msg_string.encode('utf-8')) signature = pss.new(private_key).sign(msg_hash) raw_data_value = b64encode(signature).decode('utf-8') ``` ## Heartbeat & Sequence Numbers | Behavior | Detail | | ------------------------------------ | ------------------------------------------------------------------------ | | Default heartbeat interval | 30 seconds | | Missed heartbeat | Connection terminates if heartbeat response not received within interval | | Sequence number lower than expected | Connection terminated | | Sequence number higher than expected | Recoverable with ResendRequest (KalshiRT, KalshiPT only) | ## Message Retransmission Message retransmission (ResendRequest, SequenceReset) is only supported on **KalshiRT** and **KalshiPT**. For all other sessions, `ResetSeqNumFlag<141>` in the Logon message must always be `Y` or the Logon will be rejected. The [drop copy session](/fix/drop-copy) provides an alternative way to query for missed execution reports. For a real-time streaming feed, see [Listener Sessions](/fix/listener-sessions). ### ResendRequest (35=2) **KalshiRT and KalshiPT only.** Lookback window limited to 24 hours (or up to 72 hours if `MessageRetentionPeriod` was set on Logon). | Tag | Name | Description | | --- | ---------- | ----------------------- | | 7 | BeginSeqNo | Lower bound (inclusive) | | 16 | EndSeqNo | Upper bound (inclusive) | ## Logout (35=5) Either side may initiate a Logout. The counterparty responds with a Logout, and the transport connection is terminated. If `CancelOrdersOnDisconnect=Y` was set on Logon, all open orders are canceled. # Changelog Source: https://docs.kalshi.com/fix/changelog Version history and updates for the Kalshi FIX API # FIX API Changelog ## Version 1.0.25 (2026-05-08) BidSize (134) and OfferSize (135) conditionally offered on QuoteStatusReport (35=AI). ## Version 1.0.24 (2026-05-07) * OrderGroupResponse (UOH) now echoes AllocAccount (tag 79), with `79=0` for the primary account and `79=1-32` for subaccounts ## Version 1.0.23 (2026-05-05) * Quote (35=S) now accepts `RestRemainder` (21015) * Set `21015=Y` to rest the quote remainder after execution * Omitting the tag or setting `21015=N` preserves the existing behavior ## Version 1.0.22 (2026-04-28) * Added `AlwaysEmitNewBeforeTrade` (21026) Logon flag * With Logon flag `21026=Y`, the gateway always emits a standalone `New<0>` execution report before any `Trade` report, even when an order takes liquidity in the same matching cycle as its placement * Without `21026`, the New ack continues to be folded into the first Trade report when both events arrive in the same batch (existing behavior) * Useful for clients whose state machines require an explicit `39=0` ack before they can issue replaces against the order ## Version 1.0.21 (2026-04-20) * OrderGroupRequest (UOG) now accepts AllocAccount (tag 79) to scope the operation to a subaccount * Applies to all five actions: Create, Reset, Delete, Trigger, Update * Omit or set `79=0` to operate on the primary account * An OrderGroupID created under one subaccount cannot be managed without the matching AllocAccount on the follow-up request * OrderGroupResponse (UOH) now echoes OrderGroupContractsLimit (tag 20132) on Create and Update responses ## Version 1.0.20 (2026-03-01) * Added `OrderExpiryCancel` support for expired status mapping in execution reports * With Logon flag `21012=Y`, both `CloseCancel` and `OrderExpiryCancel` emit `ExecType(150)=C` and `OrdStatus(39)=C` * Without `21012`, behavior remains `Canceled<4>` for compatibility ## Version 1.0.19 (2026-02-27) * SettlementPrice (730) precision extended in MarketSettlementReport * SettlementPrice will continue to be in cents but may have up to two decimal places (e.g. `30.60` instead of `30`) * This enables sub-cent settlement values to be represented without truncation * MiscFeeAmt (137) now reports actual settlement fees in MarketSettlementReport * Previously hardcoded to zero; now reflects the real settlement fee for each position ## Version 1.0.18 (2026-02-12) * Execution report precision extended for fractional shares * On qty fields, Kalshi will return at least a scale of 2 instead of 0. * E.g. on a trade which executes for 10 contracts, Kalshi will return `CumQty: 14=10.00` as opposed to `14=10` * Despite the change in precision, the numerical value will remain unchanged for now because fractional trading is not yet enabled on any market. * Affected fields: `LastQty`, `CumQty`, `LeavesQty` ## Version 1.0.17 (2025-11-30) * **BREAKING CHANGE**: Tag reorganization for improved compatibility * QuoteConfirmStatus now uses tag 21010 (currently supporting both 297 and 21010) * SkipPendingExecReports now uses tag 21011 (currently accepting both 21003 and 21011) * Tag 297 designated for standard QuoteStatus field * Tag 21003 designated for ResendEventCount field * Clients should update to use new tags; legacy support will be removed in future version ## Version 1.0.16 (2025-11-30) * Added MaxExecutionCost (21009) NewOrderSingle flag. ## Version 1.0.15 (2025-11-21) * Added PreserveOriginalOrderQty (21008) Logon flag to maintain original OrderQty across all execution reports ## Version 1.0.14 (2025-10-01) * Added support for subpenny pricing across multiple FIX messages * For more info see [Subpenny Pricing](/fix/subpenny-pricing) ## Version 1.0.13 (2025-08-15) * Added Order Group management messages (UOG/UOH) * Support for automatic order cancellation with contracts limits * Create, Reset, and Delete operations for order groups ## Version 1.0.12 (2025-06-26) * Added support for ListenerSession Logon flag for KalshiNR/KalshiRT * Added support for ReceiveSettlementReports Logon flag for KalshiRT * Deprecated SecurityGroup ## Version 1.0.11 (2025-06-12) * Removed Required from OrderQty on Cancel 35=F * Added PostOnly to Create 35=D ## Version 1.0.10 (2025-04-15) * Removed deprecated event settlement message type * Added ListenerSession and SkipPendingExecReports flag to Logon message type # Common Components Source: https://docs.kalshi.com/fix/common-components Standard header, trailer, and shared components across all FIX messages Kalshi's FIX implementation uses **FIXT.1.1** with application version **FIX50SP2**. Members on the Premier tier or above have FIX access by default. For all other tiers, contact [institutional@kalshi.com](mailto:institutional@kalshi.com) to inquire about access. ## FIX Dictionary Download the Kalshi-specific FIX dictionary for import into your FIX engine: * [Kalshi FIX Dictionary (XML)](https://kalshi-public-docs.s3.us-east-1.amazonaws.com/fix/kalshi-fix-dictionary.xml) If you are using a FIX engine such as [QuickFIX/J](https://www.quickfixj.org/), [QuickFIX/N](https://quickfixn.readthedocs.io/), or [quickfix-go](https://github.com/quickfixgo/quickfix), the standard header and trailer fields below are managed automatically by the library. This section is primarily a reference for custom implementations or debugging. ## Standard Header Every FIX message begins with the following fields: | Tag | Name | Type | Required | Description | | --- | --------------- | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 8 | BeginString | String | Y | Always `FIXT.1.1` | | 9 | BodyLength | Int | Y | Message length in bytes, from the tag after BodyLength up to (but not including) the CheckSum field. Must be the second field. | | 35 | MsgType | String | Y | Identifies the message type. Must be the third field. | | 49 | SenderCompID | String | Y | Your FIX API Key (UUID format) when sending; `Kalshi` when receiving. | | 56 | TargetCompID | String | Y | Session identifier (e.g. `KalshiRT`, `KalshiNR`) when sending; your API key when receiving. | | 34 | MsgSeqNum | Int | Y | Monotonically increasing sequence number, starting at 1. | | 52 | SendingTime | UTCTimestamp | Y | Time the message was sent, in UTC. Format: `YYYYMMDD-HH:MM:SS.mmm`. Must be within 30 seconds of server time or the message is rejected (`SessionRejectReason=10`). | | 43 | PossDupFlag | Boolean | N | `Y` if the message is a possible duplicate of a previously sent message (used during retransmission). | | 97 | PossResend | Boolean | N | `Y` if the message may contain information that has already been sent under a different sequence number. | | 122 | OrigSendingTime | UTCTimestamp | N | Original SendingTime of a message being resent. Required when `PossDupFlag=Y`. | ## Standard Trailer Every FIX message ends with: | Tag | Name | Type | Required | Description | | --- | -------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 10 | CheckSum | String | Y | Three-character checksum. Calculated by summing every byte in the message up to (but not including) the CheckSum field, then taking modulo 256. Always three digits, zero-padded (e.g. `007`). | ## Supported MsgTypes ### Session-Level (all sessions) | MsgType | Name | Direction | | ------- | ------------- | ------------------------------ | | A | Logon | Both | | 0 | Heartbeat | Both | | 1 | TestRequest | Both | | 2 | ResendRequest | Both (KalshiRT, KalshiPT only) | | 3 | Reject | Server -> Client | | 4 | SequenceReset | Both (KalshiRT, KalshiPT only) | | 5 | Logout | Both | ### Application-Level #### Order Entry | MsgType | Name | Sessions | Direction | | ------- | ------------------------- | ---------------------------- | ---------------- | | D | NewOrderSingle | KalshiNR, KalshiRT | Client -> Server | | F | OrderCancelRequest | KalshiNR, KalshiRT | Client -> Server | | G | OrderCancelReplaceRequest | KalshiNR, KalshiRT | Client -> Server | | q | OrderMassCancelRequest | KalshiNR | Client -> Server | | 8 | ExecutionReport | KalshiNR, KalshiRT, KalshiDC | Server -> Client | | 9 | OrderCancelReject | KalshiNR, KalshiRT | Server -> Client | | r | OrderMassCancelReport | KalshiNR | Server -> Client | | j | BusinessMessageReject | All | Server -> Client | #### Order Groups | MsgType | Name | Sessions | Direction | | ------- | ------------------ | ------------------ | ---------------- | | UOG | OrderGroupRequest | KalshiNR, KalshiRT | Client -> Server | | UOH | OrderGroupResponse | KalshiNR, KalshiRT | Server -> Client | #### Drop Copy | MsgType | Name | Sessions | Direction | | ------- | ------------------- | -------- | ---------------- | | U1 | EventResendRequest | KalshiDC | Client -> Server | | U2 | EventResendComplete | KalshiDC | Server -> Client | | U3 | EventResendReject | KalshiDC | Server -> Client | After an EventResendRequest, the server replays the matching historical order updates as ExecutionReport (35=8) messages and then sends EventResendComplete (35=U2) or EventResendReject (35=U3). #### Post Trade | MsgType | Name | Sessions | Direction | | ------- | ---------------------- | ------------------ | ---------------- | | UMS | MarketSettlementReport | KalshiPT, KalshiRT | Server -> Client | #### RFQ | MsgType | Name | Sessions | Direction | | ------- | ------------------ | ------------------- | ------------------------------------------------------- | | R | QuoteRequest | KalshiRT, KalshiRFQ | KalshiRT: Client -> Server; KalshiRFQ: Server -> Client | | b | QuoteRequestAck | KalshiRT | Server -> Client | | S | Quote | KalshiRT, KalshiRFQ | KalshiRT: Server -> Client; KalshiRFQ: Client -> Server | | AI | QuoteStatusReport | KalshiRFQ | Server -> Client | | Z | QuoteCancel | KalshiRFQ | Client -> Server | | U9 | QuoteCancelStatus | KalshiRFQ | Server -> Client | | AG | QuoteRequestReject | KalshiRT, KalshiRFQ | Server -> Client | | UA | AcceptQuote | KalshiRT | Client -> Server | | UC | AcceptQuoteStatus | KalshiRT | Server -> Client | | U7 | QuoteConfirm | KalshiRFQ | Client -> Server | | U8 | QuoteConfirmStatus | KalshiRFQ | Server -> Client | | UE | RFQCancel | KalshiRT | Client -> Server | | UB | RFQCancelStatus | KalshiRT | Server -> Client | # Connectivity Source: https://docs.kalshi.com/fix/connectivity Endpoints, transport configuration, and rate limits for the Kalshi FIX API ## Endpoints **Host:** `mm.fix.elections.kalshi.com` | Purpose | Port | TargetCompID | Description | | ------------------------------------ | ---- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Order Entry (without retransmission) | 8228 | KalshiNR | Submit, modify, and cancel orders; no message persistence or retransmission. Supports [Listener Sessions](/fix/listener-sessions) for read-only streaming | | Order Entry (with retransmission) | 8230 | KalshiRT | Order entry with message retransmission, RFQ creation, and optional settlement reports. Supports [Listener Sessions](/fix/listener-sessions) for read-only streaming. Contact [institutional@kalshi.com](mailto:institutional@kalshi.com) for access | | Drop Copy | 8229 | KalshiDC | Request-response queries for historical execution reports | | Post Trade | 8231 | KalshiPT | Read-only stream for market settlement reports and position resolution. Contact [institutional@kalshi.com](mailto:institutional@kalshi.com) for access | | RFQ | 8232 | KalshiRFQ | Market maker session for receiving RFQ broadcasts, submitting quotes, and managing quote lifecycle | **Host:** `fix.demo.kalshi.co` | Purpose | Port | TargetCompID | Description | | ------------------------------------ | ---- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Order Entry (without retransmission) | 8228 | KalshiNR | Submit, modify, and cancel orders; no message persistence or retransmission. Supports [Listener Sessions](/fix/listener-sessions) for read-only streaming | | Order Entry (with retransmission) | 8230 | KalshiRT | Order entry with message retransmission, RFQ creation, and optional settlement reports. Supports [Listener Sessions](/fix/listener-sessions) for read-only streaming. Contact [institutional@kalshi.com](mailto:institutional@kalshi.com) for access | | Drop Copy | 8229 | KalshiDC | Request-response queries for historical execution reports | | Post Trade | 8231 | KalshiPT | Read-only stream for market settlement reports and position resolution. Contact [institutional@kalshi.com](mailto:institutional@kalshi.com) for access | | RFQ | 8232 | KalshiRFQ | Market maker session for receiving RFQ broadcasts, submitting quotes, and managing quote lifecycle | ## Session Configuration All connections use **FIXT.1.1** with application version **FIX50SP2**. | Parameter | Value | | ------------ | ------------------------------ | | SenderCompID | Your FIX API Key (UUID format) | | TargetCompID | See endpoints table above | | Session ID | `TargetCompID + SenderCompID` | Only one FIX connection is allowed per API key. Separate API keys are required for concurrent connections. ## SSL/TLS You must use TLS 1.2 or higher (not plain TCP) to connect to the FIX gateway. Cipher suites follow [AWS Network Load Balancer TLS policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/create-tls-listener.html#describe-ssl-policies). If your FIX implementation does not support native TLS connections, use a local proxy such as [stunnel](https://www.stunnel.org/). To obtain the server certificate for pinning on the initiator side: ```bash theme={null} openssl s_client -showcerts -connect : < /dev/null | openssl x509 > kalshi-fix.pem ``` For example, to pin against the demo order entry endpoint: ```bash theme={null} openssl s_client -showcerts -connect fix.demo.kalshi.co:8228 < /dev/null | openssl x509 > kalshi-fix.pem ``` ## Private Connectivity For participants requiring network-level isolation, Kalshi supports private connectivity via [AWS PrivateLink](https://docs.aws.amazon.com/vpc/latest/privatelink/what-is-privatelink.html). With PrivateLink, FIX traffic is routed entirely within the AWS backbone and never traverses the public internet. Contact [institutional@kalshi.com](mailto:institutional@kalshi.com) to provision a PrivateLink endpoint for your AWS account. ## Rate Limits * **Limit**: Your account-level rate limits are applicable * **Scope**: Application messages only (from client to server) * **Excluded**: Logout (35=5), Heartbeat (35=0), TestRequest (35=1) * Logon (35=A) **is** rate-limited. ## Maintenance Window See [Maintenance and Pauses](/getting_started/maintenance_and_pauses) for scheduled maintenance times and the difference between trading pauses and exchange pauses. Sessions may be disconnected during the maintenance window. Kalshi does not initiate sequence number resets during maintenance; clients should reset sequence numbers on their side when reconnecting. KalshiRT sessions retain message continuity across the maintenance window. If your KalshiRT session is disconnected, you can request retransmission of any messages missed during the downtime after reconnecting. ### CancelOrderOnPause To control what happens to your resting orders during a [pause](/getting_started/maintenance_and_pauses), set tag `21006` (CancelOrderOnPause) on your **New Order Single (35=D)** messages: | Value | Behavior | | ----------- | ------------------------------------------------------------------------ | | Y | Order is automatically cancelled when a trading or exchange pause begins | | N (default) | Order remains resting on the book and resumes when activity reopens | # Drop Copy Session Source: https://docs.kalshi.com/fix/drop-copy Recover missed execution reports and query historical order events **This is not a traditional drop copy session.** Kalshi's Drop Copy uses a request-response pattern for querying historical execution reports. For a real-time streaming feed, use a [Listener Session](/fix/listener-sessions) on KalshiRT instead. Lookback window is limited to the last 3 hours. Only ExecutionReport (35=8) messages are returned. Rejects and pending orders (ExecID `"-1;-1"`) are excluded. Resent messages have new FIX sequence numbers, different from their original numbers on the order entry session. Use ExecID to reconcile. ## EventResendRequest (35=U1) Request execution reports within a specified ExecID range. | Tag | Name | Description | Required | | ----- | ----------- | ---------------------------------------------------------------- | -------- | | 21001 | BeginExecID | Starting ExecID (inclusive) | Yes | | 21002 | EndExecID | Ending ExecID (inclusive). Defaults to latest ExecID if omitted. | No | **Example:** ```fix theme={null} 8=FIXT.1.1|35=U1|21001=12345;67890|21002=12350;67895| ``` ## EventResendComplete (35=U2) Sent after all requested events have been resent. | Tag | Name | Description | Required | | ----- | ---------------- | ----------------------------------- | -------- | | 45 | RefSeqNum | MsgSeqNum of the EventResendRequest | Yes | | 21003 | ResendEventCount | Total number of events resent | Yes | ## EventResendReject (35=U3) Sent when a resend request cannot be fulfilled. | Tag | Name | Description | Required | | ----- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------- | | 45 | RefSeqNum | MsgSeqNum of the EventResendRequest | Yes | | 21004 | EventResendRejectReason | Rejection code: `1`=Too many resend requests, `2`=Server error, `3`=BeginExecID too small (outside window), `4`=EndExecID too large | Yes | # Error Handling Source: https://docs.kalshi.com/fix/error-handling Understanding and handling errors in the FIX protocol ## Overview Kalshi FIX API uses standard FIX error messages with additional detail in the Text field. Errors fall into two categories: * **Session-level errors**: Protocol violations, handled with Reject (35=3) * **Business-level errors**: Application logic issues, handled with BusinessMessageReject (35=j) or specific rejection messages ## Error Message Types ### Reject (35=3) Used for session-level protocol violations. | Tag | Name | Description | Required | | --- | ------------------- | ----------------------------------- | -------- | | 45 | RefSeqNum | Sequence number of rejected message | Yes | | 58 | Text | Human-readable error description | No | | 371 | RefTagID | Tag that caused the rejection | No | | 372 | RefMsgType | Message type being rejected | No | | 373 | SessionRejectReason | Rejection reason code | No | #### Session Reject Reasons (373) | Code | Reason | Description | | ---- | --------------------------- | ---------------------------------------------------- | | 0 | Invalid tag number | Unknown tag in message | | 1 | Required tag missing | Mandatory field not present | | 2 | Tag not defined for message | Tag not valid for this message type | | 3 | Undefined tag | Tag number not in FIX specification | | 4 | Tag without value | Empty tag value | | 5 | Incorrect value | Invalid value for tag | | 6 | Incorrect data format | Wrong data type | | 7 | Decryption problem | Security issue | | 8 | Signature problem | Authentication failure | | 9 | CompID problem | SenderCompID/TargetCompID issue | | 10 | SendingTime accuracy | SendingTime must be within 30 seconds of server time | | 11 | Invalid MsgType | Unknown message type | ### BusinessMessageReject (35=j) Used for application-level business logic errors. | Tag | Name | Description | Required | | --- | -------------------- | ----------------------------------- | -------- | | 45 | RefSeqNum | Sequence number of rejected message | Yes | | 58 | Text | Human-readable error description | No | | 371 | RefTagID | Tag that caused the rejection | No | | 372 | RefMsgType | Message type being rejected | No | | 379 | BusinessRejectRefID | Business ID from rejected message | No | | 380 | BusinessRejectReason | Business rejection reason code | Yes | #### Business Reject Reasons (380) | Code | Reason | Description | | ---- | ------------------------------------ | ---------------------------------------------------------- | | 0 | Other | See Text field for details | | 1 | Unknown ID | Referenced ID not found | | 2 | Unknown Security | Invalid symbol | | 3 | Unsupported Message Type | Message type not implemented | | 4 | Application not available | System temporarily unavailable | | 5 | Conditionally required field missing | Context-specific field missing | | 6 | Not authorized | User or API key is not authorized for the requested action | | 8 | Rate limit exceeded | Request was rejected by FIX rate limits | ## Order-Specific Rejections ### Order Reject Reasons (103) In ExecutionReport (35=8) with ExecType=Rejected: | Code | Reason | Common Causes | | ---- | -------------------------------- | ---------------------------------------------------------------- | | 1 | Unknown symbol | Invalid market ticker | | 2 | Exchange closed | Outside trading hours | | 3 | Order exceeds limit | Position or order size limit, insufficient balance | | 4 | Too late to enter | Market expired/closed | | 6 | Duplicate order | ClOrdID already used | | 8 | Stale order | Timestamp or RFQ quote was expired | | 11 | Unsupported order characteristic | Invalid order parameters, order ID/side/ticker mismatch on amend | | 13 | Incorrect quantity | Invalid order size | | 15 | Unknown account | Subaccount or sub-trader does not exist | | 99 | Other | See Text field | ### Cancel Reject Reasons (102) In OrderCancelReject (35=9): | Code | Reason | Description | | ---- | ----------------------- | ------------------------------------------------------------------------ | | 0 | Too late to cancel | Order already filled | | 1 | Unknown order | Order ID not found, order ID/side/ticker mismatch | | 2 | Broker | Invalid amend quantity, or order already fully filled | | 18 | Invalid price increment | Replace would self-cross with another order belonging to the same trader | | 99 | Other | See Text field | ## Common Error Scenarios **Example: Invalid Tag** **Scenario**: Undefined tag in NewOrderSingle ```fix theme={null} // Sent 8=FIXT.1.1|35=D|11=123|38=10|333333=test|... // Response: Reject 8=FIXT.1.1|35=3|45=5|58=Undefined tag received|371=333333|372=D|373=3| ``` **Example: Order Rejected by Exchange** **Scenario**: Trading during maintenance ```fix theme={null} // Sent 8=FIXT.1.1|35=D|11=456|38=10|55=HIGHNY-23DEC31|... // Response: ExecutionReport (Rejected) 8=FIXT.1.1|35=8|11=456|150=8|39=8|58=EXCHANGE_PAUSED|103=2|... ``` Order-entry failures returned by the exchange are sent as ExecutionReport (35=8) with ExecType=Rejected, not as BusinessMessageReject. BusinessMessageReject (35=j) is used for application-layer failures before normal exchange rejection handling, such as rate limiting or listener-session restrictions. **Example: Insufficient Balance** ```fix theme={null} // Response: ExecutionReport 8=FIXT.1.1|35=8|11=789|150=8|39=8|58=INSUFFICIENT_BALANCE|103=3|... ``` ## Troubleshooting ### MsgSeqNum Too High on Logon **Symptom**: Logon fails or the server sends a ResendRequest for messages the client doesn't have. **Cause**: The client is sending a `MsgSeqNum` higher than what the server last saw. This typically happens when the client's local sequence store persists across sessions but the server has reset (e.g. after maintenance or a prior `ResetSeqNumFlag=Y` logon). **Fix**: * **KalshiNR, KalshiDC, KalshiRFQ**: Set `ResetSeqNumFlag<141>=Y` on every Logon. These sessions require it; Logon will be rejected without it. * **KalshiRT, KalshiPT**: If you don't need to recover missed messages, set `ResetSeqNumFlag<141>=Y` to reset both sides to 1. If you do need retransmission continuity, ensure your local sequence store matches the server's state. If using QuickFIX, set `ResetOnLogon=Y` in your session config for non-retransmission sessions. ### SendingTime Rejected **Symptom**: Reject (35=3) with `SessionRejectReason<373>=10`. **Cause**: The client's clock is more than 30 seconds off from the server. Sync your system clock via NTP. ### Duplicate Session ("already exists") **Symptom**: Logout (35=5) immediately after Logon with `Text<58>="already exists"`. **Cause**: Another FIX connection is already active with the same API key. Only one connection is allowed per API key. This can also occur if a previous connection was not cleanly closed and the server hasn't yet detected the disconnect. **Fix**: Ensure the previous session is fully disconnected before reconnecting. If the prior connection was lost unexpectedly, wait for the server's heartbeat timeout to expire (up to 60 seconds depending on your `HeartbeatInt` setting) before retrying. Use separate API keys for concurrent connections. ### Logon Signature Rejected **Symptom**: Logout immediately after Logon with a signature error. **Cause**: The `SendingTime` used in the pre-hash string doesn't match the `SendingTime<52>` in the actual Logon message. If using a FIX library, the library may auto-populate `SendingTime`. Use that exact value when computing the signature, not a separately generated timestamp. # Listener Sessions Source: https://docs.kalshi.com/fix/listener-sessions Real-time read-only feed of execution reports from your trading session ## Overview A listener session provides a **real-time, read-only stream** of execution reports from your trading session. This is what most exchanges refer to as a "drop copy": a live shadow feed of all fills and order state changes. Kalshi's [Drop Copy session](/fix/drop-copy) (KalshiDC) is a separate request-response tool for querying historical execution reports, not a live feed. ## How It Works A listener session is not a separate endpoint. It is a **mode** enabled on a standard KalshiNR or KalshiRT order entry session by setting `ListenerSession=Y` (tag 20126) during Logon. Once connected, the listener session receives the same execution reports as your active trading session in real time, but **cannot send any orders or modifications**. Listener sessions connect to the same KalshiNR or KalshiRT endpoints listed on the [Connectivity](/fix/connectivity) page. A **separate API key** is required (read-only scope is sufficient). ## Logon Configuration ### Required Logon Fields | Tag | Name | Value | Description | | ----- | ---------------------- | ----- | ------------------------------- | | 20126 | ListenerSession | Y | Enables listen-only mode | | 21011 | SkipPendingExecReports | Y | Required when ListenerSession=Y | ### Restrictions The following Logon flags are **not compatible** with listener sessions: | Tag | Name | Restriction | | ---- | ------------------------ | ---------------------- | | 8013 | CancelOrdersOnDisconnect | Must be N (or omitted) | **Example Logon:** ```fix theme={null} 8=FIXT.1.1|35=A|98=0|108=30|1137=9|20126=Y|21011=Y|96=| ``` ## What You Receive Listener sessions receive **ExecutionReport (35=8)** messages for all order activity on your account, including: * New order acknowledgements * Fills and partial fills * Order cancellations * Order replacements ## What You Cannot Do Listener sessions are strictly read-only. The following message types will be **rejected**: * NewOrderSingle (35=D) * OrderCancelRequest (35=F) * OrderCancelReplaceRequest (35=G) * OrderMassCancelRequest (35=q) * QuoteRequest / RFQ creation * Quote acceptance # Market Settlement Source: https://docs.kalshi.com/fix/market-settlement Settlement reports for market outcomes and position resolution See [Market Settlement](/getting_started/market_settlement) for an overview. Settlement reports are available on **KalshiPT** sessions by default, unless `ReceiveSettlementReports=N` (tag 20127) is set during Logon, and on **KalshiRT** sessions with `ReceiveSettlementReports=Y`. ## Market Settlement Report (35=UMS) Provides settlement details for a specific market. ### Message Structure | Tag | Name | Description | Required | | ----- | ----------------------------- | -------------------------------------------------------------------- | -------- | | 20105 | MarketSettlementReportID | Unique settlement identifier | Yes | | 55 | Symbol | Market ticker (e.g., NHIGH-23JAN02-66) | Yes | | 715 | ClearingBusinessDate | Date settlement cleared (YYYYMMDD) | Yes | | 20106 | TotNumMarketSettlementReports | Total number of settlement reports in sequence | No | | 20107 | MarketResult | Result of the market when determined: `yes`, `no`, or `scalar` | Yes | | 893 | LastFragment | Last page indicator (Y/N) | No | | 730 | SettlementPrice | Settlement price of market in cents (2 decimal places, e.g. `30.60`) | Yes | ### Repeating Groups Collateral changes and fees are nested inside each `NoMarketSettlementPartyIDs` entry. #### Party Information (NoMarketSettlementPartyIDs) | Tag | Name | Description | | ----- | -------------------------- | ------------------------------------- | | 20108 | NoMarketSettlementPartyIDs | Number of parties | | 20109 | MarketSettlementPartyID | Unique identifier for party | | 20110 | MarketSettlementPartyRole | Type of party (Customer Account\<24>) | | 704 | LongQty | Decimal quantity of YES position held | | 705 | ShortQty | Decimal quantity of NO position held | #### Collateral Changes (NoCollateralAmountChanges) | Tag | Name | Description | | ---- | ------------------------- | ----------------------------------------------------------------------- | | 1703 | NoCollateralAmountChanges | Number of collateral changes (should be only 1 - payout balance change) | | 1704 | CollateralAmountChange | Delta in dollars | | 1705 | CollateralAmountType | `BALANCE` or `PAYOUT` | #### Fees (NoMiscFees) | Tag | Name | Description | | --- | ------------ | ---------------------------------------- | | 136 | NoMiscFees | Number of fee entries (always 1) | | 137 | MiscFeeAmt | Fee amount in dollars (zero when no fee) | | 138 | MiscFeeCurr | Currency (USD) | | 139 | MiscFeeType | Type of fee (Exchange fees\<4>) | | 891 | MiscFeeBasis | Unit for fee (Absolute\<0>) | ## Example Settlement Report ```fix theme={null} // Market settled as "yes", no fees 8=FIXT.1.1|35=UMS| 20105=settle-123|55=HIGHNY-23DEC31|715=20231231| 20107=yes|730=100.00| 20108=1| 20109=user-456|20110=24| 704=100|705=0| 1703=1| 1704=100.00|1705=PAYOUT| 136=1| 137=0.00|138=USD|139=4|891=0| 893=Y| ``` ```fix theme={null} // Market settled as "yes", with sub-cent rounding fee 8=FIXT.1.1|35=UMS| 20105=settle-456|55=HIGHNY-23DEC31|715=20231231| 20107=yes|730=100.00| 20108=1| 20109=user-789|20110=24| 704=100|705=0| 1703=1| 1704=100.00|1705=PAYOUT| 136=1| 137=0.006|138=USD|139=4|891=0| 893=Y| ``` The first example shows: * Market HIGHNY-23DEC31 settled as "yes" * User held 100 Yes contracts * Received \$100.00 payout to balance * Zero settlement fees The second example shows: * Same market, different user * $100.00 payout with a $0.006 rounding fee ## Pagination Large settlement batches may span multiple messages: | Tag | Use Case | | ----- | ----------------------------------------- | | 20106 | Total number of reports in batch | | 893 | LastFragment=N for more pages, Y for last | **Important:** The `MarketSettlementReportID` (tag 20105) will be different across paginated responses. Each page of results generates a new unique settlement ID. Use the `Symbol` (tag 55) ticker to identify fragments belonging to the same paginated settlement. # Order Entry Source: https://docs.kalshi.com/fix/order-entry Submit, modify, and cancel orders through FIX messages ## New Order Single (35=D) Used to submit a new order to the Exchange. | Tag | Name | Type | Required | Description | | ----- | ----------------------- | ------------ | -------- | ----------------------------------------------------------------------------------------------------------- | | 11 | ClOrdID | String | Y | Client order ID for idempotency. UUID preferred, max 64 chars. Must not match any open order. | | 18 | ExecInst | Char | N | `6`=Post Only | | 38 | OrderQty | Decimal | Y | Quantity of contracts. Fractional quantities supported. | | 40 | OrdType | Char | Y | `2`=Limit | | 44 | Price | Integer | Y | Price per contract in cents (1–99). | | 54 | Side | Char | Y | `1`=Buy (Yes), `2`=Sell (No) | | 55 | Symbol | String | Y | Market ticker (e.g. `EURUSD-23JUN2618-B1.087`) | | 59 | TimeInForce | Char | N | `0`=Day (expires 11:59:59.999pm ET), `1`=GTC, `3`=IOC, `4`=FOK, `6`=GTD. Past GTD dates are treated as IOC. | | 126 | ExpireTime | UTCTimestamp | C | Required when TimeInForce=GTD. | | 448 | PartyID | UUID | N | FCM only. Sub-account identifier. | | 452 | PartyRole | Integer | N | FCM only. `24`=Customer Account. Required when using PartyID. | | 453 | NoPartyIDs | Integer | N | FCM only. Number of parties (only 1 supported). | | 79 | AllocAccount | Integer | N | Subaccount number (0–32). Alternative to NoPartyIDs. | | 526 | SecondaryClOrdID | UUID | N | [Order group](/getting_started/order_groups) identifier. | | 2964 | SelfTradePreventionType | Integer | N | `1`=Taker At Cross (default), `2`=Maker | | 21006 | CancelOrderOnPause | Boolean | N | Cancel order if trading is paused. | | 21009 | MaxExecutionCost | Decimal | N | Max execution cost in dollars. Order canceled if unable to fill within cost. | ```fix Example New Order theme={null} 8=FIXT.1.1|9=200|35=D|34=5|52=20230809-12:34:56.789|49=your-api-key|56=KalshiNR| 11=550e8400-e29b-41d4-a716-446655440000|38=10|40=2|54=1|55=HIGHNY-23DEC31|44=75| 59=1|10=123| ``` ## Order Cancel/Replace Request (35=G) Used to modify an existing order without canceling it. ### Supported Modifications * **OrderQty**: Increases or decreases the quantity of your order, note that increasing the quantity for the same point means forfeiting your queue position * **Price**: Changes the limit price of your order | Tag | Name | Type | Required | Description | | --- | ------------ | ------- | -------- | ---------------------------------------------------------------------------------------- | | 11 | ClOrdID | String | Y | Unique modification request ID. UUID preferred, max 64 chars. | | 37 | OrderID | String | N | Exchange-assigned order identifier. | | 38 | OrderQty | Decimal | Y | New total quantity. If equal to filled qty, order is canceled. If less, rejected. | | 40 | OrdType | Char | Y | `2`=Limit | | 41 | OrigClOrdID | String | Y | ClOrdID of the order to modify. | | 44 | Price | Integer | N | New price in cents (1–99). Required if changing price. | | 54 | Side | Char | Y | Must match original order. | | 55 | Symbol | String | Y | Must match original order. | | 448 | PartyID | UUID | N | FCM only. Must match original order. | | 452 | PartyRole | Integer | N | FCM only. `24`=Customer Account. Must match original order. Required when using PartyID. | | 453 | NoPartyIDs | Integer | N | FCM only. Must match original order (only 1 supported). | | 79 | AllocAccount | Integer | N | Subaccount number (0–32). Must match original order. | ## Order Cancel Request (35=F) Cancel all remaining quantity of an existing order. | Tag | Name | Type | Required | Description | | --- | ------------ | ------- | -------- | ---------------------------------------------------------------------------------------- | | 11 | ClOrdID | String | Y | Unique cancel request ID. UUID preferred, max 64 chars. | | 37 | OrderID | String | N | Exchange-assigned order identifier. | | 41 | OrigClOrdID | String | Y | ClOrdID of the order to cancel. | | 54 | Side | Char | Y | Must match original order. | | 55 | Symbol | String | Y | Must match original order. | | 448 | PartyID | UUID | N | FCM only. Must match original order. | | 452 | PartyRole | Integer | N | FCM only. `24`=Customer Account. Must match original order. Required when using PartyID. | | 453 | NoPartyIDs | Integer | N | FCM only. Must match original order (only 1 supported). | | 79 | AllocAccount | Integer | N | Subaccount number (0–32). Must match original order. | ## Execution Report (35=8) Sent by the exchange to reflect order state changes. | Tag | Name | Type | Required | Description | | --- | ------------ | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------- | | 6 | AvgPx | Decimal | Y | Average price of all fills on this order. | | 11 | ClOrdID | String | Y | ClOrdID from the last message that changed the order. | | 14 | CumQty | Decimal | Y | Total quantity filled so far. | | 17 | ExecID | String | Y | Unique sequenced report ID (`int;int` format, e.g. `4;7`). Monotonically increasing. `"-1;-1"` for PENDING reports. | | 31 | LastPx | Integer | C | Fill price in cents. Present only for ExecType=Trade. | | 32 | LastQty | Decimal | C | Fill quantity. Present only for ExecType=Trade. | | 37 | OrderID | String | Y | Exchange-assigned order identifier. | | 38 | OrderQty | Decimal | Y | Total order quantity. OrderQty = CumQty + LeavesQty. | | 39 | OrdStatus | Char | Y | Current order status. See Order Status below. | | 41 | OrigClOrdID | String | C | Previous ClOrdID. Present for Replaced/Canceled orders. | | 44 | Price | Integer | C | Price per contract in cents. | | 54 | Side | Char | Y | `1`=Buy (Yes), `2`=Sell (No) | | 55 | Symbol | String | Y | Market ticker. | | 58 | Text | String | N | Human-readable result description. See Text Field Values below. | | 60 | TransactTime | UTCTimestamp | C | Timestamp of the triggering event. | | 103 | OrdRejReason | Integer | C | Rejection reason. Present when ExecType=Rejected. See below. | | 126 | ExpireTime | UTCTimestamp | C | Expiration timestamp. 11:59pm ET for Day orders. | | 150 | ExecType | Char | Y | Report reason. See Execution Types below. | | 151 | LeavesQty | Decimal | Y | Remaining quantity open for execution. | | 448 | PartyID | UUID | N | FCM only. Sub-account identifier. | | 452 | PartyRole | Integer | N | FCM only. `24`=Customer Account. Present when PartyID is present. | | 453 | NoPartyIDs | Integer | N | FCM only. Number of parties (only 1 supported). | | 79 | AllocAccount | Integer | C | Subaccount number (0–32). Present if order was placed for a subaccount. | ### Order Status (39) * **New\<0>**: Active order, no fills * **Partially Filled\<1>**: Some quantity filled * **Filled\<2>**: Completely filled * **Canceled\<4>**: Canceled (may have partial fills) * **Pending Cancel\<6>**: Cancel pending * **Rejected\<8>**: Order rejected * **Pending New\**: Order pending acceptance * **Expired\**: Time in force expired * **Pending Replace\**: Modification pending By default, expiry-style system cancellations are reported as **Canceled\<4>**.\ If Logon tag **21012 (UseExpiredOrdStatus)=Y**, expiry-style system cancellations (CloseCancel and OrderExpiryCancel) are reported as **Expired\**. ### Order Rejection Reasons (103) * **Unknown symbol\<1>** * **Exchange closed\<2>** * **Order exceeds limit\<3>** * **Too late to enter\<4>** * **Duplicate order\<6>** * **Stale order\<8>** * **Unsupported order characteristic\<11>** * **Incorrect quantity\<13>** * **Unknown account\<15>** * **Other\<99>** ### Execution Types (150) * **New\<0>**: Order accepted * **Trade\**: Order filled (partial or complete) * **Canceled\<4>**: Order canceled * **Replaced\<5>**: Order modified * **Rejected\<8>**: Order rejected * **Expired\**: Order expired * **Pending New\**: Order pending acceptance * **Pending Cancel\<6>**: Cancel pending * **Pending Replace\**: Modification pending ### Text Field Values (58) Common values for the Text field in Execution Reports: * **EXCHANGE\_UNAVAILABLE** - Catch-all for Exchange outage or unmapped errors, maps to OrdRejReason "Other" * **MARKET\_ALREADY\_CLOSED** - maps to OrdRejReason "Exchange closed" * **MARKET\_INACTIVE** - maps to OrdRejReason "Exchange closed" * **MARKET\_NOT\_FOUND** - maps to OrdRejReason "Unknown symbol" * **SELF\_CROSS\_ATTEMPT** - maps to ExecutionType "Canceled" * **SELF\_CROSS\_ATTEMPT\_PARTIALLY\_FILLED** - maps to ExecutionType "Canceled" * **ORDER\_ALREADY\_EXISTS** - maps to OrdRejReason "Duplicate order" * **EXCEEDED\_ORDER\_GROUP\_RISK\_LIMIT** - maps to OrdRejReason "Order exceeds limit" * **INSUFFICIENT\_BALANCE** - maps to OrdRejReason "Order exceeds limit" * **EXCHANGE\_PAUSED** - maps to OrdRejReason "Exchange closed" * **TRADING\_PAUSED** - maps to OrdRejReason "Exchange closed" * **INVALID\_ORDER** - maps to OrdRejReason "Unsupported order characteristic" * **ORDER\_GROUP\_NOT\_FOUND** - maps to OrdRejReason "Unsupported order characteristic" * **EXCEEDED\_PER\_MARKET\_RISK\_LIMIT** - maps to OrdRejReason "Order exceeds limit" * **EXCEEDED\_SELL\_POSITION\_FLOOR** - maps to OrdRejReason "Order exceeds limit" * **CUSTOMER\_ACCOUNT\_NOT\_FOUND** - maps to OrdRejReason "Unknown account" * **PERMISSION\_DENIED\_FOR\_CUSTOMER\_ACCOUNT** - maps to OrdRejReason "Unknown account" * **FOK\_INSUFFICIENT\_VOLUME** - maps to ExecutionType "Canceled" * **POST\_ONLY\_CROSS** - maps to OrdRejReason "Other" * **ORDER\_GROUP\_CANCEL** - maps to ExecutionType "Canceled" * **TAKER\_CANCEL\_FOR\_SELF\_TRADE\_PREVENTION** - maps to ExecutionType "Canceled" * **MAKER\_CANCEL\_FOR\_SELF\_TRADE\_PREVENTION** - maps to ExecutionType "Canceled" * **IMMEDIATE\_OR\_CANCELLED** - maps to ExecutionType "Canceled" * **EXPIRED** - maps to OrdRejReason "Stale order" (RFQ quote had expired when the order arrived) ### OrderCancelReject (35=9) Exchange-side amend and cancel failures are returned as OrderCancelReject (35=9), not ExecutionReport. | Text (58) | CxlRejReason (102) | | ----------------------------- | ----------------------- | | `INVALID_AMEND_QTY_FOR_ORDER` | Broker | | `CANNOT_UPDATE_FILLED_ORDER` | Broker | | `SELF_CROSS_ATTEMPT` | Invalid price increment | ### Position and Fee Information When ExecType=Trade: | Tag | Name | Description | | ---- | ------------------ | -------------------------------------------------- | | 704 | LongQty | Net Yes position after trade as a decimal quantity | | 705 | ShortQty | Net No position after trade as a decimal quantity | | 136 | NoMiscFees | Number of fees | | 137 | MiscFeeAmt | Total fees in dollars | | 138 | MiscFeeCurr | Currency (USD) | | 139 | MiscFeeType | Exchange Fees\<4> | | 891 | MiscFeeBasis | Fee unit (always ABSOLUTE\<0>) | | 880 | TrdMatchID | Unique trade identifier | | 1057 | AggressorIndicator | Taker/Maker flag | ### Collateral Changes | Tag | Name | Description | | ---- | ------------------------- | ---------------------------- | | 1703 | NoCollateralAmountChanges | Number of collateral changes | | 1704 | CollateralAmountChange | Delta in dollars | | 1705 | CollateralAmountType | BALANCE or PAYOUT | ### Party Information Party fields from the original order request are echoed back in ExecutionReports: | Tag | Name | Description | | --- | ------------ | ------------------------------------ | | 453 | NoPartyIDs | Number of parties (for sub-accounts) | | 448 | PartyID | Sub-account identifier | | 452 | PartyRole | Customer Account\<24> | | 79 | AllocAccount | Subaccount number (0-32) | ### Rejection Reasons (102) * **Too late to cancel\<0>**: Order already filled * **Unknown order\<1>**: Order not found * **Other\<99>**: See Text field ## Mass Cancel Request (35=q) Cancel all orders for the trading session. Only available on KalshiNR (NewOrderMode) sessions. | Tag | Name | Description | | --- | --------------------- | ---------------------- | | 11 | ClOrdID | Unique request ID | | 530 | MassCancelRequestType | Cancel for session\<6> | ## Mass Cancel Report (35=r) Response to mass cancel request. | Tag | Name | Description | | --- | ---------------------- | --------------------------- | | 11 | ClOrdID | Request ID | | 37 | OrderID | Operation ID | | 531 | MassCancelResponse | Success\<6> or Rejected\<0> | | 532 | MassCancelRejectReason | If rejected | Individual ExecutionReports will follow for each canceled order. # Order Groups Source: https://docs.kalshi.com/fix/order-groups Manage order groups for automatic position management For an overview of order groups and how they work, see [Order Groups](/getting_started/order_groups). ## Order Group Request (35=UOG) Manage order groups with Create, Reset, Delete, Trigger, and Update operations. ### Required Fields | Tag | Name | Description | Type/Values | | ----- | ---------------- | -------------------- | ---------------------------------------------------------- | | 20131 | OrderGroupAction | Operation to perform | Create\<1>, Reset\<2>, Delete\<3>, Trigger\<4>, Update\<5> | ### Optional Fields | Tag | Name | Description | Type/Values | | --- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | | 79 | AllocAccount | Subaccount number (0-32). When provided on any action, the request targets the order group belonging to that subaccount. Omit (or set to 0) to operate on the primary account. | Integer | Order groups are scoped per subaccount. An `OrderGroupID` created under `AllocAccount=2` cannot be reset, updated, deleted, or triggered without also passing `AllocAccount=2` on the follow-up request. If the AllocAccount value does not match the group's owning subaccount, the exchange returns an `ORDER_GROUP_NOT_FOUND` business reject. ### Fields by Action #### Create (Action=1) | Tag | Name | Description | Required | | ----- | ------------------------ | ---------------------------------------------- | -------- | | 20132 | OrderGroupContractsLimit | Maximum contracts allowed (1-1,000,000) | Yes | | 79 | AllocAccount | Subaccount number (0-32) to own the new group. | No | The OrderGroupID is generated by the server and returned in the response. Do not include tag 20130 in Create requests. #### Reset (Action=2) | Tag | Name | Description | Required | | ----- | ------------ | --------------------------------------------- | -------- | | 20130 | OrderGroupID | ID of group to reset | Yes | | 79 | AllocAccount | Subaccount number (0-32) that owns the group. | No | #### Delete (Action=3) | Tag | Name | Description | Required | | ----- | ------------ | --------------------------------------------- | -------- | | 20130 | OrderGroupID | ID of group to delete | Yes | | 79 | AllocAccount | Subaccount number (0-32) that owns the group. | No | Deleting an order group cancels all resting orders in that group. #### Trigger (Action=4) | Tag | Name | Description | Required | | ----- | ------------ | --------------------------------------------- | -------- | | 20130 | OrderGroupID | ID of group to trigger | Yes | | 79 | AllocAccount | Subaccount number (0-32) that owns the group. | No | The Trigger action immediately cancels all orders in the specified order group, regardless of whether the contracts limit has been reached. This is useful for manual risk management or emergency order cancellation. #### Update (Action=5) | Tag | Name | Description | Required | | ----- | ------------------------ | --------------------------------------------- | -------- | | 20130 | OrderGroupID | ID of group to update | Yes | | 20132 | OrderGroupContractsLimit | New maximum contracts allowed (1-1,000,000) | Yes | | 79 | AllocAccount | Subaccount number (0-32) that owns the group. | No | If the updated limit would immediately trigger the group (based on the rolling 15-second window), the server cancels all orders in the group and marks it as triggered. No new orders can be placed until the group is reset. **Examples:** ```fix Create Order Group theme={null} 8=FIXT.1.1|9=150|35=UOG|34=5|52=20230809-12:34:56.789|49=your-api-key|56=KalshiNR| 20131=1|20132=5000|10=123| ``` ```fix Reset Order Group theme={null} 8=FIXT.1.1|9=150|35=UOG|34=6|52=20230809-12:34:57.789|49=your-api-key|56=KalshiNR| 20131=2|20130=770e8400-e29b-41d4-a716-446655440002|10=124| ``` ```fix Delete Order Group theme={null} 8=FIXT.1.1|9=150|35=UOG|34=7|52=20230809-12:34:58.789|49=your-api-key|56=KalshiNR| 20131=3|20130=770e8400-e29b-41d4-a716-446655440002|10=125| ``` ```fix Trigger Order Group theme={null} 8=FIXT.1.1|9=150|35=UOG|34=8|52=20230809-12:34:59.789|49=your-api-key|56=KalshiNR| 20131=4|20130=770e8400-e29b-41d4-a716-446655440002|10=126| ``` ```fix Update Order Group Limit theme={null} 8=FIXT.1.1|9=150|35=UOG|34=9|52=20230809-12:35:00.789|49=your-api-key|56=KalshiNR| 20131=5|20130=770e8400-e29b-41d4-a716-446655440002|20132=2500|10=127| ``` ```fix Create Order Group for subaccount 2 theme={null} 8=FIXT.1.1|9=150|35=UOG|34=10|52=20230809-12:35:01.789|49=your-api-key|56=KalshiNR| 20131=1|20132=5000|79=2|10=128| ``` ## Order Group Response (35=UOH) Response to order group management requests. ### Response Fields | Tag | Name | Description | | ----- | ------------------------ | -------------------------------------------------------------------- | | 20130 | OrderGroupID | ID of the order group | | 20132 | OrderGroupContractsLimit | Current contracts limit (only echoed on Create and Update responses) | | 79 | AllocAccount | Subaccount number (0-32) that owns the group | Business-logic errors (e.g. order group not found, exchange-returned errors) are returned as BusinessMessageReject (35=j) messages. Malformed fields (e.g. invalid UUID format for OrderGroupID) produce a session-level Reject (35=3). # RFQ Source: https://docs.kalshi.com/fix/rfq-messages Request for Quote functionality for RFQ creators and market makers ## Overview RFQ functionality involves two types of participants connecting via different FIX sessions: **RFQ Creators** - Users who want to trade via RFQ (connect via **RT mode**): 1. Create RFQ via QuoteRequest (35=R) 2. Receive quotes from market makers via Quote (35=S) 3. Accept a quote via AcceptQuote (35=UA) 4. Receive trade execution via ExecutionReport (35=8) **Market Makers** - Users who provide quotes (connect via **RfqMode**): 1. Receive QuoteRequest from exchange 2. Respond with Quote (35=S) 3. Receive acceptance notification 4. Confirm execution via QuoteConfirm (35=U7) RFQ Creators use the KalshiRT endpoint (same as order entry), which provides message persistence and retransmission support. Market Makers use the KalshiRFQ endpoint to receive RFQ broadcasts and submit quotes. ## Message Flow ### Full RFQ Flow (Creator via FIX) ```mermaid theme={null} sequenceDiagram participant Creator as RFQ Creator participant Exchange participant MarketMaker as Market Maker Creator->>Exchange: QuoteRequest (35=R) Exchange->>Creator: QuoteRequestAck (35=b) Exchange->>MarketMaker: QuoteRequest (35=R) MarketMaker->>Exchange: Quote (35=S) Exchange->>MarketMaker: QuoteStatusReport (35=AI)
Status=PENDING Exchange->>Creator: Quote (35=S) Creator->>Exchange: AcceptQuote (35=UA) Exchange->>Creator: AcceptQuoteStatus (35=UC) Exchange->>MarketMaker: QuoteStatusReport (35=AI)
Status=ACCEPTED MarketMaker->>Exchange: QuoteConfirm (35=U7) Exchange->>MarketMaker: QuoteConfirmStatus (35=U8) Exchange->>Creator: ExecutionReport (35=8) ``` ## QuoteRequest (35=R) This message is used bidirectionally: * **Creator → Exchange**: Create a new RFQ * **Exchange → Market Makers**: Notify of new RFQ ### Creator → Exchange (Create RFQ) | Tag | Name | Type | Required | Description | | ----- | -------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 131 | QuoteReqId | UUID | Y | Client-assigned RFQ identifier | | 146 | NoRelatedSym | Integer | Y | Number of symbols (must be 1) | | 55 | Symbol | String | C | Market ticker. Required unless MVE legs are specified | | 38 | OrderQty | Decimal | C | Number of contracts as a fixed-point decimal. Currently only whole contracts are accepted (for example `5`, `5.0`, or `5.00`). Required unless CashOrderQty is specified | | 152 | CashOrderQty | Decimal | C | Target cost in dollars. Required unless OrderQty is specified | | 453 | NoPartyIDs | Integer | N | Number of parties (only 1 supported) | | 448 | PartyId | String | N | FCM SubtraderId for the customer on whose behalf the RFQ is submitted | | 452 | PartyRole | Integer | N | 24 (CustomerAccount) - required when using PartyId | | 21015 | RestRemainder | Char | N | Y/N - Rest the quote remainder after execution (default: N) | | 21016 | ReplaceExisting | Char | N | Y/N - Whether to delete existing RFQs as part of this RFQ's creation (default: N) | | 20180 | MultivariateCollectionTicker | String | C | Collection ticker for parlay/MVE markets. Use instead of Symbol | | 20181 | NoMultivariateSelectedLegs | Integer | C | Number of MVE legs (repeating group). Required with 20180 | | 20182 | MultivariateSelectedEventTicker | String | Y | Event ticker for the leg | | 20183 | MultivariateSelectedMarketTicker | String | Y | Market ticker for the leg | | 20184 | MultivariateSelectedMarketSide | String | Y | Side for the leg ("yes" or "no") | **MVE/Parlay Support**: Instead of specifying a Symbol, you can submit MVE legs directly. The server will automatically resolve or create the parlay market and return the resolved market ticker in the QuoteRequestAck. ### Exchange → Market Maker (RFQ Notification) | Tag | Name | Type | Required | Description | | ----- | -------------------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------- | | 131 | QuoteReqId | UUID | Y | Server-assigned RFQ identifier | | 146 | NoRelatedSym | Integer | Y | Number of symbols (always 1) | | 55 | Symbol | String | Y | Market ticker | | 38 | OrderQty | Decimal | Y | Number of contracts as a fixed-point decimal. Currently emitted as whole contracts | | 152 | CashOrderQty | Decimal | N | Target cost in dollars (if specified by creator) | | 453 | NoPartyIDs | Integer | N | Number of parties (always 1) | | 448 | PartyId | String | N | Requester public communications ID. This value is pseudonymous and is not the requester's SubtraderId | | 20180 | MultivariateCollectionTicker | String | N | Collection ticker for multivariate markets | | 20181 | NoMultivariateSelectedLegs | Integer | N | Number of MVE legs (repeating group) | | 20182 | MultivariateSelectedEventTicker | String | N | Event ticker for the leg | | 20183 | MultivariateSelectedMarketTicker | String | N | Market ticker for the leg | | 20184 | MultivariateSelectedMarketSide | String | N | Side for the leg ("yes" or "no") | ## QuoteRequestAck (35=b) Exchange response to an inbound QuoteRequest from an RFQ creator. | Tag | Name | Type | Required | Description | | ----- | ---------------- | ------- | -------- | ------------------------------------------------------------------------ | | 131 | QuoteReqId | UUID | Y | Client-assigned RFQ ID (echoed back) | | 303 | QuoteRequestType | Integer | Y | 1 (MANUAL) | | 21023 | RfqId | UUID | C | Server-assigned RFQ ID. Present when an RFQ ID is returned by the server | | 55 | Symbol | String | C | Resolved market ticker. Present when MVE legs were submitted | The server-assigned RFQ ID is returned in tag 21023. Store it if you want to reconcile later Quote or QuoteStatusReport messages to the created RFQ. RFQCancel accepts either your original client-assigned QuoteReqId (tag 131) or the server-assigned RfqId (tag 21023). When creating an RFQ with MVE legs instead of a Symbol, the resolved market ticker is returned in tag 55. This is the market that was created or looked up based on your leg selection. ## Quote (35=S) This message is used bidirectionally: * **Market Maker → Exchange**: Submit a quote for an RFQ * **Exchange → Creator**: Notify creator of a new quote If a new Quote is created when an existing quote for the same market already exists for the user, the exchange will cancel the existing quote. ### Market Maker → Exchange (Submit Quote) | Tag | Name | Type | Required | Description | | ----- | ------------- | ------- | -------- | ---------------------------------------------------------------------------------------------- | | 117 | QuoteId | UUID | Y | Client-assigned quote identifier | | 131 | QuoteReqId | UUID | Y | Server-assigned RFQ ID (from QuoteRequest) | | 55 | Symbol | String | Y | Market ticker | | 132 | BidPx | Integer | C | Yes price in cents (1-99) | | 133 | OfferPx | Integer | C | No price in cents (1-99) | | 79 | AllocAccount | Integer | N | Subaccount number (0-32). If provided, the quote will be created for the specified subaccount. | | 21015 | RestRemainder | Char | N | Y/N - Allow partial fills (default: N) | ### Exchange → Creator (Quote Notification) | Tag | Name | Type | Required | Description | | --- | ---------- | ------- | -------- | ---------------------------------------------------------------------------------- | | 117 | QuoteId | UUID | Y | Quote identifier (use this to accept) | | 131 | QuoteReqId | UUID | Y | Server-assigned RFQ ID | | 55 | Symbol | String | Y | Market ticker | | 132 | BidPx | Decimal | C | Yes price in dollars (e.g. 0.4500). Not present when zero | | 133 | OfferPx | Decimal | C | No price in dollars (e.g. 0.5500). Not present when zero | | 38 | OrderQty | Decimal | N | Number of contracts as a fixed-point decimal. Currently emitted as whole contracts | | 134 | BidSize | Decimal | N | Quantity offered on the Yes side | | 135 | OfferSize | Decimal | N | Quantity offered on the No side | Either BidPx or OfferPx can be zero, but not both. Zero indicates no quote for that side. ## QuoteStatusReport (35=AI) A QuoteStatusReport is sent by the exchange: 1. In response to a Quote. Status will be PENDING if processed, or REJECTED if rejected 2. When the requester accepts the quote. Status will be ACCEPTED 3. In response to a QuoteCancel. Status will be CANCELLED | Tag | Name | Type | Required | Description | | --- | ------------ | ------- | -------- | --------------------------------------------------------------------------- | | 117 | QuoteId | String | Y | Quote identifier (empty if rejected) | | 131 | QuoteReqId | String | Y | Request reference | | 79 | AllocAccount | Integer | C | Subaccount number (0-32). Present if the quote was created for a subaccount | | 297 | QuoteStatus | Integer | Y | Current status | | 38 | OrderQty | Decimal | C | Original RFQ contract size if specified. | | 132 | BidPx | Integer | C | Yes price in cents. Only integer part considered. Not present if REJECTED | | 133 | OfferPx | Integer | C | No price in cents. Only integer part considered. Not present if REJECTED | | 134 | BidSize | Decimal | C | Yes contract size offered by the quote. | | 135 | OfferSize | Decimal | C | No contract size offered by the quote. | | 54 | AcceptedSide | Char | C | Side accepted (1=Yes, 2=No). Only present if ACCEPTED | | 58 | Text | String | C | Rejection reason. Only present if REJECTED | ### Quote Status Values (297) * **ACCEPTED\<0>**: Requester accepted the quote * **REJECTED\<5>**: Exchange rejected the quote * **PENDING\<10>**: Quote processed, awaiting action * **CANCELLED\<17>**: Quote cancelled ## QuoteCancel (35=Z) Market maker cancels an active quote. | Tag | Name | Type | Required | Description | | --- | ------- | ------ | -------- | --------------- | | 117 | QuoteId | String | Y | Quote to cancel | Exchange responds with QuoteStatusReport (Status=CANCELLED). ## QuoteCancelStatus (35=U9) Response to QuoteCancel from exchange. | Tag | Name | Type | Required | Description | | --- | ----------------- | ------- | -------- | ---------------------------------------- | | 117 | QuoteId | String | Y | Quote identifier | | 298 | QuoteCancelStatus | Integer | Y | CANCELED(0) or REJECTED(1) | | 58 | RejectReason | String | C | Present if QuoteCancelStatus is REJECTED | ## QuoteConfirm (35=U7) Market maker confirms willingness to execute after quote acceptance. | Tag | Name | Type | Required | Description | | --- | ------- | ------ | -------- | ----------------- | | 117 | QuoteId | String | Y | Accepted quote ID | Quote must be confirmed within 30 seconds of acceptance or it will be voided. ## QuoteConfirmStatus (35=U8) Exchange response to quote confirmation. | Tag | Name | Type | Required | Description | | ----- | ------------------ | ------- | -------- | ----------------------------------------- | | 117 | QuoteId | String | Y | Quote identifier | | 21010 | QuoteConfirmStatus | Integer | Y | ACCEPTED(0) or REJECTED(1) | | 58 | RejectReason | String | C | Present if QuoteConfirmStatus is REJECTED | ## AcceptQuote (35=UA) RFQ creator accepts a quote from a market maker. | Tag | Name | Type | Required | Description | | ----- | ----------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 117 | QuoteId | UUID | Y | Quote to accept | | 54 | Side | Char | Y | FIX side (1=BUY, 2=SELL). For AcceptQuote, BUY accepts the maker's NO quote and SELL accepts the maker's YES quote. | | 38 | OrderQty | Decimal | N | Contracts to accept as a fixed-point decimal. Currently only whole contracts are accepted | | 11 | ClOrdID | String | N | Client order ID | | 453 | NoPartyIDs | Integer | N | Number of parties (only 1 supported) | | 448 | PartyId | String | N | FCM SubtraderId for the customer on whose behalf the accept is submitted | | 452 | PartyRole | Integer | N | 24 (CustomerAccount). Required when using PartyId | | 21022 | PreferBetterQuote | Char | N | Y/N - When set to Y, the exchange will select the best available quote for the RFQ rather than the specified quote. The best quote must be at least as good as the requested quote. Default: N | ## AcceptQuoteStatus (35=UC) Exchange response to AcceptQuote. | Tag | Name | Type | Required | Description | | ----- | ----------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | 117 | QuoteId | String | Y | Quote identifier | | 21025 | AcceptQuoteStatus | Integer | Y | ACCEPTED(0) or REJECTED(1) | | 21024 | AcceptedQuoteId | UUID | C | Present when the accept succeeds. The quote that was actually accepted. When PreferBetterQuote is used, this may differ from the requested QuoteId | | 11 | ClOrdID | String | C | Echoed back when provided on the AcceptQuote request | | 58 | Text | String | C | Rejection reason if REJECTED | ## RFQCancel (35=UE) RFQ creator cancels/deletes an active RFQ. | Tag | Name | Type | Required | Description | | ----- | ---------- | ------- | -------- | ---------------------------------------------------------------------------------------- | | 131 | QuoteReqId | UUID | C | Client-assigned RFQ ID from the original QuoteRequest. Required unless RfqId is provided | | 21023 | RfqId | UUID | C | Server-assigned RFQ ID from QuoteRequestAck. Required unless QuoteReqId is provided | | 453 | NoPartyIDs | Integer | N | Number of parties (only 1 supported) | | 448 | PartyId | String | N | FCM SubtraderId for the customer on whose behalf the RFQ is canceled | | 452 | PartyRole | Integer | N | 24 (CustomerAccount). Required when using PartyId | ## RFQCancelStatus (35=UB) Exchange response to RFQCancel. | Tag | Name | Type | Required | Description | | ----- | --------------- | ------- | -------- | ---------------------------------------------------------- | | 131 | QuoteReqId | String | Y | RFQ identifier (echoes back the ID from RFQCancel request) | | 21013 | RFQCancelStatus | Integer | Y | CANCELED(0) or REJECTED(1) | | 58 | Text | String | C | Rejection reason if REJECTED | ## QuoteRequestReject (35=AG) Exchange notifies that an RFQ creation request was rejected or that a quote request was cancelled. | Tag | Name | Type | Required | Description | | --- | ------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------- | | 58 | Text | String | Y | Reason the RFQ creation was rejected or the quote request was cancelled | | 131 | QuoteReqId | String | Y | Request identifier | | 658 | QuoteRequestRejectReason | Integer | Y | UNKNOWN\_SYMBOL(1), QUOTE\_REQUEST\_EXCEEDS\_LIMIT(3), INSUFFICIENT\_CREDIT(11), or OTHER(99) | Market makers do not send QuoteRequestReject when ignoring a request. ## Example Workflow ### RFQ Creator Flow ```fix Create RFQ (Creator → Exchange) theme={null} 8=FIXT.1.1|35=R|131=client-req-123|146=1|55=HIGHNY-23DEC31|38=100| ``` ```fix Create RFQ with MVE Legs (Creator → Exchange) theme={null} 8=FIXT.1.1|35=R|131=client-req-456|146=1|38=100|20180=PARLAY-COLLECTION|20181=2|20182=EVENT1|20183=MKT1|20184=yes|20182=EVENT2|20183=MKT2|20184=no| ``` ```fix QuoteRequestAck (Exchange → Creator) theme={null} 8=FIXT.1.1|35=b|131=client-req-123|303=1|21023=server-rfq-456| ``` ```fix QuoteRequestAck with Resolved Ticker (Exchange → Creator) theme={null} 8=FIXT.1.1|35=b|131=client-req-456|303=1|21023=server-rfq-789|55=PARLAY-MKT-ABC| ``` ```fix Quote Notification (Exchange → Creator) theme={null} 8=FIXT.1.1|35=S|117=quote-789|131=server-rfq-456|55=HIGHNY-23DEC31|132=0.7500|133=0.2500|38=100| ``` ```fix Accept Quote (Creator → Exchange) theme={null} 8=FIXT.1.1|35=UA|117=quote-789|54=1|38=100|11=client-accept-123| ``` ```fix AcceptQuoteStatus (Exchange → Creator) theme={null} 8=FIXT.1.1|35=UC|117=quote-789|21025=0|21024=quote-789|11=client-accept-123| ``` ```fix Cancel RFQ (Creator → Exchange) theme={null} 8=FIXT.1.1|35=UE|131=client-req-123| ``` ```fix RFQCancelStatus (Exchange → Creator) theme={null} 8=FIXT.1.1|35=UB|131=client-req-123|21013=0| ``` ### Market Maker Flow ```fix QuoteRequest (Exchange → MM) theme={null} 8=FIXT.1.1|35=R|131=server-rfq-456|146=1|55=HIGHNY-23DEC31|38=100|453=1|448=anon-456| ``` ```fix Quote Response (MM → Exchange) theme={null} 8=FIXT.1.1|35=S|117=quote-789|131=server-rfq-456|55=HIGHNY-23DEC31|132=75|133=25| ``` ```fix Quote Status Pending (Exchange → MM) theme={null} 8=FIXT.1.1|35=AI|117=quote-789|131=server-rfq-456|297=10|38=100|132=75|133=25| ``` ```fix Quote Accepted (Exchange → MM) theme={null} 8=FIXT.1.1|35=AI|117=quote-789|131=server-rfq-456|297=0|54=1|38=100| ``` ```fix Quote Confirmation (MM → Exchange) theme={null} 8=FIXT.1.1|35=U7|117=quote-789| ``` ```fix QuoteConfirmStatus (Exchange → MM) theme={null} 8=FIXT.1.1|35=U8|117=quote-789|21010=0| ``` # Subpenny Pricing Source: https://docs.kalshi.com/fix/subpenny-pricing Dollar-based pricing format for subpenny precision For the general overview of fixed-point pricing and contract quantities across REST and WebSocket APIs, see [Fixed-Point Migration](/getting_started/fixed_point_migration). ## Technical Specification To enable subpenny precision, include tag **21005** in your Logon message: | Tag | Name | Description | Value | | ----- | ---------- | -------------------------------- | ----- | | 21005 | UseDollars | Enable dollar-based price format | Y | Overview: * **Legacy Format (Cents)**: Prices given in whole cents. E.g. 72 cents = `72`. * **New Format (Dollars)**: Prices normalized to dollars with fixed precision (up to 4 decimal places). Examples: | Cents | FIX Decimal | String Representation | | ----- | ----------------- | --------------------- | | 1.23¢ | Decimal(123, -4) | 0.0123 | | 72.5¢ | Decimal(7250, -4) | 0.725 | | 99¢ | Decimal(9900, -4) | 0.99 | Affected Tags: | Tag | Field Name | Description | | --- | ---------- | ---------------------- | | 6 | AvgPx | Average price of fills | | 31 | LastPx | Price of last fill | | 44 | Price | Order limit price | | 132 | BidPx | Quote bid price | | 133 | OfferPx | Quote ask price | ## Sample Messages ```FIX logon theme={null} 8=FIXT.1.1|9=300|35=A|34=1|52=20250926-21:54:07.001| 96=QhA8659Mhygcm+xE/wb1m...|21005=Y| ^^ Enable dollar format ``` ```FIX new order single theme={null} 8=FIXT.1.1|9=200|35=D|34=2|52=20250926-21:54:16.040| 38=100.0|40=2|44=0.7500|54=1|60=20250926-21:54:16.040| ^^ price 10=092| ``` ```FIX execution report theme={null} 8=FIXT.1.1|9=400|35=8|34=4|52=20250926-21:54:16.159| 6=0.6600|14=100|31=0.7000|32=60|38=100.0000|39=2|44=0.7500| ^^ avgPx ^^ lastPx ^^ price ``` # API Environments and Endpoints Source: https://docs.kalshi.com/getting_started/api_environments REST and WebSocket base URLs for production and demo Kalshi provides separate production and demo environments. Credentials are not shared between environments, so demo API keys only work against demo endpoints and production API keys only work against production endpoints. ## REST API Use these base URLs for the Trade API: | Environment | Recommended base URL | Also supported | | ----------- | -------------------------------------------------- | ----------------------------------------------- | | Production | `https://external-api.kalshi.com/trade-api/v2` | `https://api.elections.kalshi.com/trade-api/v2` | | Demo | `https://external-api.demo.kalshi.co/trade-api/v2` | `https://demo-api.kalshi.co/trade-api/v2` | The `external-api` hosts are dedicated to the external Trade API and are the recommended hosts for API traders. The existing shared hosts remain supported for compatibility with existing clients. Despite the `elections` subdomain, the production Trade API provides access to all Kalshi markets, not only election-related markets. ## WebSocket API Use these WebSocket URLs for the Trade API: | Environment | Recommended URL | Also supported | | ----------- | ------------------------------------------------------ | ------------------------------------------------ | | Production | `wss://external-api-ws.kalshi.com/trade-api/ws/v2` | `wss://api.elections.kalshi.com/trade-api/ws/v2` | | Demo | `wss://external-api-ws.demo.kalshi.co/trade-api/ws/v2` | `wss://demo-api.kalshi.co/trade-api/ws/v2` | ## Request Signing The host does not change the signature payload. Sign the full request path from the API root, without query parameters. For example, all of these hosts use the same signed path for an order request: ```text theme={null} /trade-api/v2/portfolio/orders ``` If the request URL is: ```text theme={null} https://external-api.kalshi.com/trade-api/v2/portfolio/orders?limit=5 ``` sign: ```text theme={null} /trade-api/v2/portfolio/orders ``` not the hostname and not the query string. # API Keys Source: https://docs.kalshi.com/getting_started/api_keys API Key usage This process is the same for the demo or production environment. ## Generating an API Key ### Access the Account Settings Page: Log in to your account and navigate to the "Account Settings" page. You can typically find this option by clicking on your profile picture or account icon in the top-right corner of the application. ### Generate a New API Key In the "Profile Settings" page [https://kalshi.com/account/profile](https://kalshi.com/account/profile), locate the "API Keys" section. Click on the "Create New API Key" button. This action will generate a new API key in the RSA\_PRIVATE\_KEY format. ### Store Your API Key and Key ID: After generating the key, you will be presented with: • Private Key: This is your secret key in RSA\_PRIVATE\_KEY format. • Key ID: This is a unique identifier associated with your private key. **Important**: For security reasons, the private key will not be stored by our service, and you will not be able to retrieve it again once this page is closed. Please make sure to securely copy and save the private key immediately. The key will also be downloaded as txt file with the name provided. ## Using a API Key Each request to Kalshi trading api will need to be signed with the private key generated above. The following header values will need to be provided with each request: `KALSHI-ACCESS-KEY`- the Key ID `KALSHI-ACCESS-TIMESTAMP` - the request timestamp in ms `KALSHI-ACCESS-SIGNATURE`- request hash signed with private key The above signature is generated by signing a concatenation of the timestamp, the HTTP method and the path. **Important**: When signing requests, use the path **without query parameters**. For example, if your request is to `/trade-api/v2/portfolio/orders?limit=5`, sign only `/trade-api/v2/portfolio/orders` (strip the `?` and everything after it). Sample code for generating the required headers is below. For end-to-end examples, see [Quick Start: Authenticated Requests](/getting_started/quick_start_authenticated_requests). ### Python Load the private key stored in a file ```python theme={null} from cryptography.hazmat.primitives import serialization from cryptography.hazmat.backends import default_backend def load_private_key_from_file(file_path): with open(file_path, "rb") as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=None, # or provide a password if your key is encrypted backend=default_backend() ) return private_key ``` Sign text with private key ```python theme={null} import base64 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding, rsa from cryptography.exceptions import InvalidSignature def sign_pss_text(private_key: rsa.RSAPrivateKey, text: str) -> str: message = text.encode('utf-8') try: signature = private_key.sign( message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.DIGEST_LENGTH ), hashes.SHA256() ) return base64.b64encode(signature).decode('utf-8') except InvalidSignature as e: raise ValueError("RSA sign PSS failed") from e ``` Send a request to Kalshi API with signed header ```python theme={null} import requests import datetime current_time = datetime.datetime.now() timestamp = current_time.timestamp() current_time_milliseconds = int(timestamp * 1000) timestampt_str = str(current_time_milliseconds) private_key = load_private_key_from_file('kalshi-key-2.key') method = "GET" base_url = 'https://external-api.demo.kalshi.co' path='/trade-api/v2/portfolio/balance' # Strip query parameters from path before signing path_without_query = path.split('?')[0] msg_string = timestampt_str + method + path_without_query sig = sign_pss_text(private_key, msg_string) headers = { 'KALSHI-ACCESS-KEY': 'a952bcbe-ec3b-4b5b-b8f9-11dae589608c', 'KALSHI-ACCESS-SIGNATURE': sig, 'KALSHI-ACCESS-TIMESTAMP': timestampt_str } response = requests.get(base_url + path, headers=headers) print(response.text) ``` ### Javascript Load the private key stored in a file ```javascript theme={null} const fs = require('fs'); const path = require('path'); function loadPrivateKeyFromFile(filePath) { const absolutePath = path.resolve(filePath); const privateKeyPem = fs.readFileSync(absolutePath, 'utf8'); return privateKeyPem; } ``` Sign text with private key ```javascript theme={null} const crypto = require('crypto'); function signPssText(privateKeyPem, text) { const sign = crypto.createSign('RSA-SHA256'); sign.update(text); sign.end(); const signature = sign.sign({ key: privateKeyPem, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST, }); return signature.toString('base64'); } ``` Send a request to Kalshi API with signed header ```javascript theme={null} const axios = require('axios'); const currentTimeMilliseconds = Date.now(); const timestampStr = currentTimeMilliseconds.toString(); const privateKeyPem = loadPrivateKeyFromFile('path/to/your/private-key.pem'); const method = "GET"; const baseUrl = 'https://external-api.demo.kalshi.co'; const path = '/trade-api/v2/portfolio/balance'; // Strip query parameters from path before signing const pathWithoutQuery = path.split('?')[0]; const msgString = timestampStr + method + pathWithoutQuery; const sig = signPssText(privateKeyPem, msgString); const headers = { 'KALSHI-ACCESS-KEY': 'your-api-key-id', 'KALSHI-ACCESS-SIGNATURE': sig, 'KALSHI-ACCESS-TIMESTAMP': timestampStr }; axios.get(baseUrl + path, { headers }) .then(response => { console.log(response.data); }) .catch(error => { console.error('Error:', error); }); ``` # Test In The Demo Environment Source: https://docs.kalshi.com/getting_started/demo_env Set up and test with Kalshi's demo environment For testing purposes, Kalshi offers a *demo* environment with mock funds. You can access the Demo environment at [https://demo.kalshi.co/](https://demo.kalshi.co/). For safety, credentials are not shared between this environment and production. To set up a Kalshi Demo account, [follow this step-by-step tutorial](https://docs.google.com/presentation/d/e/2PACX-1vRvhUAqRBYzJmt7JCinMXmu6KVWkj-cc7ikDXGConmqjcv4mnlJacgHPcZJ20fWWnrYdubn-oczclKP/pub?start=false\&loop=false\&delayms=3000\&slide=id.p). Demo's recommended Trade API root is `https://external-api.demo.kalshi.co/trade-api/v2`. | Surface | Recommended demo endpoint | Also supported | | -------------- | ------------------------------------------------------ | ------------------------------------------ | | REST Trade API | `https://external-api.demo.kalshi.co/trade-api/v2` | `https://demo-api.kalshi.co/trade-api/v2` | | WebSocket API | `wss://external-api-ws.demo.kalshi.co/trade-api/ws/v2` | `wss://demo-api.kalshi.co/trade-api/ws/v2` | For the full production and demo endpoint list, see [API Environments and Endpoints](/getting_started/api_environments). # Fee Rounding Source: https://docs.kalshi.com/getting_started/fee_rounding How the exchange rounds fees to maintain cent-aligned balances. ## Overview User balances must be exact multiples of **\$0.01** before and after every fill. When a trade produces a sub-cent balance change, the exchange charges a **rounding fee** to bring the balance back to cent alignment. A **fee accumulator** applies rounding across all fills of an order collectively so that the total fee converges to what a single equivalent fill would cost. Every fill produces three fee components: | Component | Description | | ---------------- | -------------------------------------------------------------------------- | | **Trade fee** | Fee from the fee model, rounded up to the nearest \$0.0001 (centicent) | | **Rounding fee** | Sub-cent adjustment that restores cent-alignment (\$0.0000 - \$0.0099) | | **Rebate** | Refund from accumulated rounding overpayment (always a multiple of \$0.01) | **Net fee** = trade fee + rounding fee - rebate (always >= \$0.00) ## Rounding Mechanics Given a fill's `revenue` (signed; negative for buyers) and `trade_fee`: 1. Round trade fee **up** to the nearest \$0.0001 2. Compute `balance_change = revenue - trade_fee` 3. Floor `balance_change` toward negative infinity to the nearest \$0.01 4. `rounding_fee = balance_change - floor(balance_change)` The user's balance changes by `floor(balance_change)`, which is always cent-aligned. ## Fee Accumulator The fee accumulator tracks cumulative rounding overpayment across all fills of an order. Once the accumulated rounding exceeds \$0.01, a whole-cent rebate is issued and the accumulator is reduced by \$0.01. This ensures the total fee across many small fills converges to what a single equivalent fill would cost. The fee accumulator is maintained per order across all fills regardless of whether the fills are taker or maker. If an order initially takes (matching resting orders) and then becomes a resting maker order, the accumulated rounding carries over to subsequent maker fills. ## When Does Rounding Apply? Rounding applies whenever `revenue - trade_fee` has a sub-cent component. This can happen two ways: * **Subpenny prices** (e.g., \$0.0550) — sub-cent revenue from the price itself * **Fractional contracts** (e.g., 0.30 contracts) — sub-cent revenue from the fractional quantity When both apply simultaneously, intermediate values can reach up to 6 decimal places (for example, `$0.3301 * 0.03 = $0.009903`). The worked examples below show each scenario. ## Settlement Rounding Settlement can also create sub-cent balance changes. When that happens, the exchange rounds the posted payout down to the nearest cent and records the fractional remainder as a settlement fee. Example: if a user holds 10.60 YES contracts and the market settles at \$0.5970, the raw payout is `10.60 * \$0.5970 = \$6.3282`. Because posted payouts must be whole-cent amounts, the exchange credits \$6.32 and records the remaining \$0.0082 as a settlement fee. This rounding adjustment is always less than \$0.01 on any posted payout and exists only to keep balances in whole-cent increments. *** ## Worked Examples Buy **3 contracts** at **\$0.055** — filled as three 1-lot matches. Contracts are whole; rounding arises from the sub-cent price. **Fill 1 walkthrough:** ``` revenue = -$0.055 x 1 = -$0.0550 trade fee = $0.0085 (ceiled to centicent) balance change = -$0.0550 - $0.0085 = -$0.0635 floored to -$0.07 rounding fee = $0.07 - $0.0635 = $0.0065 ``` **All fills:** | Fill | Trade Fee | Rounding | Accumulator | Rebate | Net Fee | Balance Change | | ---: | --------: | -------: | ----------: | -------: | -------: | -------------: | | 1 | \$0.0085 | \$0.0065 | \$0.0065 | — | \$0.0150 | -\$0.07 | | 2 | \$0.0085 | \$0.0065 | \$0.0130 | \$0.0100 | \$0.0050 | -\$0.07 | | 3 | \$0.0085 | \$0.0065 | \$0.0095 | — | \$0.0150 | -\$0.07 | On Fill 2, the accumulator reaches \$0.0130 (> \$0.01), triggering a \$0.01 rebate. The net fee drops to \$0.0050 for that fill. Buy **0.90 contracts** at **\$0.50** — filled as three 0.30-lot matches. The price is a whole cent; rounding arises from the fractional quantity. **Fill 1 walkthrough:** ``` revenue = -$0.50 x 0.30 = -$0.1500 trade fee = $0.0041 (ceiled to centicent) balance change = -$0.1500 - $0.0041 = -$0.1541 floored to -$0.16 rounding fee = $0.16 - $0.1541 = $0.0059 ``` **All fills:** | Fill | Trade Fee | Rounding | Accumulator | Rebate | Net Fee | Balance Change | | ---: | --------: | -------: | ----------: | -------: | -------: | -------------: | | 1 | \$0.0041 | \$0.0059 | \$0.0059 | — | \$0.0100 | -\$0.16 | | 2 | \$0.0041 | \$0.0059 | \$0.0118 | \$0.0100 | \$0.0000 | -\$0.16 | | 3 | \$0.0041 | \$0.0059 | \$0.0077 | — | \$0.0100 | -\$0.16 | On Fill 2, the accumulator reaches \$0.0118 (> \$0.01), triggering a \$0.01 rebate. The entire fee is offset, resulting in a \$0.00 net fee for that fill. Buy **0.09 contracts** at **\$0.3301** — filled as three 0.03-lot matches. Both features contribute sub-cent components, pushing intermediates to 6 decimal places. **Fill 1 walkthrough:** ``` revenue = -$0.3301 x 0.03 = -$0.009903 trade fee = $0.0005 (ceiled to centicent) balance change = -$0.009903 - $0.0005 = -$0.010403 floored to -$0.02 rounding fee = $0.02 - $0.010403 = $0.009597 ``` **All fills:** | Fill | Trade Fee | Rounding | Accumulator | Rebate | Net Fee | Balance Change | | ---: | --------: | ---------: | ----------: | -------: | ---------: | -------------: | | 1 | \$0.0005 | \$0.009597 | \$0.009597 | — | \$0.010097 | -\$0.02 | | 2 | \$0.0005 | \$0.009597 | \$0.019194 | \$0.0100 | \$0.000097 | -\$0.02 | | 3 | \$0.0005 | \$0.009597 | \$0.018791 | \$0.0100 | \$0.000097 | -\$0.02 | The accumulator triggers a rebate on both Fill 2 and Fill 3, keeping the total net fee close to the single-fill equivalent. Subpenny prices alone produce 4-decimal-place intermediates. Fractional contracts alone also produce 4-decimal-place intermediates. When combined, intermediates can reach 6 decimal places (e.g., \$0.3301 x 0.03 = \$0.009903). Final balances are always rounded to whole cents. # Fixed-Point Migration Source: https://docs.kalshi.com/getting_started/fixed_point_migration Fixed-point representation for contract quantities and prices. Last Updated: April 17, 2026 ## Overview Kalshi uses fixed-point representation across all APIs. This involves two independent changes: 1. **Subpenny Pricing** — price fields use fixed-point dollar strings (`_dollars` suffix) 2. **Fractional Contracts** — contract count fields use fixed-point strings (`_fp` suffix) The `price_level_structure` field on Market responses indicates which pricing tier is active for a given market. *** ## Subpenny Pricing Prices are represented as fixed-point dollar strings. ```json theme={null} { "price_dollars": "0.1200" } ``` * `*_dollars` fields are fixed-point dollar strings with up to 4 decimal places (e.g., `"0.1200"`) * When combined with fractional contract sizes, intermediate calculations can reach up to 6 decimal places (for example, in fee rounding math) Subpenny pricing is offered on a per-market basis. The `price_level_structure` field on Market responses indicates which pricing tier is active, and the `price_ranges` array provides the exact valid price intervals and tick sizes for that market. ### Price Level Structures | Structure | Ranges | Tick Size | | ------------------- | --------------- | --------- | | `linear_cent` | \$0.00 – \$1.00 | \$0.01 | | `tapered_deci_cent` | \$0.00 – \$0.10 | \$0.001 | | | \$0.10 – \$0.90 | \$0.01 | | | \$0.90 – \$1.00 | \$0.001 | | `deci_cent` | \$0.00 – \$1.00 | \$0.001 | `tapered_deci_cent` provides finer \$0.001 (decicent) precision at the tails of the probability range — below \$0.10 and above \$0.90 — where small absolute price differences represent large relative changes in implied probability. The middle range uses standard \$0.01 (cent) ticks. `deci_cent` applies \$0.001 precision across the entire range. *** ## Fractional Contracts Contract count fields use fixed-point strings and support fractional contract sizes. ```json theme={null} { "count_fp": "10.00" } ``` * `*_fp` fields are strings * Accept 0-2 decimal places on input (responses always emit 2 decimals) * Minimum granularity is 0.01 contracts * In requests where both integer and `_fp` fields are provided, they must match Even if you are not placing fractional orders, you will encounter fractional values elsewhere in the API (for example, fills). One way to prepare is to internally multiply the `_fp` value by 100 and cast to an integer. For example, treating `"1.55"` as 155 units of 1c contracts allows continued use of integer arithmetic. *** ## Fee Rounding Both subpenny pricing and fractional contracts can produce sub-cent balance changes on fills. When this happens, the exchange applies a rounding fee to restore cent-alignment, and a fee accumulator issues rebates to prevent systematic overpayment. See [Fee Rounding](/getting_started/fee_rounding) for the mechanics and worked examples. # Historical Data Source: https://docs.kalshi.com/getting_started/historical_data Accessing historical exchange data via the Kalshi API. ## Overview As trading activity on Kalshi grows, so does the volume of settled markets, completed trades, and fulfilled orders. To keep the live API fast and responsive, Kalshi partitions exchange data into **live** and **historical** tiers. Live endpoints return current and recent data — open and recently closed markets, active orders, and recent fills. Older data that is no longer actively referenced is made available through a separate set of historical endpoints. This separation means that if you query for data that is older than the cutoff (described below), you'll need to use the historical API instead of the standard live endpoints. The partitioning happens for **markets**, **market\_candlesticks**, **trades**, and **orders**. Old **Events** and **Series** will always still be available through their original endpoints. ## How It Works The boundary between live and historical data is defined by a set of **cutoff timestamps**, which you can retrieve at any time via `GET /historical/cutoff`. Any record older than the relevant cutoff must be queried through the corresponding historical endpoint. The cutoff timestamps will be regularly updated, advancing forward over time. The target window for live data is **3 months**. ## Cutoff Timestamps | Field | Partitioned By | Meaning | | ------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `market_settled_ts` | Market settlement time | Markets and their candlesticks that settled before this timestamp are only available via `GET /historical/markets` | | `trades_created_ts` | Trade fill time | Trades that occurred before this timestamp are only available via `GET /historical/trades`. User fills are only available via `GET /historical/fills` | | `orders_updated_ts` | Order cancellation or execution time | Orders canceled or fully executed before this timestamp are only available via `GET /historical/orders` | Resting (active) orders are unaffected and always appear in `GET /portfolio/orders`, regardless of the cutoff. ## Historical Endpoints | Endpoint | Description | | ----------------------------------------------- | ---------------------------------------------- | | `GET /historical/cutoff` | Returns the current cutoff timestamps | | `GET /historical/markets` | Settled markets older than the cutoff | | `GET /historical/markets/{ticker}` | Single historical market by ticker | | `GET /historical/markets/{ticker}/candlesticks` | Candlestick data for historical markets | | `GET /historical/trades` | All trades older than the cutoff | | `GET /historical/fills` | User-scoped trade fills older than the cutoff | | `GET /historical/orders` | Canceled/executed orders older than the cutoff | ## Impacted Live Endpoints The following live endpoints will no longer return data older than the corresponding cutoff: | Live Endpoint | Cutoff Field | Impact | | --------------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------- | | `GET /markets`, `GET /markets/{ticker}` | `market_settled_ts` | Settled markets and their candlesticks older than the cutoff will not appear | | `GET /events` with `with_nested_markets=true` | `market_settled_ts` | Nested markets older than the cutoff will not be included, only markets impacted | | `GET /markets/trades` | `trades_created_ts` | Trades older than the cutoff will not appear | | `GET /portfolio/fills` | `trades_created_ts` | Fills older than the cutoff will not appear | | `GET /portfolio/orders` | `orders_updated_ts` | Completed/canceled orders older than the cutoff will not appear (resting orders are unaffected) | ## Migration Guide 1. **Fetch the cutoff** — call `GET /historical/cutoff` to get the current timestamps. 2. **Route queries accordingly** — if the data you need is older than the relevant cutoff, use the corresponding `GET /historical/...` endpoint instead. 3. **Combine results if needed** — for use cases like building a complete fill history, query both the live and historical endpoints and merge the results. The historical endpoints support the same [cursor-based pagination](/getting_started/pagination) as their live counterparts. # Maintenance and Pauses Source: https://docs.kalshi.com/getting_started/maintenance_and_pauses Scheduled maintenance windows, trading pauses, and exchange pauses ## Scheduled Maintenance Every **Thursday from 3:00 AM to 5:00 AM ET**, Kalshi runs scheduled maintenance. During this window, a **trading pause** is in effect. In rare cases, a more intensive maintenance may require a full **exchange pause** instead. Clients should be prepared for session disconnections during this window and reconnect after 5:00 AM ET. ## Trading Pause vs Exchange Pause | | Trading Pause | Exchange Pause | | ------------------------ | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | **When** | Every Thursday 3:00–5:00 AM ET | Rare; during scheduled maintenance if intensive work is needed, or unscheduled if Kalshi has a temporary outage | | **Place / amend orders** | No | No | | **Cancel orders** | Yes | No | | **Resting orders** | Remain on the book (unless CancelOrderOnPause is set) | Remain on the book (unless CancelOrderOnPause is set) | If an exchange pause occurs outside the scheduled Thursday window, it indicates a temporary Kalshi Exchange outage. ## CancelOrderOnPause When placing an order, you can set `CancelOrderOnPause` to control whether the order is automatically cancelled during either type of pause. | Value | Behavior | | ------------------- | ------------------------------------------------------------------------ | | true / Y | Order is automatically cancelled when a trading or exchange pause begins | | false / N (default) | Order remains resting on the book and resumes when activity reopens | Set this field on order creation: * **REST**: `cancel_order_on_pause` field on the create order request * **FIX**: Tag `21006` (CancelOrderOnPause) on New Order Single (35=D) messages # Making Your First Request Source: https://docs.kalshi.com/getting_started/making_your_first_request Start trading with Kalshi API in under 5 minutes To make your request we recommend testing a public endpoint like [GetMarkets](https://docs.kalshi.com/api-reference/market/get-markets). As you explore our other endpoints, you'll notice some endpoints return an authentication\_error. If you want to experiment with these endpoints, you will need to get [API Keys](https://docs.kalshi.com/getting_started/api_keys). You may also want to sign up for a demo account to test without real funds. The following resources might help you on your journey to exploring Kalshi's markets: * [**Quick Start: Market Data**](/getting_started/quick_start_market_data) * [**Quick Start: Authenticated Requests**](/getting_started/quick_start_authenticated_requests) * [**Discord**](https://discord.gg/kalshi) and check out #dev and #support # Market Lifecycle Source: https://docs.kalshi.com/getting_started/market_lifecycle How markets move from creation to settlement Markets on Kalshi follow a lifecycle from creation through trading to determination and settlement. This page describes the states a market passes through and what to expect at each stage. ## Statuses The REST API returns these statuses on `GET /markets` and `GET /markets/{ticker}`: | Status | Meaning | | ------------- | ----------------------------------------------------------------------------------------- | | `initialized` | Created but not yet open for trading. Transitions to `active` when `open_time` passes. | | `active` | Open for trading. | | `inactive` | Temporarily deactivated by the exchange. Trading is paused but the market has not closed. | | `closed` | Past `close_time`. No new orders accepted. Awaiting determination. | | `determined` | Result is known. Settlement timer is running. | | `disputed` | Result has been challenged. May be re-determined. | | `amended` | Re-determined after a dispute. Settlement timer restarts. | | `finalized` | Settlement complete. Positions have been paid out. Terminal state. | When filtering with `GET /markets?status=`, the values map as follows: | Filter value | Matches | | ------------ | -------------------------------------------------------- | | `unopened` | `initialized` (before `open_time`) | | `open` | `active` | | `paused` | `inactive` | | `closed` | Any market past `close_time` that is not yet `finalized` | | `settled` | `finalized` | ## Transitions Some transitions are implicit (time-based), others are explicit (event-driven). **Implicit (no WebSocket event):** * `initialized` → `active`: when `open_time` passes. There is no `activated` WebSocket event for this transition. * `active` / `inactive` → `closed`: when `close_time` passes. **Explicit (WebSocket event emitted):** * `active` → `inactive`: exchange deactivates the market. Event: `deactivated`. * `inactive` → `active`: exchange reactivates a paused market. Event: `activated`. All resting orders are cancelled on this reactivation. * `closed` → reopened `active`: `close_time` is moved into the future. Events: `close_date_updated`, then `activated`. * Close time updated: `close_time` changes. Event: `close_date_updated`. This can happen when a market is closed ahead of its scheduled close time, including before determination. * `closed` → `determined`: result is set. Event: `determined`. * `determined` / `amended` → `finalized`: positions paid out. Event: `settled`. ## Time fields Markets have several time fields: | Field | Meaning | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `open_time` | When the market opens for trading. | | `close_time` | When trading stops. May be moved earlier if `can_close_early` is true. | | `expected_expiration_time` | When the outcome is expected to be known. | | `latest_expiration_time` | Latest possible expiration time. | | `expiration_time` | Deprecated legacy field. Prefer `latest_expiration_time` for the legacy expiry semantics; use `expected_expiration_time` if you want the forecasted time. | ## Determination and settlement After a market closes and the outcome is known, the market is determined and `result` is set to `yes`, `no`, or `scalar`. A settlement timer then runs for `settlement_timer_seconds`, which is visible in the REST response. During this window the market remains at `determined` and the result may be disputed. Once settlement completes, positions are paid out. In REST, settled markets end up at `finalized` rather than a separate `settled` status, and `settlement_ts` is populated. ## Orders after close Once `close_time` passes, all order operations, including cancellations, are rejected with `MARKET_INACTIVE`. Resting orders are cancelled shortly after close, and cancellation updates are published on the usual user channels. ## WebSocket Market lifecycle events are delivered on two channels: | Channel | Markets covered | Event types | | ------------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------- | | `market_lifecycle_v2` | All markets except MVE (`KXMVE*`) | `created`, `activated`, `deactivated`, `close_date_updated`, `determined`, `settled`, `metadata_updated` | | `multivariate_market_lifecycle` | MVE markets only (`KXMVE*`) | `created`, `activated`, `deactivated`, `close_date_updated`, `determined`, `settled` | Both channels also emit `event_lifecycle` messages when new events are created. The WebSocket `settled` event corresponds to settlement being processed; in REST, settled markets end up at `finalized`. ## FAQ `expected_expiration_time` is the time the event is likely to resolve — for a sports game, typically a few hours after the scheduled start. `close_time` is when the market automatically closes for trading, and may be set well into the future to allow for rescheduling. That means `expected_expiration_time` can be earlier than `close_time`. The market may not be queryable immediately after a `created` event. Retry with backoff. `GET /events` supports a `status` filter with values `unopened`, `open`, `closed`, and `settled`. The filter matches on child market statuses, not an event-level status — an event appears in results if **any** of its child markets has a matching status. For example, an event with four open markets and one settled market matches both `status=open` and `status=settled`. Use `with_nested_markets=true` if you need individual market statuses. # Market Settlement Source: https://docs.kalshi.com/getting_started/market_settlement How market outcomes are determined and positions are resolved Settlement occurs when a market's outcome is determined. Positions are automatically resolved and funds transferred. ## How It Works * **Yes outcome**: Yes contract holders receive \$1 per contract * **No outcome**: No contract holders receive \$1 per contract * Only net positions are settled (after netting) ## Settlement Timing Markets typically settle shortly after expiration, but timing can vary based on market type, data source availability, and manual review requirements. ## Fees Settlement fees are zero for simple yes/no determinations but may apply for sub-cent scalar settlement. The actual payout (`CollateralAmountChange`) is rounded to whole cents. `CollateralAmountChange + MiscFeeAmt` equals the pre-rounding settlement value. ## Protocol-Specific Details * [FIX Market Settlement Messages](/fix/market-settlement) # Order direction (outcome_side and book_side) Source: https://docs.kalshi.com/getting_started/order_direction How direction is expressed on Order, Fill, and Trade responses, and how to migrate from the legacy action/side fields. Direction on every Order, Fill, and Trade response is expressed by two fields that carry the same bit in two vocabularies: * **`outcome_side`** (`yes` | `no`) — which outcome the user is positioned for. A user paying to be long the yes outcome has `outcome_side=yes`; paying to be long the no outcome has `outcome_side=no`. * **`book_side`** (`bid` | `ask`) — same bit in book-vocabulary. **`bid ≡ yes`, `ask ≡ no`** — always. Pick whichever vocabulary fits your integration; you only need one of them to know the trade's direction. On public `Trade` and the `trade` WebSocket channel the fields are named `taker_outcome_side` and `taker_book_side`, since a public trade has no user perspective and reports the taker's side. ## Direction does not change the price `outcome_side` describes directional exposure only; it does not change the order's price. An order at price `p` with `outcome_side=no` is matched by an order at the same price `p` with `outcome_side=yes` — both parties trade at the same price, just on opposite directions. ## Equivalence between (action, side) and outcome\_side Buy-yes and sell-no produce the same directional exposure (long yes); buy-no and sell-yes both produce long no. The new fields make this collapse explicit: | Legacy `action` | Legacy `side` | `outcome_side` | `book_side` | | --------------- | ------------- | -------------- | ----------- | | buy | yes | yes | bid | | sell | no | yes | bid | | buy | no | no | ask | | sell | yes | no | ask | ## Migration `outcome_side` and `book_side` are the canonical way to determine direction going forward. The legacy fields below are marked deprecated and **will not be removed before May 28, 2026**. | Legacy field | Surface | Replacement | | ---------------- | ----------------- | ---------------------------------------- | | `action` | Order, Fill | `outcome_side` / `book_side` | | `side` | Order, Fill | `outcome_side` / `book_side` | | `is_yes` | Order (WS) | `outcome_side` / `book_side` | | `purchased_side` | Fill (WS) | `outcome_side` / `book_side` | | `taker_side` | Trade (REST + WS) | `taker_outcome_side` / `taker_book_side` | Existing integrations continue to receive the legacy fields until the removal date. New integrations should read only `outcome_side` and `book_side` (or the `taker_*` variants on public trades). ## Orderbook pricing convention The `orderbook_delta` and `orderbook_snapshot` WebSocket channels are an exception to the price-doesn't-change rule above. By default, no-side deltas and snapshot levels are reported in **no-leg pricing**: a no-side delta at `price_dollars=0.30` corresponds to a market offer of "no at 30c", which would match against "yes at 70c". The yes-side and no-side therefore use different price scales by default — toggling sides flips the price. Subscriptions can opt into a single-scale view by passing `use_yes_price: true` in the subscribe command params. When set: * Yes-side deltas and snapshot levels are unchanged. * No-side deltas and snapshot levels are reported in **yes-leg pricing** instead of no-leg, so `price_dollars` carries the same scale on both sides. A no-side delta at the price level that would otherwise be reported as `0.30` (no-leg) is instead reported as `0.70` (yes-leg). This brings the orderbook channels in line with the price-doesn't-change semantics on Order/Fill/Trade. The flag defaults to false to preserve the existing long-standing behavior; new integrations are encouraged to set it. **Migration plan.** The default for `use_yes_price` will be flipped to `true` in a future release, so subscriptions that don't explicitly set it will start receiving the unified yes-leg pricing automatically. The flag itself will then be removed in a subsequent release and the unified-pricing behavior will be the only supported behavior — explicit `use_yes_price: false` requests will no longer toggle the legacy no-leg pricing once the flag is removed. We will announce concrete dates for both steps before they happen; integrations that depend on the legacy no-leg pricing should plan to migrate before the default flip. # Orderbook Responses Source: https://docs.kalshi.com/getting_started/orderbook_responses Understanding Kalshi orderbook structure and binary prediction market mechanics ## Getting Orderbook Data The [Get Market Orderbook](/api-reference/market/get-market-order-book) endpoint returns the current state of bids for a specific market. ### Request Format ``` GET /markets/{ticker}/orderbook ``` No authentication is required for this endpoint. ### Example Request ```python Python theme={null} import requests # Get orderbook for a specific market market_ticker = "KXHIGHNY-24JAN01-T60" url = f"https://external-api.kalshi.com/trade-api/v2/markets/{market_ticker}/orderbook" response = requests.get(url) orderbook_data = response.json() ``` ```javascript JavaScript theme={null} // Get orderbook for a specific market const marketTicker = "KXHIGHNY-24JAN01-T60"; const url = `https://external-api.kalshi.com/trade-api/v2/markets/${marketTicker}/orderbook`; fetch(url) .then(response => response.json()) .then(data => console.log(data)); ``` ```curl cURL theme={null} curl -X GET "https://external-api.kalshi.com/trade-api/v2/markets/KXHIGHNY-24JAN01-T60/orderbook" ``` ## Response Structure The orderbook response is wrapped in an `orderbook_fp` object containing two arrays of bids — `yes_dollars` for YES positions and `no_dollars` for NO positions. Each bid is a two-element string array: `[price_dollars, count_fp]`. * **`price_dollars`**: Price as a dollar string (e.g., `"0.4200"` = \$0.42) * **`count_fp`**: Number of contracts as a fixed-point string (e.g., `"13.00"` = 13 contracts) Both values are strings to support subpenny pricing and fractional contract sizes. See [Fixed-Point Migration](/getting_started/fixed_point_migration) for details. ### Example Response ```json theme={null} { "orderbook_fp": { "yes_dollars": [ ["0.0100", "200.00"], ["0.1500", "100.00"], ["0.2000", "50.00"], ["0.2500", "20.00"], ["0.3000", "11.00"], ["0.3100", "10.00"], ["0.3200", "10.00"], ["0.3300", "11.00"], ["0.3400", "9.00"], ["0.3500", "11.00"], ["0.4100", "10.00"], ["0.4200", "13.00"] ], "no_dollars": [ ["0.0100", "100.00"], ["0.1600", "3.00"], ["0.2500", "50.00"], ["0.2800", "19.00"], ["0.3600", "5.00"], ["0.3700", "50.00"], ["0.3800", "300.00"], ["0.4400", "29.00"], ["0.4500", "20.00"], ["0.5600", "17.00"] ] } } ``` ### Understanding the Arrays * **First element**: Price in dollars as a string (e.g., `"0.4200"`) * **Second element**: Number of contracts as a fixed-point string (e.g., `"13.00"`) * Arrays are sorted by price in **ascending order** * The **highest** bid (best bid) is the **last** element in each array ## Why Only Bids? **Important**: Kalshi's orderbook only returns bids, not asks. This is because in binary prediction markets, there's a reciprocal relationship between YES and NO positions. In binary prediction markets, every position has a complementary opposite: * A **YES BID** at price X is equivalent to a **NO ASK** at price (\$1.00 - X) * A **NO BID** at price Y is equivalent to a **YES ASK** at price (\$1.00 - Y) ### The Reciprocal Relationship Since binary markets must sum to \$1.00, these relationships always hold: | Action | Equivalent To | Why | | ----------------- | ----------------- | ------------------------------------------------------------------ | | YES BID at \$0.60 | NO ASK at \$0.40 | Willing to pay $0.60 for YES = Willing to receive $0.40 to take NO | | NO BID at \$0.30 | YES ASK at \$0.70 | Willing to pay $0.30 for NO = Willing to receive $0.70 to take YES | This reciprocal nature means that by showing only bids, the orderbook provides complete market information while avoiding redundancy. ## Calculating Spreads To find the bid-ask spread for a market: 1. **YES spread**: * Best YES bid: Highest price in the `yes_dollars` array * Best YES ask: \$1.00 - (Highest price in the `no_dollars` array) * Spread = Best YES ask - Best YES bid 2. **NO spread**: * Best NO bid: Highest price in the `no_dollars` array * Best NO ask: \$1.00 - (Highest price in the `yes_dollars` array) * Spread = Best NO ask - Best NO bid ### Example Calculation ```python theme={null} from decimal import Decimal # Using the example orderbook above best_yes_bid = Decimal("0.4200") # Highest YES bid (last in array) best_yes_ask = Decimal("1.00") - Decimal("0.5600") # $1.00 - highest NO bid = $0.44 spread = best_yes_ask - best_yes_bid # $0.44 - $0.42 = $0.02 # The spread is $0.02 # You can buy YES at $0.44 (implied ask) and sell at $0.42 (bid) ``` ## Working with Orderbook Data ### Display Best Prices ```python Python theme={null} from decimal import Decimal def display_best_prices(orderbook_data): """Display the best bid prices and implied asks""" ob = orderbook_data['orderbook_fp'] # Best bids (if any exist) if ob.get('yes_dollars'): best_yes_bid = ob['yes_dollars'][-1][0] # Last element is highest print(f"Best YES Bid: ${best_yes_bid}") if ob.get('no_dollars'): best_no_bid = ob['no_dollars'][-1][0] # Last element is highest best_yes_ask = Decimal("1.00") - Decimal(best_no_bid) print(f"Best YES Ask: ${best_yes_ask} (implied from NO bid)") print() if ob.get('no_dollars'): best_no_bid = ob['no_dollars'][-1][0] # Last element is highest print(f"Best NO Bid: ${best_no_bid}") if ob.get('yes_dollars'): best_yes_bid = ob['yes_dollars'][-1][0] # Last element is highest best_no_ask = Decimal("1.00") - Decimal(best_yes_bid) print(f"Best NO Ask: ${best_no_ask} (implied from YES bid)") ``` ```javascript JavaScript theme={null} function displayBestPrices(orderbookData) { const ob = orderbookData.orderbook_fp; // Best bids (if any exist) if (ob.yes_dollars && ob.yes_dollars.length > 0) { const bestYesBid = ob.yes_dollars[ob.yes_dollars.length - 1][0]; console.log(`Best YES Bid: $${bestYesBid}`); } if (ob.no_dollars && ob.no_dollars.length > 0) { const bestNoBid = ob.no_dollars[ob.no_dollars.length - 1][0]; const bestYesAsk = (1 - parseFloat(bestNoBid)).toFixed(4); console.log(`Best YES Ask: $${bestYesAsk} (implied from NO bid)`); } console.log(); if (ob.no_dollars && ob.no_dollars.length > 0) { const bestNoBid = ob.no_dollars[ob.no_dollars.length - 1][0]; console.log(`Best NO Bid: $${bestNoBid}`); } if (ob.yes_dollars && ob.yes_dollars.length > 0) { const bestYesBid = ob.yes_dollars[ob.yes_dollars.length - 1][0]; const bestNoAsk = (1 - parseFloat(bestYesBid)).toFixed(4); console.log(`Best NO Ask: $${bestNoAsk} (implied from YES bid)`); } } ``` ### Calculate Market Depth ```python theme={null} from decimal import Decimal def calculate_depth(orderbook_data, depth_dollars="0.05"): """Calculate total volume within X dollars of best bid""" ob = orderbook_data['orderbook_fp'] depth = Decimal(depth_dollars) yes_depth = Decimal("0") no_depth = Decimal("0") # YES side depth (iterate backwards from best bid) if ob.get('yes_dollars'): best_yes = Decimal(ob['yes_dollars'][-1][0]) for price_str, count_str in reversed(ob['yes_dollars']): if best_yes - Decimal(price_str) <= depth: yes_depth += Decimal(count_str) else: break # NO side depth (iterate backwards from best bid) if ob.get('no_dollars'): best_no = Decimal(ob['no_dollars'][-1][0]) for price_str, count_str in reversed(ob['no_dollars']): if best_no - Decimal(price_str) <= depth: no_depth += Decimal(count_str) else: break return {"yes_depth": str(yes_depth), "no_depth": str(no_depth)} ``` ## Next Steps * Learn about [making authenticated requests](/getting_started/api_keys) to place orders * Explore [WebSocket connections](/websockets) for real-time orderbook updates * Read about [market mechanics](https://kalshi.com/learn) on the Kalshi website # Understanding Pagination Source: https://docs.kalshi.com/getting_started/pagination Learn how to navigate through large datasets using cursor-based pagination The Kalshi API uses cursor-based pagination to help you efficiently navigate through large datasets. This guide explains how pagination works and provides examples for handling paginated responses. ## How Pagination Works When making requests to list endpoints (like `/markets`, `/events`, or `/series`), the API returns results in pages to keep response sizes manageable. Each page contains: * **Data array**: The actual items for the current page (markets, events, etc.) * **Cursor field**: A token that points to the next page of results * **Limit**: The maximum number of items per page (default: 100) ## Using Cursors To paginate through results: 1. Make your initial request without a cursor 2. Check if the response includes a `cursor` field 3. If a cursor exists, make another request with `?cursor={cursor_value}` 4. Continue until the cursor is `null` (no more pages) ## Example: Paginating Through Markets ```python Python theme={null} import requests def get_all_markets(series_ticker): """Fetch all markets for a series, handling pagination""" all_markets = [] cursor = None base_url = "https://external-api.kalshi.com/trade-api/v2/markets" while True: # Build URL with cursor if we have one url = f"{base_url}?series_ticker={series_ticker}&limit=100" if cursor: url += f"&cursor={cursor}" response = requests.get(url) data = response.json() # Add markets from this page all_markets.extend(data['markets']) # Check if there are more pages cursor = data.get('cursor') if not cursor: break print(f"Fetched {len(data['markets'])} markets, total: {len(all_markets)}") return all_markets # Example usage markets = get_all_markets("KXHIGHNY") print(f"Total markets found: {len(markets)}") ``` ```javascript JavaScript theme={null} async function getAllMarkets(seriesTicker) { const allMarkets = []; let cursor = null; const baseUrl = 'https://external-api.kalshi.com/trade-api/v2/markets'; while (true) { // Build URL with cursor if we have one let url = `${baseUrl}?series_ticker=${seriesTicker}&limit=100`; if (cursor) { url += `&cursor=${cursor}`; } const response = await fetch(url); const data = await response.json(); // Add markets from this page allMarkets.push(...data.markets); // Check if there are more pages cursor = data.cursor; if (!cursor) { break; } console.log(`Fetched ${data.markets.length} markets, total: ${allMarkets.length}`); } return allMarkets; } // Example usage getAllMarkets('KXHIGHNY').then(markets => { console.log(`Total markets found: ${markets.length}`); }); ``` ## Pagination Parameters Most list endpoints support these pagination parameters: * **`cursor`**: Token from previous response to get the next page * **`limit`**: Number of items per page (typically 1-100, default: 100) ## Best Practices 1. **Handle rate limits**: When paginating through large datasets, be mindful of [rate limits](/getting_started/rate_limits) 2. **Set appropriate limits**: Use smaller page sizes if you only need a few items 3. **Cache results**: Store paginated data locally to avoid repeated API calls 4. **Check for changes**: Data can change between requests, so consider implementing refresh logic ## Endpoints Supporting Pagination The following endpoints support cursor-based pagination: * [Get Markets](/api-reference/market/get-markets) - `/markets` * [Get Events](/api-reference/market/get-events) - `/events` * [Get Series](/api-reference/market/get-series) - `/series` * [Get Trades](/api-reference/market/get-trades) - `/markets/trades` * [Get Portfolio History](/api-reference/portfolio/get-portfolio-history) - `/portfolio/history` * [Get Fills](/api-reference/portfolio/get-fills) - `/portfolio/fills` * [Get Orders](/api-reference/portfolio/get-orders) - `/portfolio/orders` ## Common Patterns ### Fetching Recent Items If you only need recent items, you can limit results without pagination: ```python theme={null} # Get just the 10 most recent markets url = "https://external-api.kalshi.com/trade-api/v2/markets?limit=10&status=open" ``` ### Filtering While Paginating You can combine filters with pagination: ```python theme={null} # Get all open markets for a series url = f"{base_url}?series_ticker={ticker}&status=open&limit=100&cursor={cursor}" ``` ### Detecting New Items To check for new items since your last fetch: 1. Store the first item's ID or timestamp from your previous fetch 2. Paginate through results until you find that item 3. Everything before it is new ## Next Steps Now that you understand pagination, you can efficiently work with large datasets in the Kalshi API. For more details on specific endpoints, check the [API Reference](/api-reference). # Quick Start: Authenticated Requests Source: https://docs.kalshi.com/getting_started/quick_start_authenticated_requests Three simple steps to make your first authenticated API request to Kalshi This guide shows you how to make authenticated requests to the Kalshi API in three simple steps. For the full production and demo endpoint list, see [API Environments and Endpoints](/getting_started/api_environments). ## Step 1: Get Your API Keys 1. Log in to your Kalshi account ([demo](https://demo.kalshi.co) or [production](https://kalshi.com)) 2. Navigate to **Account & security** → **API Keys** 3. Click **Create Key** 4. Save both: * **Private Key**: Downloaded as a `.key` file * **API Key ID**: Displayed on screen (looks like `a952bcbe-ec3b-4b5b-b8f9-11dae589608c`) Your private key cannot be retrieved after this page is closed. Store it securely! ## Step 2: Set Up Your Request Every authenticated request to Kalshi requires three headers: | Header | Description | Example | | ------------------------- | ----------------------------- | -------------------------------------- | | `KALSHI-ACCESS-KEY` | Your API Key ID | `a952bcbe-ec3b-4b5b-b8f9-11dae589608c` | | `KALSHI-ACCESS-TIMESTAMP` | Current time in milliseconds | `1703123456789` | | `KALSHI-ACCESS-SIGNATURE` | Request signature (see below) | `base64_encoded_signature` | ### How to Create the Signature The signature proves you own the private key. Here's how it works: 1. **Create a message string**: Concatenate `timestamp + HTTP_METHOD + path` * Example: `1703123456789GET/trade-api/v2/portfolio/balance` * **Important**: Sign the full URL path from the API root, without query parameters. For `https://external-api.demo.kalshi.co/trade-api/v2/portfolio/orders?limit=5`, sign `/trade-api/v2/portfolio/orders`. 2. **Sign with your private key**: Use RSA-PSS with SHA256 3. **Encode as base64**: Convert the signature to base64 string Here's the signing process in Python: ```python theme={null} import base64 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding def sign_request(private_key, timestamp, method, path): # Strip query parameters from path before signing path_without_query = path.split('?')[0] # Create the message to sign message = f"{timestamp}{method}{path_without_query}".encode('utf-8') # Sign with RSA-PSS signature = private_key.sign( message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.DIGEST_LENGTH ), hashes.SHA256() ) # Return base64 encoded return base64.b64encode(signature).decode('utf-8') ``` ## Step 3: Get Your Balance Now let's make your first authenticated request to get your account balance: ```python theme={null} import requests import datetime # Set up the request timestamp = str(int(datetime.datetime.now().timestamp() * 1000)) method = "GET" path = "/trade-api/v2/portfolio/balance" # Create signature (using function from Step 2) signature = sign_request(private_key, timestamp, method, path) # Make the request headers = { 'KALSHI-ACCESS-KEY': 'your-api-key-id', 'KALSHI-ACCESS-SIGNATURE': signature, 'KALSHI-ACCESS-TIMESTAMP': timestamp } response = requests.get('https://external-api.demo.kalshi.co' + path, headers=headers) balance = response.json() print(f"Your balance: ${balance['balance'] / 100:.2f}") ``` ## Complete Working Example Here's the minimal code to get your balance: ```python theme={null} import requests import datetime import base64 from urllib.parse import urlparse from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import padding # Configuration API_KEY_ID = 'your-api-key-id-here' PRIVATE_KEY_PATH = 'path/to/your/kalshi-key.key' BASE_URL = 'https://external-api.demo.kalshi.co/trade-api/v2' # or 'https://external-api.kalshi.com/trade-api/v2' for production def load_private_key(key_path): with open(key_path, "rb") as f: return serialization.load_pem_private_key(f.read(), password=None, backend=default_backend()) def create_signature(private_key, timestamp, method, path): """Create the request signature.""" # Strip query parameters before signing path_without_query = path.split('?')[0] message = f"{timestamp}{method}{path_without_query}".encode('utf-8') signature = private_key.sign( message, padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.DIGEST_LENGTH), hashes.SHA256() ) return base64.b64encode(signature).decode('utf-8') def get(private_key, api_key_id, path, base_url=BASE_URL): """Make an authenticated GET request to the Kalshi API.""" timestamp = str(int(datetime.datetime.now().timestamp() * 1000)) # Signing requires the full URL path from root (e.g. /trade-api/v2/portfolio/balance) sign_path = urlparse(base_url + path).path signature = create_signature(private_key, timestamp, "GET", sign_path) headers = { 'KALSHI-ACCESS-KEY': api_key_id, 'KALSHI-ACCESS-SIGNATURE': signature, 'KALSHI-ACCESS-TIMESTAMP': timestamp } return requests.get(base_url + path, headers=headers) # Load private key private_key = load_private_key(PRIVATE_KEY_PATH) # Get balance response = get(private_key, API_KEY_ID, "/portfolio/balance") print(f"Your balance: ${response.json()['balance'] / 100:.2f}") ``` ## Common Issues | Problem | Solution | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 Unauthorized | Check your API Key ID and private key file path | | Signature error | Ensure timestamp is in milliseconds (not seconds) | | Path not found | If your `BASE_URL` already ends with `/trade-api/v2`, pass only the endpoint path to the helper (e.g. `/portfolio/balance`, not `/trade-api/v2/portfolio/balance`) so the request URL is not double-prefixed | | Signature error with query params | Sign the request path without query parameters. The examples do this with `path.split('?')[0]` after building the full URL path | ## Next Steps Now you can make authenticated requests! Try these endpoints (relative to `BASE_URL`): * `/portfolio/positions` - Get your positions * `/portfolio/orders` - View your orders * `/markets` - Browse available markets For more details, see the [Complete Order Lifecycle](/getting_started/quick_start_create_order) guide or explore the [API Reference](/api-reference). # Quick Start: Create your first order Source: https://docs.kalshi.com/getting_started/quick_start_create_order Learn how to find markets, place orders, check status, and cancel orders on Kalshi This guide will walk you through the complete lifecycle of placing and managing orders on Kalshi. ## Prerequisites Before you begin, you'll need: * A Kalshi account with API access configured * Python with the `requests` and `cryptography` libraries installed * Your authentication functions set up (see our [authentication guide](quick_start_authenticated_requests)) This guide assumes you have the authentication code from our authentication guide, including the `get()` function for making authenticated requests. ## Step 1: Find an Open Market First, let's find an open market to trade on. ```python theme={null} # Get the first open market (no auth required for public market data) response = requests.get('https://external-api.demo.kalshi.co/trade-api/v2/markets?limit=1&status=open') market = response.json()['markets'][0] print(f"Selected market: {market['ticker']}") print(f"Title: {market['title']}") ``` ## Step 2: Place a Buy Order Now let's place an order to buy 1 YES contract for 1 cent (limit order). We'll use a `client_order_id` to deduplicate orders - this allows you to identify duplicate orders before receiving the server-generated `order_id` in the response. ```python theme={null} import uuid from urllib.parse import urlparse def post(private_key, api_key_id, path, data, base_url=BASE_URL): """Make an authenticated POST request to the Kalshi API.""" timestamp = str(int(datetime.datetime.now().timestamp() * 1000)) # Signing requires the full URL path from root (e.g. /trade-api/v2/portfolio/orders) sign_path = urlparse(base_url + path).path signature = create_signature(private_key, timestamp, "POST", sign_path) headers = { 'KALSHI-ACCESS-KEY': api_key_id, 'KALSHI-ACCESS-SIGNATURE': signature, 'KALSHI-ACCESS-TIMESTAMP': timestamp, 'Content-Type': 'application/json' } return requests.post(base_url + path, headers=headers, json=data) # Place a buy order for 1 YES contract at 1 cent order_data = { "ticker": market['ticker'], "action": "buy", "side": "yes", "count": 1, "type": "limit", "yes_price": 1, "client_order_id": str(uuid.uuid4()) # Unique ID for deduplication } response = post(private_key, API_KEY_ID, '/portfolio/orders', order_data) if response.status_code == 201: order = response.json()['order'] print(f"Order placed successfully!") print(f"Order ID: {order['order_id']}") print(f"Client Order ID: {order_data['client_order_id']}") print(f"Status: {order['status']}") else: print(f"Error: {response.status_code} - {response.text}") ``` ## Complete Example Script Here's a complete script that creates your first order: ```python theme={null} import requests import uuid from urllib.parse import urlparse # Assumes you have the authentication code from the prerequisites # Add POST function to your existing auth code def post(private_key, api_key_id, path, data, base_url=BASE_URL): """Make an authenticated POST request to the Kalshi API.""" timestamp = str(int(datetime.datetime.now().timestamp() * 1000)) # Signing requires the full URL path from root (e.g. /trade-api/v2/portfolio/orders) sign_path = urlparse(base_url + path).path signature = create_signature(private_key, timestamp, "POST", sign_path) headers = { 'KALSHI-ACCESS-KEY': api_key_id, 'KALSHI-ACCESS-SIGNATURE': signature, 'KALSHI-ACCESS-TIMESTAMP': timestamp, 'Content-Type': 'application/json' } return requests.post(base_url + path, headers=headers, json=data) # Step 1: Find an open market print("Finding an open market...") response = requests.get('https://external-api.demo.kalshi.co/trade-api/v2/markets?limit=1&status=open') market = response.json()['markets'][0] print(f"Selected: {market['ticker']} - {market['title']}") # Step 2: Place a buy order print("\nPlacing order...") client_order_id = str(uuid.uuid4()) order_data = { "ticker": market['ticker'], "action": "buy", "side": "yes", "count": 1, "type": "limit", "yes_price": 1, "client_order_id": client_order_id } response = post(private_key, API_KEY_ID, '/portfolio/orders', order_data) if response.status_code == 201: order = response.json()['order'] print(f"Order placed successfully!") print(f"Order ID: {order['order_id']}") print(f"Client Order ID: {client_order_id}") print(f"Status: {order['status']}") else: print(f"Error: {response.status_code} - {response.text}") ``` ## Important Notes ### Client Order ID The `client_order_id` field is crucial for order deduplication: * Generate a unique ID (like UUID4) for each order before submission * If network issues occur, you can resubmit with the same `client_order_id` * The API will reject duplicate submissions, preventing accidental double orders * Store this ID locally to track orders before receiving the server's `order_id` ### Error Handling Common errors and how to handle them: * `401 Unauthorized`: Check your API keys and signature generation * `400 Bad Request`: Verify your order parameters (price must be 1-99 cents) * `409 Conflict`: Order with this `client_order_id` already exists * `429 Too Many Requests`: You've hit the rate limit - slow down your requests ## Next Steps Now that you've created your first order, you can: * Check order status using the `/portfolio/orders/{order_id}` endpoint * List all your orders with `/portfolio/orders` * Amend your order price or quantity using PUT `/portfolio/orders/{order_id}` * Cancel orders using DELETE `/portfolio/orders/{order_id}` * Implement WebSocket connections for real-time updates * Build automated trading strategies For more information, check out: * [API Reference Documentation](https://docs.kalshi.com/api-reference) * [Kalshi Discord Community](https://discord.gg/kalshi) # Quick Start: Market Data Source: https://docs.kalshi.com/getting_started/quick_start_market_data Learn how to access real-time market data without authentication This guide will walk you through accessing Kalshi's public market data endpoints without authentication. You'll learn how to retrieve series information, events, markets, and orderbook data for the popular "Who will have a higher net approval" market. ## Making Unauthenticated Requests Kalshi provides several public endpoints that don't require API keys. These endpoints allow you to access market data directly from our production servers at `https://external-api.kalshi.com/trade-api/v2`. **Note about the API URL**: Despite the "elections" subdomain, the production Trade API provides access to ALL Kalshi markets - not just election-related ones. This includes markets on economics, climate, technology, entertainment, and more. No authentication headers are required for the endpoints in this guide. You can start making requests immediately! ## Step 1: Get Series Information Let's start by fetching information about the KXHIGHNY series ([Highest temperature in NYC today?](https://kalshi.com/markets/kxhighny/highest-temperature-in-nyc)). This series tracks the highest temperature recorded in Central Park, New York on a given day. We'll use the [Get Series](/api-reference/market/get-series) endpoint. ```python Python theme={null} import requests # Get series information for KXHIGHNY url = "https://external-api.kalshi.com/trade-api/v2/series/KXHIGHNY" response = requests.get(url) series_data = response.json() print(f"Series Title: {series_data['series']['title']}") print(f"Frequency: {series_data['series']['frequency']}") print(f"Category: {series_data['series']['category']}") ``` ```javascript JavaScript theme={null} // Get series information for KXHIGHNY fetch('https://external-api.kalshi.com/trade-api/v2/series/KXHIGHNY') .then(response => response.json()) .then(data => { console.log(`Series Title: ${data.series.title}`); console.log(`Frequency: ${data.series.frequency}`); console.log(`Category: ${data.series.category}`); }); ``` ```curl cURL theme={null} curl -X GET "https://external-api.kalshi.com/trade-api/v2/series/KXHIGHNY" ``` ## Step 2: Get Today's Events and Markets Now that we have the series information, let's get the markets for this series. We'll use the [Get Markets](/api-reference/market/get-markets) endpoint with the series ticker filter to find all active markets. If there are no open markets today, remove `status=open` or use `status=all` to see the full series history. ```python Python theme={null} # Get all open markets for the KXHIGHNY series markets_url = f"https://external-api.kalshi.com/trade-api/v2/markets?series_ticker=KXHIGHNY&status=open" markets_response = requests.get(markets_url) markets_data = markets_response.json() print(f"\nActive markets in KXHIGHNY series:") for market in markets_data['markets']: print(f"- {market['ticker']}: {market['title']}") print(f" Event: {market['event_ticker']}") print(f" Yes Price: ${market['yes_bid_dollars']} | Volume: {market['volume_fp']}") print() # Get details for a specific event if you have its ticker if markets_data['markets']: # Let's get details for the first market's event event_ticker = markets_data['markets'][0]['event_ticker'] event_url = f"https://external-api.kalshi.com/trade-api/v2/events/{event_ticker}" event_response = requests.get(event_url) event_data = event_response.json() print(f"Event Details:") print(f"Title: {event_data['event']['title']}") print(f"Category: {event_data['event']['category']}") ``` ```javascript JavaScript theme={null} // Get markets for the KXHIGHNY series async function getSeriesMarkets() { // Get all open markets for this series const marketsResponse = await fetch('https://external-api.kalshi.com/trade-api/v2/markets?series_ticker=KXHIGHNY&status=open'); const marketsData = await marketsResponse.json(); console.log('\nActive markets in KXHIGHNY series:'); marketsData.markets.forEach(market => { console.log(`- ${market.ticker}: ${market.title}`); console.log(` Event: ${market.event_ticker}`); console.log(` Yes Price: $${market.yes_bid_dollars} | Volume: ${market.volume_fp}`); console.log(); }); // Get details for a specific event if markets exist if (marketsData.markets.length > 0) { const eventTicker = marketsData.markets[0].event_ticker; const eventResponse = await fetch(`https://external-api.kalshi.com/trade-api/v2/events/${eventTicker}`); const eventData = await eventResponse.json(); console.log('Event Details:'); console.log(`Title: ${eventData.event.title}`); console.log(`Category: ${eventData.event.category}`); } } getSeriesMarkets(); ``` You can view these markets in the Kalshi UI at: [https://kalshi.com/markets/kxhighny](https://kalshi.com/markets/kxhighny) ## Step 3: Get Orderbook Data Now let's fetch the orderbook for a specific market to see the current bids and asks using the [Get Market Orderbook](/api-reference/market/get-market-order-book) endpoint. This snippet assumes you still have the `markets_data` from the previous step. If `markets_data['markets']` is empty, pick a market from a different series or remove the `status=open` filter. ```python Python theme={null} # Get orderbook for a specific market # Replace with an actual market ticker from the markets list if not markets_data['markets']: raise ValueError("No open markets found. Try removing status=open or choose another series.") market_ticker = markets_data['markets'][0]['ticker'] orderbook_url = f"https://external-api.kalshi.com/trade-api/v2/markets/{market_ticker}/orderbook" orderbook_response = requests.get(orderbook_url) orderbook_data = orderbook_response.json() print(f"\nOrderbook for {market_ticker}:") print("YES BIDS:") for price_dollars, count_fp in orderbook_data['orderbook_fp']['yes_dollars'][:5]: # Show top 5 print(f" Price: ${price_dollars}, Quantity: {count_fp}") print("\nNO BIDS:") for price_dollars, count_fp in orderbook_data['orderbook_fp']['no_dollars'][:5]: # Show top 5 print(f" Price: ${price_dollars}, Quantity: {count_fp}") ``` ```javascript JavaScript theme={null} // Get orderbook data async function getOrderbook(marketTicker) { const response = await fetch(`https://external-api.kalshi.com/trade-api/v2/markets/${marketTicker}/orderbook`); const data = await response.json(); console.log(`\nOrderbook for ${marketTicker}:`); console.log('YES BIDS:'); data.orderbook_fp.yes_dollars.slice(0, 5).forEach(([priceDollars, countFp]) => { console.log(` Price: $${priceDollars}, Quantity: ${countFp}`); }); console.log('\nNO BIDS:'); data.orderbook_fp.no_dollars.slice(0, 5).forEach(([priceDollars, countFp]) => { console.log(` Price: $${priceDollars}, Quantity: ${countFp}`); }); } ``` ## Working with Large Datasets The Kalshi API uses cursor-based pagination to handle large datasets efficiently. To learn more about navigating through paginated responses, see our [Understanding Pagination](/getting_started/pagination) guide. ## Understanding Orderbook Responses Kalshi's orderbook structure is unique due to the nature of binary prediction markets. The API only returns bids (not asks) because of the reciprocal relationship between YES and NO positions. To learn more about orderbook responses and why they work this way, see our [Orderbook Responses](/getting_started/orderbook_responses) guide. ## Next Steps Now that you understand how to access market data without authentication, you can: 1. Explore other public series and events 2. Build real-time market monitoring tools 3. Create market analysis dashboards 4. Set up a WebSocket connection for live updates (requires authentication) For authenticated endpoints that allow trading and portfolio management, check out our [API Keys guide](/getting_started/api_keys). # Quick Start: WebSockets Source: https://docs.kalshi.com/getting_started/quick_start_websockets Learn how to establish and maintain a WebSocket connection to stream real-time market data ## Overview Kalshi's WebSocket API provides real-time updates for: * Order book changes * Trade executions * Market status updates * Fill notifications ## Connection URL Connect to the WebSocket endpoint at: ``` wss://external-api-ws.kalshi.com/trade-api/ws/v2 ``` For the demo environment, use: ``` wss://external-api-ws.demo.kalshi.co/trade-api/ws/v2 ``` The existing shared WebSocket hosts, `wss://api.elections.kalshi.com/trade-api/ws/v2` for production and `wss://demo-api.kalshi.co/trade-api/ws/v2` for demo, remain supported. For the full endpoint list, see [API Environments and Endpoints](/getting_started/api_environments). ## Authentication WebSocket connections require authentication during the connection handshake. Once connected, channels fall into two groups: * **Private channels (user-specific data):** `orderbook_delta`, `fill`, `market_positions`, `communications`, `order_group_updates` * **Public market-data channels (no additional channel-level auth):** `ticker`, `trade`, `market_lifecycle_v2`, `multivariate_market_lifecycle`, `multivariate` In other words, even channels that carry public market data still use the authenticated WebSocket session, but they do not impose additional per-channel authorization checks. For detailed information about API key generation and request signing, see our [API Keys documentation](/getting_started/api_keys). ### Required Headers When establishing the WebSocket connection, include these headers: ```http theme={null} KALSHI-ACCESS-KEY: your_api_key_id KALSHI-ACCESS-SIGNATURE: request_signature KALSHI-ACCESS-TIMESTAMP: unix_timestamp_in_milliseconds ``` ### Signing the WebSocket Request The signature for WebSocket connections follows the same pattern as REST API requests: 1. **Create the message to sign:** ``` timestamp + "GET" + "/trade-api/ws/v2" ``` 2. **Generate the signature** using your private key (see [API Keys documentation](/getting_started/api_keys)) 3. **Include the headers** when opening the WebSocket connection ## Establishing a Connection To connect to the WebSocket API, you need to: 1. Generate authentication headers (same as REST API) 2. Create a WebSocket connection with those headers 3. Handle the connection lifecycle Here's how to establish an authenticated connection: ```python theme={null} import websockets import asyncio # WebSocket URL ws_url = "wss://external-api-ws.demo.kalshi.co/trade-api/ws/v2" # Demo environment # Generate authentication headers (see API Keys documentation) auth_headers = { "KALSHI-ACCESS-KEY": "your_api_key_id", "KALSHI-ACCESS-SIGNATURE": "generated_signature", "KALSHI-ACCESS-TIMESTAMP": "timestamp_in_milliseconds" } # Connect with authentication async def connect(): async with websockets.connect(ws_url, additional_headers=auth_headers) as websocket: print("Connected to Kalshi WebSocket") # Connection is now established # You can start sending and receiving messages # Listen for messages async for message in websocket: print(f"Received: {message}") # Run the connection asyncio.run(connect()) ``` ## Subscribing to Data Once connected, subscribe to channels by sending a subscription command: ```python theme={null} import json async def subscribe_to_ticker(websocket): """Subscribe to ticker updates""" subscription = { "id": 1, "cmd": "subscribe", "params": { "channels": ["ticker"] } } await websocket.send(json.dumps(subscription)) async def subscribe_to_orderbook(websocket, market_tickers): """Subscribe to orderbook updates for specific markets""" subscription = { "id": 2, "cmd": "subscribe", "params": { "channels": ["orderbook_delta"], "market_tickers": market_tickers } } await websocket.send(json.dumps(subscription)) ``` ## Processing Messages Handle incoming messages based on their type: ```python theme={null} async def process_message(message): """Process incoming WebSocket messages""" data = json.loads(message) msg_type = data.get("type") if msg_type == "ticker": # Handle ticker update market = data["msg"]["market_ticker"] bid = data["msg"]["yes_bid_dollars"] ask = data["msg"]["yes_ask_dollars"] print(f"{market}: Yes Bid ${bid}, Yes Ask ${ask}") elif msg_type == "orderbook_snapshot": # Handle full orderbook state print(f"Orderbook snapshot for {data['msg']['market_ticker']}") elif msg_type == "orderbook_delta": # Handle orderbook changes print(f"Orderbook update for {data['msg']['market_ticker']}") # Note: client_order_id field is optional - present only when you caused this change if 'client_order_id' in data['msg']: print(f" Your order {data['msg']['client_order_id']} caused this change") elif msg_type == "error": error_code = data.get("msg", {}).get("code") error_msg = data.get("msg", {}).get("msg") print(f"Error {error_code}: {error_msg}") ``` ## Connection Keep-Alive The Python `websockets` library automatically handles WebSocket ping/pong frames to keep connections alive. No manual heartbeat handling is required. Learn more about [automatic keepalive in the websockets documentation](https://websockets.readthedocs.io/en/stable/topics/design.html#keepalive). Other WebSocket libraries may require manual ping/pong implementation. ## Subscribing to Channels Once connected, subscribe to specific data channels: ### Subscribe to Ticker Updates To receive real-time ticker updates for all markets: ```python theme={null} async def subscribe_to_tickers(self): """Subscribe to ticker updates for all markets""" subscription_message = { "id": self.message_id, "cmd": "subscribe", "params": { "channels": ["ticker"] } } await self.ws.send(json.dumps(subscription_message)) self.message_id += 1 ``` ### Subscribe to Specific Markets To subscribe to orderbook or trade updates for specific markets: ```python theme={null} async def subscribe_to_markets(self, channels, market_tickers): """Subscribe to specific channels and markets""" subscription_message = { "id": self.message_id, "cmd": "subscribe", "params": { "channels": channels, "market_tickers": market_tickers } } await self.ws.send(json.dumps(subscription_message)) self.message_id += 1 # Example usage: # Subscribe to orderbook updates await subscribe_to_markets(["orderbook_delta"], ["KXFUT24-LSV", "KXHARRIS24-LSV"]) # Subscribe to trade feed await subscribe_to_markets(["trade"], ["KXFUT24-LSV"]) ``` ## Connection Lifecycle 1. **Initial Connection**: Establish WebSocket with authentication headers 2. **Subscribe**: Send subscription commands for desired channels 3. **Receive Updates**: Process incoming messages based on their type 4. **Handle Disconnects**: Implement reconnection logic with exponential backoff ## Error Handling The server sends error messages in this format: ```json theme={null} { "id": 123, "type": "error", "msg": { "code": 2, "msg": "Params required" } } ``` ### WebSocket Error Codes | Code | Error | Description | User error? | | ---- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | 1 | Unable to process message | The incoming message was not valid JSON, or a JSON field had a type incompatible with the websocket command schema. | Y | | 2 | Params required | The command requires `params` or required subscription parameters are missing. | Y | | 3 | Channels required | The `subscribe` command must include at least one channel. | Y | | 4 | Subscription IDs required | The `unsubscribe` command must include at least one subscription ID in `sids`. | Y | | 5 | Unknown command | The `cmd` value is not supported. | Y | | 6 | Already subscribed | A subscription to the same channel is already active in this session. | Y | | 7 | Unknown subscription ID | The command references a subscription ID that is not active in the session. | Y | | 8 | Unknown channel name | The requested channel is not supported by this endpoint. | Y | | 9 | Authentication required | The requested channel or action requires authentication or channel access that was not granted. | Y | | 10 | Channel error | An internal channel error occurred while starting or running the subscription. If it persists, contact [support@kalshi.com](mailto:support@kalshi.com). | N | | 11 | Invalid parameter | A parameter has an invalid format, such as a malformed market ID. | Y | | 12 | Exactly one subscription ID is required | The `update_subscription` command must target exactly one subscription. | Y | | 13 | Unsupported action | The subscription does not support the requested `action`. | Y | | 14 | Market Ticker required | The command requires a market filter such as `market_ticker` or `market_tickers`. | Y | | 15 | Action required | The `update_subscription` command must include `params.action`. | Y | | 16 | Market not found | The specified `market_ticker` or `market_id` does not match any known market. | Y | | 17 | Internal error | An unexpected server-side error occurred. If it persists, contact [support@kalshi.com](mailto:support@kalshi.com). | N | | 18 | Command timeout | The server timed out while routing a command to an existing subscription. | N | | 19 | shard\_factor must be > 0 | The supplied `communications` `shard_factor` value is invalid. | Y | | 20 | shard\_factor is required when shard\_key is set | `communications` set `shard_key` without a valid shard factor. | Y | | 21 | shard\_key must be >= 0 and \< shard\_factor | The `communications` shard key is outside the valid range. | Y | | 22 | shard\_factor must be \<= 100 | The `communications` shard factor exceeds the maximum. | Y | | 25 | Subscription buffer overflow | The subscription's event buffer overflowed during a message burst. Subscribe to a smaller subset of data, or ensure that your connection read throughput is optimized. | Y | ## Best Practices * Implement automatic reconnection with exponential backoff * Handle network interruptions gracefully * Use the websockets library's built-in keepalive * Process messages asynchronously to avoid blocking * Implement proper error handling for malformed messages * Cache initial orderbook state before applying updates * Never expose your private key in client-side code * Rotate API keys regularly * Use secure key storage practices * Subscribe only to markets you need * Implement message buffering for high-frequency updates * Consider using connection pooling for multiple subscriptions ## Complete Example Here's a complete, runnable example that connects to the WebSocket API and subscribes to orderbook updates: ```python theme={null} import asyncio import base64 import json import time import websockets from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import padding # Configuration KEY_ID = "your_api_key_id" PRIVATE_KEY_PATH = "path/to/private_key.pem" MARKET_TICKER = "KXHARRIS24-LSV" # Replace with any open market WS_URL = "wss://external-api-ws.demo.kalshi.co/trade-api/ws/v2" def sign_pss_text(private_key, text: str) -> str: """Sign message using RSA-PSS""" message = text.encode('utf-8') signature = private_key.sign( message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.DIGEST_LENGTH ), hashes.SHA256() ) return base64.b64encode(signature).decode('utf-8') def create_headers(private_key, method: str, path: str) -> dict: """Create authentication headers""" timestamp = str(int(time.time() * 1000)) msg_string = timestamp + method + path.split('?')[0] signature = sign_pss_text(private_key, msg_string) return { "Content-Type": "application/json", "KALSHI-ACCESS-KEY": KEY_ID, "KALSHI-ACCESS-SIGNATURE": signature, "KALSHI-ACCESS-TIMESTAMP": timestamp, } async def orderbook_websocket(): """Connect to WebSocket and subscribe to orderbook""" # Load private key with open(PRIVATE_KEY_PATH, 'rb') as f: private_key = serialization.load_pem_private_key( f.read(), password=None ) # Create WebSocket headers ws_headers = create_headers(private_key, "GET", "/trade-api/ws/v2") async with websockets.connect(WS_URL, additional_headers=ws_headers) as websocket: print(f"Connected! Subscribing to orderbook for {MARKET_TICKER}") # Subscribe to orderbook subscribe_msg = { "id": 1, "cmd": "subscribe", "params": { "channels": ["orderbook_delta"], "market_ticker": MARKET_TICKER } } await websocket.send(json.dumps(subscribe_msg)) # Process messages async for message in websocket: data = json.loads(message) msg_type = data.get("type") if msg_type == "subscribed": print(f"Subscribed: {data}") elif msg_type == "orderbook_snapshot": print(f"Orderbook snapshot: {data}") elif msg_type == "orderbook_delta": # The client_order_id field is optional - only present when you caused the change if 'client_order_id' in data.get('msg', {}): print(f"Orderbook update (your order {data['msg']['client_order_id']}): {data}") else: print(f"Orderbook update: {data}") elif msg_type == "error": print(f"Error: {data}") # Run the example if __name__ == "__main__": asyncio.run(orderbook_websocket()) ``` This example: * Establishes an authenticated WebSocket connection * Subscribes to orderbook updates for the specified market * Processes both the initial snapshot and incremental updates * Displays orderbook changes in real-time To run this example: 1. Replace `KEY_ID` with your API key ID 2. Replace `PRIVATE_KEY_PATH` with the path to your private key file 3. Replace `MARKET_TICKER` with any open market ticker 4. Run with Python 3.7+ ## Next Steps * Review the [WebSocket API Reference](/websockets) for detailed message specifications * Explore [Market Data Quick Start](/getting_started/quick_start_market_data) for REST API integration * Check out our [Demo Environment](/getting_started/demo_env) for testing # Rate Limits and Tiers Source: https://docs.kalshi.com/getting_started/rate_limits Understanding API rate limits, token costs, and access tiers ## Token-based limits Every authenticated request costs **tokens**. Your tier defines how many tokens you can spend per second. Most requests cost the default of **10 tokens**; each operation's API reference page lists its cost where it differs (order cancellations, single-order reads, quote create/cancel, and multivariate-collection lookup are currently cheaper than the default). Your effective rate for any given endpoint is `budget ÷ cost`. ## Reads and writes are billed separately You have two independent token budgets: | Bucket | What it covers | | --------- | ----------------------------------------------------------------------- | | **Read** | `GET` endpoints and anything not explicitly routed elsewhere. | | **Write** | Order placement, amends, cancels, order groups, and the RFQ quote flow. | ## Batch endpoints don't save tokens A batch request costs the same as making each call individually — every item in the batch is billed separately: * [Batch Create Orders](/api-reference/orders/batch-create-orders): submitting 25 orders costs `25 × 10 = 250` tokens. * [Batch Cancel Orders](/api-reference/orders/batch-cancel-orders): cancelling 25 orders costs `25 × 2 = 50` tokens. ## Tiers and budgets Per-second token budgets in each bucket:
Tier Read budget Write budget
Basic200100
Advanced300300
Premier1,0001,000
Paragon2,0002,000
Prime4,0004,000
## Tier qualification * **Basic**: complete account signup. * **Advanced**: complete the [Advanced API application](https://kalshi.typeform.com/advanced-api). * **Premier, Paragon, Prime**: qualification criteria will be published shortly. Kalshi may, at its discretion, adjust your tier at any time — including downgrading you from higher tiers following prolonged inactivity. Members may request an upgrade by contacting support with a description of their use case. ## When you hit the limit A rate-limited request returns `429 Too Many Requests` with the body: ```json theme={null} {"error": "too many requests"} ``` 429 responses don't currently include `Retry-After` or `X-RateLimit-*` headers. Apply exponential backoff on 429 until your bucket refills. ## Bursting above your per-second budget Your Write bucket holds **two seconds** of your per-second budget — so idle or below-steady traffic builds up headroom you can spend in a single burst. Useful for event-driven clients reacting quickly to market moves or price prints. Each request drains the bucket by its token cost; the bucket refills continuously at your per-second budget up to its capacity. Over-drawing returns `429 Too Many Requests`. There's no enforced cooldown — your next request is allowed as soon as the bucket has enough tokens to cover it. Basic tier is the exception — its Write bucket holds one second of budget, with no accumulated headroom. # Request for Quote (RFQ) Source: https://docs.kalshi.com/getting_started/rfqs How the Kalshi RFQ system works Kalshi implements an RFQ (Request for Quote) system for pre-execution communication between members. RFQs allow a requester to solicit quotes from market makers on a specific market and size. Execution follows a two-step lock: accept, then confirm. RFQs are available on any market, including combo (multivariate event) markets. Combo markets are classified as High Volatility Markets (HVM), which have shorter timing windows — see [Timing](#timing). ## Interfaces RFQs are accessible over [REST](/api-reference/communications), [FIX](/fix/rfq-messages), and [WebSocket](/websockets). Quote notifications arrive on the `communications` WebSocket channel, not the orderbook channel. ## Flow 1. **Requester** creates an RFQ specifying a market ticker, size, and whether to rest any remainder. 2. The RFQ is broadcast to all makers. 3. **Makers** respond with quotes containing a `yes_bid` and `no_bid`. Quotes are for the full RFQ size. Each quote is private between the requester and the individual maker — makers cannot see each other's quotes. 4. **Requester** accepts one side of the best-priced quote. 5. **Maker** confirms within the confirmation window. Once confirmed, neither party can withdraw. 6. After the execution timeout, orders are placed on the public book. ## Sizing When creating an RFQ, the requester specifies size in exactly one of: * `contracts_fp` — number of contracts (whole only). * `target_cost_dollars` — dollar amount to spend. The exchange derives a contract count from the quote price, returned as `yes_contracts_fp` / `no_contracts_fp` on the quote. ## Quotes Each quote has two prices: `yes_bid` (price per YES contract) and `no_bid` (price per NO contract). These are typically different. Either can be `"0"` to decline that side, but not both. If `yes_bid + no_bid > $1` the quote is rejected. Quoters do not specify a size — each quote is implicitly for the full RFQ amount (`contracts_fp`, or whatever count `target_cost_dollars` resolves to at the quoted prices). Prices must land on the market's price grid. Check `price_ranges` on `GET /markets/{ticker}` for the valid step size. A new quote on the same RFQ replaces the maker's previous quote. ## Timing The exchange designates certain markets as High Volatility Markets (HVM). All combo markets are HVMs. HVMs use shorter confirmation and execution windows. | | Standard | HVM | | ----------------------- | -------- | --- | | **Confirmation window** | 30 s | 3 s | | **Execution timer** | 15 s | 1 s | After acceptance, the maker has the confirmation window to confirm. Upon confirmation, the platform begins the execution timer. At the end of the timer, orders are entered into the book. Fills appear in `GET /portfolio/fills` — match on `creator_order_id` (maker) or `rfq_creator_order_id` (requester). ## WebSocket Subscribe to the `communications` channel (requires auth). `rfq_created` and `rfq_deleted` go to all subscribers. `quote_created`, `quote_accepted`, and `quote_executed` go only to the involved requester and maker. ## Combos (MVE) Combo RFQs include `mve_collection_ticker` and `mve_selected_legs`. Use [Multivariate Event Collections](/api-reference/multivariate/get-multivariate-event-collections) to discover eligible combinations. ## Common errors | Error | What's going on | | ---------------------- | ------------------------------------------------ | | `invalid_parameters` | Price not on a valid step, or RFQ already closed | | `RFQ_CLOSED` | RFQ was deleted, expired, or already executed | | `INSUFFICIENT_BALANCE` | Not enough funds for the trade | | `409 Conflict` | Open RFQ already exists on this market ticker | # Targets & Milestones Source: https://docs.kalshi.com/getting_started/targets_and_milestones Using milestones and structured targets in the Trade API Kalshi exposes two related metadata objects that are useful when working with event and market data: * `milestones` describe a real-world occurrence tied to one or more events * `structured_targets` describe a real-world entity that a milestone or market can reference If you need to group related events, start with milestones. If you need to identify a team, player, or other entity referenced by a market, use structured targets. ## Milestones A milestone links Kalshi events to a real-world occurrence. Useful fields on a milestone include: * `id`, `type`, `title`, `start_date`, `end_date` * `primary_event_tickers` for the milestone's core markets * `related_event_tickers` for the broader set of events tied to the same occurrence * `details` for type-specific metadata * `source_id` and `source_ids` when external identifiers are available `details` is flexible JSON and varies by milestone type. For sports milestones, it commonly contains structured target IDs such as `home_team_id` or `away_team_id`. In practice, `related_event_tickers` is often a superset of `primary_event_tickers`. For example, a recent `Wyoming General Elections` `one_off_milestone` in Redshift had: * `primary_event_tickers`: `SENATEWY-26` * `related_event_tickers`: `SENATEWY-26`, `GOVPARTYWY-26`, and `KXHOUSERACE-WYAL-26` Those are event tickers, not display titles. In this case they point to the Wyoming Senate, Wyoming Governor, and Wyoming at-large House race events. That broader grouping is useful when you want all of the markets tied to one real-world occurrence. For milestone types that expose live updates, the same milestone ID is also the key used by the live data API. ### Fetch milestones Use the [Get Milestone](/api-reference/milestone/get-milestone) and [Get Milestones](/api-reference/milestone/get-milestones) endpoint docs for the supported parameters and response shape. If you want milestones returned alongside events, use [Get Events](/api-reference/events/get-events) with `with_milestones=true`. The events response includes a top-level `milestones` array alongside `events`. ### Use milestones to group events A milestone is often the easiest way to find other events tied to the same occurrence. Query by `related_event_ticker`, then read `related_event_tickers` or `primary_event_tickers` from the returned milestone. Once you have the right milestone, use [Get Live Data](/api-reference/live-data/get-live-data) when that milestone type supports live updates. ## Structured Targets A structured target identifies a real-world entity that can be referenced elsewhere in the API. Useful fields on a structured target include: * `id`, `name`, `type` * `details` for type-specific metadata * `source_id` and `source_ids` when external identifiers are available Like milestone `details`, structured target `details` is flexible JSON and depends on the target type. ### Fetch structured targets Use the [Get Structured Target](/api-reference/structured-targets/get-structured-target) and [Get Structured Targets](/api-reference/structured-targets/get-structured-targets) endpoint docs for the supported parameters and response shape. `type` values are not a short fixed list. Integrations should filter by the values they need rather than hardcoding a small allowlist. ## How They Connect To Markets Markets can reference structured targets through `custom_strike`. ```json theme={null} { "strike_type": "structured", "custom_strike": { "basketball_team": "2ef4d31c-0b46-4f43-a403-f44d62489034" } } ``` For `strike_type: "structured"`, the value inside `custom_strike` is a structured target ID. You can resolve it with the [Get Structured Target](/api-reference/structured-targets/get-structured-target) endpoint. For numeric strike types, use `floor_strike` and `cap_strike` instead of `custom_strike`. # Kalshi Glossary Source: https://docs.kalshi.com/getting_started/terms Core terminology used in the Kalshi exchange Here are some core terminologies used in Kalshi exchange: **Category:** A high-level discovery grouping for related series, such as sports, crypto, or weather. A series belongs to one category. Use [Get Series List](/api-reference/market/get-series-list) with the `category` filter to browse series in a category. **Subcategory:** A narrower discovery grouping within a category. A series can belong to multiple subcategories. In API filters, subcategories are often represented as tags; use [Get Tags for Series Categories](/api-reference/search/get-tags-for-series-categories) to discover tags grouped by category. **Market:** A single binary market. This is a low level object which rarely will need to be exposed on its own to members. The usage of the term "market" here is consistent with how it's used in the backend and API. **Event:** An event is a collection of markets and the basic unit that members should interact with on Kalshi. **Series:** A series is a collection of related events. The following should hold true for events that make up a series: * Each event should look at similar data for determination, but translated over another, disjoint time period. * Series should never have a logical outcome dependency between events. * Events in a series should have the same ticker prefix. ## Ticker Conventions Categories and subcategories help organize and filter series, but they are not part of the ticker convention. Tickers often follow `Series -> Event -> Market`: for example, the `KXHIGHNY` series may have an event like `KXHIGHNY-24JAN01`, and that event may have a market like `KXHIGHNY-24JAN01-T60`. There are occasional exceptions, so do not parse ticker strings to infer relationships. Best practice is to use the series, event, market, and search endpoints and rely on fields like `series_ticker`, `event_ticker`, `category`, and `tags`. Please see the "Timeline and Payout" dropdown on a market's page to find the Market, Event, and Series tickers. Note that the market ticker will depend on which market you are looking at on that page. For example, Trump and Harris are each their own market. # ApiKeys Source: https://docs.kalshi.com/python-sdk/api/ApiKeysApi Python SDK methods for ApiKeys operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ------------------------------------------- | ---------------------------- | ---------------- | | [**create\_api\_key**](#create-api-key) | **POST** /api\_keys | Create API Key | | [**delete\_api\_key**](#delete-api-key) | **DELETE** /api\_keys/ | Delete API Key | | [**generate\_api\_key**](#generate-api-key) | **POST** /api\_keys/generate | Generate API Key | | [**get\_api\_keys**](#get-api-keys) | **GET** /api\_keys | Get API Keys | # **create\_api\_key** > CreateApiKeyResponse create\_api\_key(create\_api\_key\_request) Create API Key Endpoint for creating a new API key with a user-provided public key. This endpoint allows users with Premier or Market Maker API usage levels to create API keys by providing their own RSA public key. The platform will use this public key to verify signatures on API requests. ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ---------------------------------------------------------------------------------------- | ----------- | ----- | | **create\_api\_key\_request** | [**CreateApiKeyRequest**](https://docs.kalshi.com/python-sdk/models/CreateApiKeyRequest) | | | ### Return type [**CreateApiKeyResponse**](https://docs.kalshi.com/python-sdk/models/CreateApiKeyResponse) ### HTTP response details | Status code | Description | | ----------- | ---------------------------------------- | | **201** | API key created successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized | | **403** | Forbidden - insufficient API usage level | | **500** | Internal server error | # **delete\_api\_key** > delete\_api\_key(api\_key) Delete API Key Endpoint for deleting an existing API key. This endpoint permanently deletes an API key. Once deleted, the key can no longer be used for authentication. This action cannot be undone. ### Parameters | Name | Type | Description | Notes | | ------------ | ------- | -------------------- | ----- | | **api\_key** | **str** | API key ID to delete | | ### Return type void (empty response body) ### HTTP response details | Status code | Description | | ----------- | -------------------------------- | | **204** | API key successfully deleted | | **400** | Bad request - invalid API key ID | | **401** | Unauthorized | | **404** | API key not found | | **500** | Internal server error | # **generate\_api\_key** > GenerateApiKeyResponse generate\_api\_key(generate\_api\_key\_request) Generate API Key Endpoint for generating a new API key with an automatically created key pair. This endpoint generates both a public and private RSA key pair. The public key is stored on the platform, while the private key is returned to the user and must be stored securely. The private key cannot be retrieved again. ### Parameters | Name | Type | Description | Notes | | ------------------------------- | -------------------------------------------------------------------------------------------- | ----------- | ----- | | **generate\_api\_key\_request** | [**GenerateApiKeyRequest**](https://docs.kalshi.com/python-sdk/models/GenerateApiKeyRequest) | | | ### Return type [**GenerateApiKeyResponse**](https://docs.kalshi.com/python-sdk/models/GenerateApiKeyResponse) ### HTTP response details | Status code | Description | | ----------- | ------------------------------ | | **201** | API key generated successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized | | **500** | Internal server error | # **get\_api\_keys** > GetApiKeysResponse get\_api\_keys() Get API Keys Endpoint for retrieving all API keys associated with the authenticated user. API keys allow programmatic access to the platform without requiring username/password authentication. Each key has a unique identifier and name. ### Parameters This endpoint does not need any parameter. ### Return type [**GetApiKeysResponse**](https://docs.kalshi.com/python-sdk/models/GetApiKeysResponse) ### HTTP response details | Status code | Description | | ----------- | --------------------------------------- | | **200** | List of API keys retrieved successfully | | **401** | Unauthorized | | **500** | Internal server error | # Communications Source: https://docs.kalshi.com/python-sdk/api/CommunicationsApi Python SDK methods for Communications operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ----------------------------------------------------- | --------------------------------------- | --------------------- | | [**accept\_quote**](#accept-quote) | **PUT** /communications/quotes//accept | Accept Quote | | [**confirm\_quote**](#confirm-quote) | **PUT** /communications/quotes//confirm | Confirm Quote | | [**create\_quote**](#create-quote) | **POST** /communications/quotes | Create Quote | | [**create\_rfq**](#create-rfq) | **POST** /communications/rfqs | Create RFQ | | [**delete\_quote**](#delete-quote) | **DELETE** /communications/quotes/ | Delete Quote | | [**delete\_rfq**](#delete-rfq) | **DELETE** /communications/rfqs/ | Delete RFQ | | [**get\_communications\_id**](#get-communications-id) | **GET** /communications/id | Get Communications ID | | [**get\_quote**](#get-quote) | **GET** /communications/quotes/ | Get Quote | | [**get\_quotes**](#get-quotes) | **GET** /communications/quotes | Get Quotes | | [**get\_rfq**](#get-rfq) | **GET** /communications/rfqs/ | Get RFQ | | [**get\_rfqs**](#get-rfqs) | **GET** /communications/rfqs | Get RFQs | # **accept\_quote** > accept\_quote(quote\_id, accept\_quote\_request) Accept Quote Endpoint for accepting a quote. This will require the quoter to confirm ### Parameters | Name | Type | Description | Notes | | -------------------------- | -------------------------------------------------------------------------------------- | ----------- | ----- | | **quote\_id** | **str** | Quote ID | | | **accept\_quote\_request** | [**AcceptQuoteRequest**](https://docs.kalshi.com/python-sdk/models/AcceptQuoteRequest) | | | ### Return type void (empty response body) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **204** | Quote accepted successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | # **confirm\_quote** > confirm\_quote(quote\_id, body=body) Confirm Quote Endpoint for confirming a quote. This will start a timer for order execution ### Parameters | Name | Type | Description | Notes | | ------------- | ---------- | ----------- | ----------- | | **quote\_id** | **str** | Quote ID | | | **body** | **object** | | \[optional] | ### Return type void (empty response body) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **204** | Quote confirmed successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | # **create\_quote** > CreateQuoteResponse create\_quote(create\_quote\_request) Create Quote Endpoint for creating a quote in response to an RFQ ### Parameters | Name | Type | Description | Notes | | -------------------------- | -------------------------------------------------------------------------------------- | ----------- | ----- | | **create\_quote\_request** | [**CreateQuoteRequest**](https://docs.kalshi.com/python-sdk/models/CreateQuoteRequest) | | | ### Return type [**CreateQuoteResponse**](https://docs.kalshi.com/python-sdk/models/CreateQuoteResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **201** | Quote created successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **create\_rfq** > CreateRFQResponse create\_rfq(create\_rfq\_request) Create RFQ Endpoint for creating a new RFQ. You can have a maximum of 100 open RFQs at a time. ### Parameters | Name | Type | Description | Notes | | ------------------------ | ---------------------------------------------------------------------------------- | ----------- | ----- | | **create\_rfq\_request** | [**CreateRFQRequest**](https://docs.kalshi.com/python-sdk/models/CreateRFQRequest) | | | ### Return type [**CreateRFQResponse**](https://docs.kalshi.com/python-sdk/models/CreateRFQResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------------------------- | | **201** | RFQ created successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **409** | Conflict - resource already exists or cannot be modified | | **500** | Internal server error | # **delete\_quote** > delete\_quote(quote\_id) Delete Quote Endpoint for deleting a quote, which means it can no longer be accepted. ### Parameters | Name | Type | Description | Notes | | ------------- | ------- | ----------- | ----- | | **quote\_id** | **str** | Quote ID | | ### Return type void (empty response body) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **204** | Quote deleted successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | # **delete\_rfq** > delete\_rfq(rfq\_id) Delete RFQ Endpoint for deleting an RFQ by ID ### Parameters | Name | Type | Description | Notes | | ----------- | ------- | ----------- | ----- | | **rfq\_id** | **str** | RFQ ID | | ### Return type void (empty response body) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **204** | RFQ deleted successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | # **get\_communications\_id** > GetCommunicationsIDResponse get\_communications\_id() Get Communications ID Endpoint for getting the communications ID of the logged-in user. ### Parameters This endpoint does not need any parameter. ### Return type [**GetCommunicationsIDResponse**](https://docs.kalshi.com/python-sdk/models/GetCommunicationsIDResponse) ### HTTP response details | Status code | Description | | ----------- | ---------------------------------------- | | **200** | Communications ID retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_quote** > GetQuoteResponse get\_quote(quote\_id) Get Quote Endpoint for getting a particular quote ### Parameters | Name | Type | Description | Notes | | ------------- | ------- | ----------- | ----- | | **quote\_id** | **str** | Quote ID | | ### Return type [**GetQuoteResponse**](https://docs.kalshi.com/python-sdk/models/GetQuoteResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Quote retrieved successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | # **get\_quotes** > GetQuotesResponse get\_quotes(cursor=cursor, event\_ticker=event\_ticker, market\_ticker=market\_ticker, limit=limit, status=status, quote\_creator\_user\_id=quote\_creator\_user\_id, user\_filter=user\_filter, rfq\_user\_filter=rfq\_user\_filter, rfq\_creator\_user\_id=rfq\_creator\_user\_id, rfq\_creator\_subtrader\_id=rfq\_creator\_subtrader\_id, rfq\_id=rfq\_id) Get Quotes Endpoint for getting quotes ### Parameters | Name | Type | Description | Notes | | ------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | | **event\_ticker** | **str** | Event ticker to filter by. Only a single event ticker is supported. | \[optional] | | **market\_ticker** | **str** | Filter by market ticker | \[optional] | | **limit** | **int** | Parameter to specify the number of results per page. Defaults to 500. | \[optional] \[default to 500] | | **status** | **str** | Filter quotes by status | \[optional] | | **quote\_creator\_user\_id** | **str** | Filter quotes by quote creator user ID | \[optional] | | **user\_filter** | [**UserFilter**](https://docs.kalshi.com/python-sdk/models/) | Filter for quotes created by the authenticated user. | \[optional] | | **rfq\_user\_filter** | [**UserFilter**](https://docs.kalshi.com/python-sdk/models/) | Filter for quotes responding to RFQs created by the authenticated user. | \[optional] | | **rfq\_creator\_user\_id** | **str** | Filter quotes by RFQ creator user ID | \[optional] | | **rfq\_creator\_subtrader\_id** | **str** | Filter quotes by RFQ creator subtrader ID (FCM members only) | \[optional] | | **rfq\_id** | **str** | Filter quotes by RFQ ID | \[optional] | ### Return type [**GetQuotesResponse**](https://docs.kalshi.com/python-sdk/models/GetQuotesResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Quotes retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_rfq** > GetRFQResponse get\_rfq(rfq\_id) Get RFQ Endpoint for getting a single RFQ by id ### Parameters | Name | Type | Description | Notes | | ----------- | ------- | ----------- | ----- | | **rfq\_id** | **str** | RFQ ID | | ### Return type [**GetRFQResponse**](https://docs.kalshi.com/python-sdk/models/GetRFQResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | RFQ retrieved successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | # **get\_rfqs** > GetRFQsResponse get\_rfqs(cursor=cursor, event\_ticker=event\_ticker, market\_ticker=market\_ticker, subaccount=subaccount, limit=limit, status=status, creator\_user\_id=creator\_user\_id, user\_filter=user\_filter) Get RFQs Endpoint for getting RFQs ### Parameters | Name | Type | Description | Notes | | --------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | | **event\_ticker** | **str** | Event ticker to filter by. Only a single event ticker is supported. | \[optional] | | **market\_ticker** | **str** | Filter by market ticker | \[optional] | | **subaccount** | **int** | Subaccount number (0 for primary, 1-32 for subaccounts). If omitted, defaults to all subaccounts. | \[optional] | | **limit** | **int** | Parameter to specify the number of results per page. Defaults to 100. | \[optional] \[default to 100] | | **status** | **str** | Filter RFQs by status | \[optional] | | **creator\_user\_id** | **str** | Filter RFQs by creator user ID | \[optional] | | **user\_filter** | [**UserFilter**](https://docs.kalshi.com/python-sdk/models/) | | \[optional] | ### Return type [**GetRFQsResponse**](https://docs.kalshi.com/python-sdk/models/GetRFQsResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | RFQs retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # Events Source: https://docs.kalshi.com/python-sdk/api/EventsApi Python SDK methods for Events operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ----------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------- | | [**get\_event**](#get-event) | **GET** /events/ | Get Event | | [**get\_event\_forecast\_percentiles\_history**](#get-event-forecast-percentiles-history) | **GET** /series//events//forecast\_percentile\_history | Get Event Forecast Percentile History | | [**get\_event\_metadata**](#get-event-metadata) | **GET** /events//metadata | Get Event Metadata | | [**get\_events**](#get-events) | **GET** /events | Get Events | | [**get\_market\_candlesticks\_by\_event**](#get-market-candlesticks-by-event) | **GET** /series//events//candlesticks | Get Event Candlesticks | | [**get\_multivariate\_events**](#get-multivariate-events) | **GET** /events/multivariate | Get Multivariate Events | # **get\_event** > GetEventResponse get\_event(event\_ticker, with\_nested\_markets=with\_nested\_markets) Get Event Endpoint for getting data about an event by its ticker. An event represents a real-world occurrence that can be traded on, such as an election, sports game, or economic indicator release. Events contain one or more markets where users can place trades on different outcomes. All events are accessible through this endpoint, even if their associated markets are older than the historical cutoff. ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | | **event\_ticker** | **str** | Event ticker | | | **with\_nested\_markets** | **bool** | If true, markets are included within the event object. If false (default), markets are returned as a separate top-level field in the response. Historical markets settled before the historical cutoff will not be included. | \[optional] \[default to False] | ### Return type [**GetEventResponse**](https://docs.kalshi.com/python-sdk/models/GetEventResponse) ### HTTP response details | Status code | Description | | ----------- | ---------------------------- | | **200** | Event retrieved successfully | | **400** | Bad request | | **404** | Event not found | | **401** | Unauthorized | | **500** | Internal server error | # **get\_event\_forecast\_percentiles\_history** > GetEventForecastPercentilesHistoryResponse get\_event\_forecast\_percentiles\_history(ticker, series\_ticker, percentiles, start\_ts, end\_ts, period\_interval) Get Event Forecast Percentile History Endpoint for getting the historical raw and formatted forecast numbers for an event at specific percentiles. ### Parameters | Name | Type | Description | Notes | | -------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ----- | | **ticker** | **str** | The event ticker | | | **series\_ticker** | **str** | The series ticker | | | **percentiles** | [**List\[int\]**](https://docs.kalshi.com/python-sdk/models/int) | Array of percentile values to retrieve (0-10000, max 10 values) | | | **start\_ts** | **int** | Start timestamp for the range | | | **end\_ts** | **int** | End timestamp for the range | | | **period\_interval** | **int** | Specifies the length of each forecast period, in minutes. 0 for 5-second intervals, or 1, 60, or 1440 for minute-based intervals. | | ### Return type [**GetEventForecastPercentilesHistoryResponse**](https://docs.kalshi.com/python-sdk/models/GetEventForecastPercentilesHistoryResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------------------------- | | **200** | Event forecast percentile history retrieved successfully | | **400** | Bad request | | **401** | Unauthorized | | **500** | Internal server error | # **get\_event\_metadata** > GetEventMetadataResponse get\_event\_metadata(event\_ticker) Get Event Metadata Endpoint for getting metadata about an event by its ticker. Returns only the metadata information for an event. ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | ------------ | ----- | | **event\_ticker** | **str** | Event ticker | | ### Return type [**GetEventMetadataResponse**](https://docs.kalshi.com/python-sdk/models/GetEventMetadataResponse) ### HTTP response details | Status code | Description | | ----------- | ------------------------------------- | | **200** | Event metadata retrieved successfully | | **400** | Bad request | | **404** | Event not found | | **401** | Unauthorized | | **500** | Internal server error | # **get\_events** > GetEventsResponse get\_events(limit=limit, cursor=cursor, with\_nested\_markets=with\_nested\_markets, with\_milestones=with\_milestones, status=status, series\_ticker=series\_ticker, min\_close\_ts=min\_close\_ts, min\_updated\_ts=min\_updated\_ts) Get Events Get all events. This endpoint excludes multivariate events. To retrieve multivariate events, use the GET /events/multivariate endpoint. All events are accessible through this endpoint, even if their associated markets are older than the historical cutoff. ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | | **limit** | **int** | Parameter to specify the number of results per page. Defaults to 200. Maximum value is 200. | \[optional] \[default to 200] | | **cursor** | **str** | Parameter to specify the pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | | **with\_nested\_markets** | **bool** | Parameter to specify if nested markets should be included in the response. When true, each event will include a 'markets' field containing a list of Market objects associated with that event. Historical markets settled before the historical cutoff will not be included. | \[optional] \[default to False] | | **with\_milestones** | **bool** | If true, includes related milestones as a field alongside events. | \[optional] \[default to False] | | **status** | **str** | Filter by event status. Possible values are 'unopened', 'open', 'closed', 'settled'. Leave empty to return events with any status. | \[optional] | | **series\_ticker** | **str** | Filter by series ticker | \[optional] | | **min\_close\_ts** | **int** | Filter events with at least one market with close timestamp greater than this Unix timestamp (in seconds). | \[optional] | | **min\_updated\_ts** | **int** | Filter events with metadata updated after this Unix timestamp (in seconds). Use this to efficiently poll for changes. | \[optional] | ### Return type [**GetEventsResponse**](https://docs.kalshi.com/python-sdk/models/GetEventsResponse) ### HTTP response details | Status code | Description | | ----------- | ----------------------------- | | **200** | Events retrieved successfully | | **400** | Bad request | | **401** | Unauthorized | | **500** | Internal server error | # **get\_market\_candlesticks\_by\_event** > GetEventCandlesticksResponse get\_market\_candlesticks\_by\_event(ticker, series\_ticker, start\_ts, end\_ts, period\_interval) Get Event Candlesticks End-point for returning aggregated data across all markets corresponding to an event. ### Parameters | Name | Type | Description | Notes | | -------------------- | ------- | ------------------------------------------------------------------------------------------------------ | ----- | | **ticker** | **str** | The event ticker | | | **series\_ticker** | **str** | The series ticker | | | **start\_ts** | **int** | Start timestamp for the range | | | **end\_ts** | **int** | End timestamp for the range | | | **period\_interval** | **int** | Specifies the length of each candlestick period, in minutes. Must be one minute, one hour, or one day. | | ### Return type [**GetEventCandlesticksResponse**](https://docs.kalshi.com/python-sdk/models/GetEventCandlesticksResponse) ### HTTP response details | Status code | Description | | ----------- | ----------------------------------------- | | **200** | Event candlesticks retrieved successfully | | **400** | Bad request | | **401** | Unauthorized | | **500** | Internal server error | # **get\_multivariate\_events** > GetMultivariateEventsResponse get\_multivariate\_events(limit=limit, cursor=cursor, series\_ticker=series\_ticker, collection\_ticker=collection\_ticker, with\_nested\_markets=with\_nested\_markets) Get Multivariate Events Retrieve multivariate (combo) events. These are dynamically created events from multivariate event collections. Supports filtering by series and collection ticker. ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | | **limit** | **int** | Number of results per page. Defaults to 100. Maximum value is 200. | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. | \[optional] | | **series\_ticker** | **str** | Filter by series ticker | \[optional] | | **collection\_ticker** | **str** | Filter events by collection ticker. Returns only multivariate events belonging to the specified collection. Cannot be used together with series\_ticker. | \[optional] | | **with\_nested\_markets** | **bool** | Parameter to specify if nested markets should be included in the response. When true, each event will include a 'markets' field containing a list of Market objects associated with that event. | \[optional] \[default to False] | ### Return type [**GetMultivariateEventsResponse**](https://docs.kalshi.com/python-sdk/models/GetMultivariateEventsResponse) ### HTTP response details | Status code | Description | | ----------- | ------------------------------------------ | | **200** | Multivariate events retrieved successfully | | **400** | Bad request - invalid parameters | | **401** | Unauthorized | | **500** | Internal server error | # Exchange Source: https://docs.kalshi.com/python-sdk/api/ExchangeApi Python SDK methods for Exchange operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | --------------------------------------------------------------- | --------------------------------------- | -------------------------- | | [**get\_exchange\_announcements**](#get-exchange-announcements) | **GET** /exchange/announcements | Get Exchange Announcements | | [**get\_exchange\_schedule**](#get-exchange-schedule) | **GET** /exchange/schedule | Get Exchange Schedule | | [**get\_exchange\_status**](#get-exchange-status) | **GET** /exchange/status | Get Exchange Status | | [**get\_series\_fee\_changes**](#get-series-fee-changes) | **GET** /series/fee\_changes | Get Series Fee Changes | | [**get\_user\_data\_timestamp**](#get-user-data-timestamp) | **GET** /exchange/user\_data\_timestamp | Get User Data Timestamp | # **get\_exchange\_announcements** > GetExchangeAnnouncementsResponse get\_exchange\_announcements() Get Exchange Announcements Endpoint for getting all exchange-wide announcements. ### Parameters This endpoint does not need any parameter. ### Return type [**GetExchangeAnnouncementsResponse**](https://docs.kalshi.com/python-sdk/models/GetExchangeAnnouncementsResponse) ### HTTP response details | Status code | Description | | ----------- | --------------------------------------------- | | **200** | Exchange announcements retrieved successfully | | **500** | Internal server error | # **get\_exchange\_schedule** > GetExchangeScheduleResponse get\_exchange\_schedule() Get Exchange Schedule Endpoint for getting the exchange schedule. ### Parameters This endpoint does not need any parameter. ### Return type [**GetExchangeScheduleResponse**](https://docs.kalshi.com/python-sdk/models/GetExchangeScheduleResponse) ### HTTP response details | Status code | Description | | ----------- | ---------------------------------------- | | **200** | Exchange schedule retrieved successfully | | **500** | Internal server error | # **get\_exchange\_status** > ExchangeStatus get\_exchange\_status() Get Exchange Status Endpoint for getting the exchange status. ### Parameters This endpoint does not need any parameter. ### Return type [**ExchangeStatus**](https://docs.kalshi.com/python-sdk/models/ExchangeStatus) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Exchange status retrieved successfully | | **500** | Internal server error | | **503** | Service unavailable | | **504** | Gateway timeout | # **get\_series\_fee\_changes** > GetSeriesFeeChangesResponse get\_series\_fee\_changes(series\_ticker=series\_ticker, show\_historical=show\_historical) Get Series Fee Changes ### Parameters | Name | Type | Description | Notes | | -------------------- | -------- | ----------- | ------------------------------- | | **series\_ticker** | **str** | | \[optional] | | **show\_historical** | **bool** | | \[optional] \[default to False] | ### Return type [**GetSeriesFeeChangesResponse**](https://docs.kalshi.com/python-sdk/models/GetSeriesFeeChangesResponse) ### HTTP response details | Status code | Description | | ----------- | ----------------------------------------- | | **200** | Series fee changes retrieved successfully | | **400** | Bad request - invalid input | | **500** | Internal server error | # **get\_user\_data\_timestamp** > GetUserDataTimestampResponse get\_user\_data\_timestamp() Get User Data Timestamp There is typically a short delay before exchange events are reflected in the API endpoints. Whenever possible, combine API responses to PUT/POST/DELETE requests with websocket data to obtain the most accurate view of the exchange state. This endpoint provides an approximate indication of when the data from the following endpoints was last validated: GetBalance, GetOrder(s), GetFills, GetPositions ### Parameters This endpoint does not need any parameter. ### Return type [**GetUserDataTimestampResponse**](https://docs.kalshi.com/python-sdk/models/GetUserDataTimestampResponse) ### HTTP response details | Status code | Description | | ----------- | ------------------------------------------ | | **200** | User data timestamp retrieved successfully | | **500** | Internal server error | # Markets Source: https://docs.kalshi.com/python-sdk/api/MarketsApi Python SDK methods for Markets operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | --------------------------------------------------------- | -------------------------------------- | ----------------------- | | [**get\_market**](#get-market) | **GET** /markets/ | Get Market | | [**get\_market\_candlesticks**](#get-market-candlesticks) | **GET** /series//markets//candlesticks | Get Market Candlesticks | | [**get\_market\_orderbook**](#get-market-orderbook) | **GET** /markets//orderbook | Get Market Orderbook | | [**get\_markets**](#get-markets) | **GET** /markets | Get Markets | | [**get\_trades**](#get-trades) | **GET** /markets/trades | Get Trades | # **get\_market** > GetMarketResponse get\_market(ticker) Get Market Get a single market by its ticker. A market represents a specific binary outcome within an event that users can trade on (e.g., "Will candidate X win?"). Markets have yes/no positions, current prices, volume, and settlement rules. ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_market_response import GetMarketResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) ticker = 'ticker_example' # str | Market ticker try: # Get Market api_response = client.get_market(ticker) print("The response of MarketsApi->get_market:\n") pprint(api_response) except Exception as e: print("Exception when calling MarketsApi->get_market: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | ------------- | ----- | | **ticker** | **str** | Market ticker | | ### Return type [**GetMarketResponse**](https://docs.kalshi.com/python-sdk/models/GetMarketResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Market retrieved successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # **get\_market\_candlesticks** > GetMarketCandlesticksResponse get\_market\_candlesticks(ticker, market\_ticker, start\_ts=start\_ts, end\_ts=end\_ts, period\_interval=period\_interval) Get Market Candlesticks Get candlestick data for a market within a series ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_market_candlesticks_response import GetMarketCandlesticksResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) ticker = 'ticker_example' # str | The series ticker market_ticker = 'market_ticker_example' # str | The market ticker start_ts = 56 # int | Start timestamp for the range (optional) end_ts = 56 # int | End timestamp for the range (optional) period_interval = 'period_interval_example' # str | Period interval for candlesticks (e.g., 1m, 5m, 1h, 1d) (optional) try: # Get Market Candlesticks api_response = client.get_market_candlesticks(ticker, market_ticker, start_ts=start_ts, end_ts=end_ts, period_interval=period_interval) print("The response of MarketsApi->get_market_candlesticks:\n") pprint(api_response) except Exception as e: print("Exception when calling MarketsApi->get_market_candlesticks: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------- | ------- | ------------------------------------------------------- | ----------- | | **ticker** | **str** | The series ticker | | | **market\_ticker** | **str** | The market ticker | | | **start\_ts** | **int** | Start timestamp for the range | \[optional] | | **end\_ts** | **int** | End timestamp for the range | \[optional] | | **period\_interval** | **str** | Period interval for candlesticks (e.g., 1m, 5m, 1h, 1d) | \[optional] | ### Return type [**GetMarketCandlesticksResponse**](https://docs.kalshi.com/python-sdk/models/GetMarketCandlesticksResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Candlesticks retrieved successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # **get\_market\_orderbook** > GetMarketOrderbookResponse get\_market\_orderbook(ticker, depth=depth) Get Market Orderbook Get the orderbook for a market ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_market_orderbook_response import GetMarketOrderbookResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) ticker = 'ticker_example' # str | Market ticker depth = 10 # int | Depth of the orderbook to retrieve (optional) (default to 10) try: # Get Market Orderbook api_response = client.get_market_orderbook(ticker, depth=depth) print("The response of MarketsApi->get_market_orderbook:\n") pprint(api_response) except Exception as e: print("Exception when calling MarketsApi->get_market_orderbook: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | ---------------------------------- | ---------------------------- | | **ticker** | **str** | Market ticker | | | **depth** | **int** | Depth of the orderbook to retrieve | \[optional] \[default to 10] | ### Return type [**GetMarketOrderbookResponse**](https://docs.kalshi.com/python-sdk/models/GetMarketOrderbookResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Orderbook retrieved successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # **get\_markets** > GetMarketsResponse get\_markets(limit=limit, cursor=cursor, event\_ticker=event\_ticker, series\_ticker=series\_ticker, max\_close\_ts=max\_close\_ts, min\_close\_ts=min\_close\_ts, status=status, tickers=tickers) Get Markets List and discover markets on Kalshi. A market represents a specific binary outcome within an event that users can trade on (e.g., "Will candidate X win?"). Markets have yes/no positions, current prices, volume, and settlement rules. This endpoint returns a paginated response. Use the 'limit' parameter to control page size (1-1000, defaults to 100). The response includes a 'cursor' field - pass this value in the 'cursor' parameter of your next request to get the next page. An empty cursor indicates no more pages are available. ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_markets_response import GetMarketsResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) limit = 100 # int | Number of results per page. Defaults to 100. Maximum value is 1000. (optional) (default to 100) cursor = 'cursor_example' # str | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. (optional) event_ticker = 'event_ticker_example' # str | Filter by event ticker (optional) series_ticker = 'series_ticker_example' # str | Filter by series ticker (optional) max_close_ts = 56 # int | Filter items that close before this Unix timestamp (optional) min_close_ts = 56 # int | Filter items that close after this Unix timestamp (optional) status = 'status_example' # str | Filter by market status. Comma-separated list. Possible values are 'initialized', 'open', 'closed', 'settled', 'determined'. Note that the API accepts 'open' for filtering but returns 'active' in the response. Leave empty to return markets with any status. (optional) tickers = 'tickers_example' # str | Filter by specific market tickers. Comma-separated list of market tickers to retrieve. (optional) try: # Get Markets api_response = client.get_markets(limit=limit, cursor=cursor, event_ticker=event_ticker, series_ticker=series_ticker, max_close_ts=max_close_ts, min_close_ts=min_close_ts, status=status, tickers=tickers) print("The response of MarketsApi->get_markets:\n") pprint(api_response) except Exception as e: print("Exception when calling MarketsApi->get_markets: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **limit** | **int** | Number of results per page. Defaults to 100. Maximum value is 1000. | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | | **event\_ticker** | **str** | Filter by event ticker | \[optional] | | **series\_ticker** | **str** | Filter by series ticker | \[optional] | | **max\_close\_ts** | **int** | Filter items that close before this Unix timestamp | \[optional] | | **min\_close\_ts** | **int** | Filter items that close after this Unix timestamp | \[optional] | | **status** | **str** | Filter by market status. Comma-separated list. Possible values are 'initialized', 'open', 'closed', 'settled', 'determined'. Note that the API accepts 'open' for filtering but returns 'active' in the response. Leave empty to return markets with any status. | \[optional] | | **tickers** | **str** | Filter by specific market tickers. Comma-separated list of market tickers to retrieve. | \[optional] | ### Return type [**GetMarketsResponse**](https://docs.kalshi.com/python-sdk/models/GetMarketsResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Markets retrieved successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # **get\_trades** > GetTradesResponse get\_trades(limit=limit, cursor=cursor, ticker=ticker, min\_ts=min\_ts, max\_ts=max\_ts) Get Trades Get all trades for all markets. A trade represents a completed transaction between two users on a specific market. Each trade includes the market ticker, price, quantity, and timestamp information. This endpoint returns a paginated response. Use the 'limit' parameter to control page size (1-1000, defaults to 100). The response includes a 'cursor' field - pass this value in the 'cursor' parameter of your next request to get the next page. An empty cursor indicates no more pages are available. ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_trades_response import GetTradesResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) limit = 100 # int | Number of results per page. Defaults to 100. Maximum value is 1000. (optional) (default to 100) cursor = 'cursor_example' # str | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. (optional) ticker = 'ticker_example' # str | Filter by market ticker (optional) min_ts = 56 # int | Filter items after this Unix timestamp (optional) max_ts = 56 # int | Filter items before this Unix timestamp (optional) try: # Get Trades api_response = client.get_trades(limit=limit, cursor=cursor, ticker=ticker, min_ts=min_ts, max_ts=max_ts) print("The response of MarketsApi->get_trades:\n") pprint(api_response) except Exception as e: print("Exception when calling MarketsApi->get_trades: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **limit** | **int** | Number of results per page. Defaults to 100. Maximum value is 1000. | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | | **ticker** | **str** | Filter by market ticker | \[optional] | | **min\_ts** | **int** | Filter items after this Unix timestamp | \[optional] | | **max\_ts** | **int** | Filter items before this Unix timestamp | \[optional] | ### Return type [**GetTradesResponse**](https://docs.kalshi.com/python-sdk/models/GetTradesResponse) ### HTTP response details | Status code | Description | | ----------- | ----------------------------- | | **200** | Trades retrieved successfully | | **400** | Bad request - invalid input | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # Milestones Source: https://docs.kalshi.com/python-sdk/api/MilestonesApi Python SDK methods for Milestones operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | -------------------------------------- | -------------------- | -------------- | | [**get\_milestone**](#get-milestone) | **GET** /milestones/ | Get Milestone | | [**get\_milestones**](#get-milestones) | **GET** /milestones | Get Milestones | # **get\_milestone** > GetMilestoneResponse get\_milestone(milestone\_id) Get Milestone Get a single milestone by ID ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_milestone_response import GetMilestoneResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) milestone_id = 'milestone_id_example' # str | Milestone ID try: # Get Milestone api_response = client.get_milestone(milestone_id) print("The response of MilestonesApi->get_milestone:\n") pprint(api_response) except Exception as e: print("Exception when calling MilestonesApi->get_milestone: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | ------------ | ----- | | **milestone\_id** | **str** | Milestone ID | | ### Return type [**GetMilestoneResponse**](https://docs.kalshi.com/python-sdk/models/GetMilestoneResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Milestone retrieved successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # **get\_milestones** > GetMilestonesResponse get\_milestones(status=status, limit=limit) Get Milestones Get all milestones ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_milestones_response import GetMilestonesResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) status = 'status_example' # str | Filter by milestone status (optional) limit = 100 # int | Number of items per page (minimum 1, maximum 500) (optional) (default to 100) try: # Get Milestones api_response = client.get_milestones(status=status, limit=limit) print("The response of MilestonesApi->get_milestones:\n") pprint(api_response) except Exception as e: print("Exception when calling MilestonesApi->get_milestones: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | ------------------------------------------------- | ----------------------------- | | **status** | **str** | Filter by milestone status | \[optional] | | **limit** | **int** | Number of items per page (minimum 1, maximum 500) | \[optional] \[default to 100] | ### Return type [**GetMilestonesResponse**](https://docs.kalshi.com/python-sdk/models/GetMilestonesResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Milestones retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # MultivariateCollections Source: https://docs.kalshi.com/python-sdk/api/MultivariateCollectionsApi Python SDK methods for MultivariateCollections operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | --------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------- | | [**get\_multivariate\_event\_collection**](#get-multivariate-event-collection) | **GET** /multivariate\_event\_collections/ | Get Multivariate Event Collection | | [**get\_multivariate\_event\_collections**](#get-multivariate-event-collections) | **GET** /multivariate\_event\_collections | Get Multivariate Event Collections | | [**lookup\_multivariate\_event\_collection\_bundle**](#lookup-multivariate-event-collection-bundle) | **POST** /multivariate\_event\_collections//lookup | Lookup Multivariate Event Collection Bundle | # **get\_multivariate\_event\_collection** > GetMultivariateEventCollectionResponse get\_multivariate\_event\_collection(collection\_ticker) Get Multivariate Event Collection Get a single multivariate event collection by ticker ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_multivariate_event_collection_response import GetMultivariateEventCollectionResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) collection_ticker = 'collection_ticker_example' # str | Collection ticker try: # Get Multivariate Event Collection api_response = client.get_multivariate_event_collection(collection_ticker) print("The response of MultivariateCollectionsApi->get_multivariate_event_collection:\n") pprint(api_response) except Exception as e: print("Exception when calling MultivariateCollectionsApi->get_multivariate_event_collection: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------- | ------- | ----------------- | ----- | | **collection\_ticker** | **str** | Collection ticker | | ### Return type [**GetMultivariateEventCollectionResponse**](https://docs.kalshi.com/python-sdk/models/GetMultivariateEventCollectionResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Collection retrieved successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # **get\_multivariate\_event\_collections** > GetMultivariateEventCollectionsResponse get\_multivariate\_event\_collections(status=status) Get Multivariate Event Collections Get all multivariate event collections ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_multivariate_event_collections_response import GetMultivariateEventCollectionsResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) status = 'status_example' # str | Filter by multivariate collection status (optional) try: # Get Multivariate Event Collections api_response = client.get_multivariate_event_collections(status=status) print("The response of MultivariateCollectionsApi->get_multivariate_event_collections:\n") pprint(api_response) except Exception as e: print("Exception when calling MultivariateCollectionsApi->get_multivariate_event_collections: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | ---------------------------------------- | ----------- | | **status** | **str** | Filter by multivariate collection status | \[optional] | ### Return type [**GetMultivariateEventCollectionsResponse**](https://docs.kalshi.com/python-sdk/models/GetMultivariateEventCollectionsResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Collections retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # **lookup\_multivariate\_event\_collection\_bundle** > LookupBundleResponse lookup\_multivariate\_event\_collection\_bundle(collection\_ticker, lookup\_bundle\_request) Lookup Multivariate Event Collection Bundle Lookup a bundle in a multivariate event collection ### Example ```python theme={null} import kalshi_python from kalshi_python.models.lookup_bundle_request import LookupBundleRequest from kalshi_python.models.lookup_bundle_response import LookupBundleResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) collection_ticker = 'collection_ticker_example' # str | Collection ticker lookup_bundle_request = kalshi_python.LookupBundleRequest() # LookupBundleRequest | try: # Lookup Multivariate Event Collection Bundle api_response = client.lookup_multivariate_event_collection_bundle(collection_ticker, lookup_bundle_request) print("The response of MultivariateCollectionsApi->lookup_multivariate_event_collection_bundle:\n") pprint(api_response) except Exception as e: print("Exception when calling MultivariateCollectionsApi->lookup_multivariate_event_collection_bundle: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ---------------------------------------------------------------------------------------- | ----------------- | ----- | | **collection\_ticker** | **str** | Collection ticker | | | **lookup\_bundle\_request** | [**LookupBundleRequest**](https://docs.kalshi.com/python-sdk/models/LookupBundleRequest) | | | ### Return type [**LookupBundleResponse**](https://docs.kalshi.com/python-sdk/models/LookupBundleResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Bundle lookup successful | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # Portfolio Source: https://docs.kalshi.com/python-sdk/api/PortfolioApi Python SDK methods for Portfolio operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | -------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------- | | [**apply\_subaccount\_transfer**](#apply-subaccount-transfer) | **POST** /portfolio/subaccounts/transfer | Transfer Between Subaccounts | | [**create\_subaccount**](#create-subaccount) | **POST** /portfolio/subaccounts | Create Subaccount | | [**get\_balance**](#get-balance) | **GET** /portfolio/balance | Get Balance | | [**get\_deposits**](#get-deposits) | **GET** /portfolio/deposits | Get Deposits | | [**get\_fills**](#get-fills) | **GET** /portfolio/fills | Get Fills | | [**get\_portfolio\_resting\_order\_total\_value**](#get-portfolio-resting-order-total-value) | **GET** /portfolio/summary/total\_resting\_order\_value | Get Total Resting Order Value | | [**get\_positions**](#get-positions) | **GET** /portfolio/positions | Get Positions | | [**get\_settlements**](#get-settlements) | **GET** /portfolio/settlements | Get Settlements | | [**get\_subaccount\_balances**](#get-subaccount-balances) | **GET** /portfolio/subaccounts/balances | Get All Subaccount Balances | | [**get\_subaccount\_netting**](#get-subaccount-netting) | **GET** /portfolio/subaccounts/netting | Get Subaccount Netting | | [**get\_subaccount\_transfers**](#get-subaccount-transfers) | **GET** /portfolio/subaccounts/transfers | Get Subaccount Transfers | | [**get\_withdrawals**](#get-withdrawals) | **GET** /portfolio/withdrawals | Get Withdrawals | | [**update\_subaccount\_netting**](#update-subaccount-netting) | **PUT** /portfolio/subaccounts/netting | Update Subaccount Netting | # **apply\_subaccount\_transfer** > object apply\_subaccount\_transfer(apply\_subaccount\_transfer\_request) Transfer Between Subaccounts Transfers funds between the authenticated user's subaccounts. Use 0 for the primary account, or 1-32 for numbered subaccounts. ### Parameters | Name | Type | Description | Notes | | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------- | ----- | | **apply\_subaccount\_transfer\_request** | [**ApplySubaccountTransferRequest**](https://docs.kalshi.com/python-sdk/models/ApplySubaccountTransferRequest) | | | ### Return type **object** ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Transfer completed successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **create\_subaccount** > CreateSubaccountResponse create\_subaccount() Create Subaccount Creates a new subaccount for the authenticated user. This endpoint is currently only available to institutions and market makers. Subaccounts are numbered sequentially starting from 1. Maximum 32 subaccounts per user. ### Parameters This endpoint does not need any parameter. ### Return type [**CreateSubaccountResponse**](https://docs.kalshi.com/python-sdk/models/CreateSubaccountResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **201** | Subaccount created successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_balance** > GetBalanceResponse get\_balance(subaccount=subaccount) Get Balance Endpoint for getting the balance and portfolio value of a member. Both values are returned in cents. ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------------------------------------------------------------------- | ----------- | | **subaccount** | **int** | Subaccount number (0 for primary, 1-32 for subaccounts). Defaults to 0. | \[optional] | ### Return type [**GetBalanceResponse**](https://docs.kalshi.com/python-sdk/models/GetBalanceResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Balance retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_deposits** > GetDepositsResponse get\_deposits(limit=limit, cursor=cursor) Get Deposits Endpoint for getting the member's deposit history. ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **limit** | **int** | Number of results per page. Defaults to 100. Maximum value is 500. | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | ### Return type [**GetDepositsResponse**](https://docs.kalshi.com/python-sdk/models/GetDepositsResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Deposits retrieved successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_fills** > GetFillsResponse get\_fills(ticker=ticker, order\_id=order\_id, min\_ts=min\_ts, max\_ts=max\_ts, limit=limit, cursor=cursor, subaccount=subaccount) Get Fills Endpoint for getting all fills for the member. A fill is when a trade you have is matched. Fills that occurred before the historical cutoff are only available via `GET /historical/fills`. See [Historical Data](https://docs.kalshi.com/getting_started/historical_data) for details. ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **ticker** | **str** | Filter by market ticker | \[optional] | | **order\_id** | **str** | Filter by order ID | \[optional] | | **min\_ts** | **int** | Filter items after this Unix timestamp | \[optional] | | **max\_ts** | **int** | Filter items before this Unix timestamp | \[optional] | | **limit** | **int** | Number of results per page. Defaults to 100. | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | | **subaccount** | **int** | Subaccount number (0 for primary, 1-32 for subaccounts). If omitted, defaults to all subaccounts. | \[optional] | ### Return type [**GetFillsResponse**](https://docs.kalshi.com/python-sdk/models/GetFillsResponse) ### HTTP response details | Status code | Description | | ----------- | ---------------------------- | | **200** | Fills retrieved successfully | | **400** | Bad request | | **401** | Unauthorized | | **500** | Internal server error | # **get\_portfolio\_resting\_order\_total\_value** > GetPortfolioRestingOrderTotalValueResponse get\_portfolio\_resting\_order\_total\_value() Get Total Resting Order Value Endpoint for getting the total value, in cents, of resting orders. This endpoint is only intended for use by FCM members (rare). Note: If you're uncertain about this endpoint, it likely does not apply to you. ### Parameters This endpoint does not need any parameter. ### Return type [**GetPortfolioRestingOrderTotalValueResponse**](https://docs.kalshi.com/python-sdk/models/GetPortfolioRestingOrderTotalValueResponse) ### HTTP response details | Status code | Description | | ----------- | ------------------------------------------------ | | **200** | Total resting order value retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_positions** > GetPositionsResponse get\_positions(cursor=cursor, limit=limit, count\_filter=count\_filter, ticker=ticker, event\_ticker=event\_ticker, subaccount=subaccount) Get Positions Restricts the positions to those with any of following fields with non-zero values, as a comma separated list. The following values are accepted: position, total\_traded ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **cursor** | **str** | The Cursor represents a pointer to the next page of records in the pagination. Use the value returned from the previous response to get the next page. | \[optional] | | **limit** | **int** | Parameter to specify the number of results per page. Defaults to 100. | \[optional] \[default to 100] | | **count\_filter** | **str** | Restricts the positions to those with any of following fields with non-zero values, as a comma separated list. The following values are accepted - position, total\_traded | \[optional] | | **ticker** | **str** | Filter by market ticker | \[optional] | | **event\_ticker** | **str** | Event ticker to filter by. Only a single event ticker is supported. | \[optional] | | **subaccount** | **int** | Subaccount number (0 for primary, 1-32 for subaccounts). Defaults to 0. | \[optional] | ### Return type [**GetPositionsResponse**](https://docs.kalshi.com/python-sdk/models/GetPositionsResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Positions retrieved successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_settlements** > GetSettlementsResponse get\_settlements(limit=limit, cursor=cursor, ticker=ticker, event\_ticker=event\_ticker, min\_ts=min\_ts, max\_ts=max\_ts, subaccount=subaccount) Get Settlements Endpoint for getting the member's settlements historical track. ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **limit** | **int** | Number of results per page. Defaults to 100. | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | | **ticker** | **str** | Filter by market ticker | \[optional] | | **event\_ticker** | **str** | Event ticker to filter by. Only a single event ticker is supported. | \[optional] | | **min\_ts** | **int** | Filter items after this Unix timestamp | \[optional] | | **max\_ts** | **int** | Filter items before this Unix timestamp | \[optional] | | **subaccount** | **int** | Subaccount number (0 for primary, 1-32 for subaccounts). If omitted, defaults to all subaccounts. | \[optional] | ### Return type [**GetSettlementsResponse**](https://docs.kalshi.com/python-sdk/models/GetSettlementsResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Settlements retrieved successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_subaccount\_balances** > GetSubaccountBalancesResponse get\_subaccount\_balances() Get All Subaccount Balances Gets balances for all subaccounts including the primary account. ### Parameters This endpoint does not need any parameter. ### Return type [**GetSubaccountBalancesResponse**](https://docs.kalshi.com/python-sdk/models/GetSubaccountBalancesResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Balances retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_subaccount\_netting** > GetSubaccountNettingResponse get\_subaccount\_netting() Get Subaccount Netting Gets the netting enabled settings for all subaccounts. ### Parameters This endpoint does not need any parameter. ### Return type [**GetSubaccountNettingResponse**](https://docs.kalshi.com/python-sdk/models/GetSubaccountNettingResponse) ### HTTP response details | Status code | Description | | ----------- | --------------------------------------- | | **200** | Netting settings retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_subaccount\_transfers** > GetSubaccountTransfersResponse get\_subaccount\_transfers(limit=limit, cursor=cursor) Get Subaccount Transfers Gets a paginated list of all transfers between subaccounts for the authenticated user. ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **limit** | **int** | Number of results per page. Defaults to 100. | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | ### Return type [**GetSubaccountTransfersResponse**](https://docs.kalshi.com/python-sdk/models/GetSubaccountTransfersResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Transfers retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **get\_withdrawals** > GetWithdrawalsResponse get\_withdrawals(limit=limit, cursor=cursor) Get Withdrawals Endpoint for getting the member's withdrawal history. ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | **limit** | **int** | Number of results per page. Defaults to 100. Maximum value is 500. | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | \[optional] | ### Return type [**GetWithdrawalsResponse**](https://docs.kalshi.com/python-sdk/models/GetWithdrawalsResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Withdrawals retrieved successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # **update\_subaccount\_netting** > update\_subaccount\_netting(update\_subaccount\_netting\_request) Update Subaccount Netting Updates the netting enabled setting for a specific subaccount. Use 0 for the primary account, or 1-32 for numbered subaccounts. ### Parameters | Name | Type | Description | Notes | | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------- | ----- | | **update\_subaccount\_netting\_request** | [**UpdateSubaccountNettingRequest**](https://docs.kalshi.com/python-sdk/models/UpdateSubaccountNettingRequest) | | | ### Return type void (empty response body) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Netting setting updated successfully | | **400** | Bad request - invalid input | | **401** | Unauthorized - authentication required | | **500** | Internal server error | # Series Source: https://docs.kalshi.com/python-sdk/api/SeriesApi Python SDK methods for Series operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ---------------------------------------------------- | ---------------- | -------------------- | | [**get\_series**](#get-series) | **GET** /series | Get Series | | [**get\_series\_by\_ticker**](#get-series-by-ticker) | **GET** /series/ | Get Series by Ticker | # **get\_series** > GetSeriesResponse get\_series(status=status) Get Series Get all market series ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_series_response import GetSeriesResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) status = 'status_example' # str | Filter by series status (optional) try: # Get Series api_response = client.get_series(status=status) print("The response of SeriesApi->get_series:\n") pprint(api_response) except Exception as e: print("Exception when calling SeriesApi->get_series: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | ----------------------- | ----------- | | **status** | **str** | Filter by series status | \[optional] | ### Return type [**GetSeriesResponse**](https://docs.kalshi.com/python-sdk/models/GetSeriesResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Series retrieved successfully | | **401** | Unauthorized - authentication required | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # **get\_series\_by\_ticker** > GetSeriesByTickerResponse get\_series\_by\_ticker(ticker) Get Series by Ticker Get a single series by its ticker ### Example ```python theme={null} import kalshi_python from kalshi_python.models.get_series_by_ticker_response import GetSeriesByTickerResponse from kalshi_python.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to https://external-api.kalshi.com/trade-api/v2 # See configuration.py for a list of all supported configuration parameters. configuration = kalshi_python.Configuration( host = "https://external-api.kalshi.com/trade-api/v2" ) # Read private key from file with open('path/to/private_key.pem', 'r') as f: private_key = f.read() # Configure API key authentication configuration.api_key_id = "your-api-key-id" configuration.private_key_pem = private_key # Initialize the Kalshi client client = kalshi_python.KalshiClient(configuration) ticker = 'ticker_example' # str | The series ticker try: # Get Series by Ticker api_response = client.get_series_by_ticker(ticker) print("The response of SeriesApi->get_series_by_ticker:\n") pprint(api_response) except Exception as e: print("Exception when calling SeriesApi->get_series_by_ticker: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | ----------------- | ----- | | **ticker** | **str** | The series ticker | | ### Return type [**GetSeriesByTickerResponse**](https://docs.kalshi.com/python-sdk/models/GetSeriesByTickerResponse) ### HTTP response details | Status code | Description | | ----------- | -------------------------------------- | | **200** | Series retrieved successfully | | **401** | Unauthorized - authentication required | | **404** | Resource not found | | **500** | Internal server error | [\[Back to top\]](#) [\[Back to API list\]](https://docs.kalshi.com/python-sdk/api) [\[Back to Model list\]](https://docs.kalshi.com/python-sdk/models) [\[Back to README\]](https://docs.kalshi.com/python-sdk) # StructuredTargets Source: https://docs.kalshi.com/python-sdk/api/StructuredTargetsApi Python SDK methods for StructuredTargets operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ------------------------------------------------------- | ----------------------------- | ---------------------- | | [**get\_structured\_target**](#get-structured-target) | **GET** /structured\_targets/ | Get Structured Target | | [**get\_structured\_targets**](#get-structured-targets) | **GET** /structured\_targets | Get Structured Targets | # **get\_structured\_target** > GetStructuredTargetResponse get\_structured\_target(structured\_target\_id) Get Structured Target Endpoint for getting data about a specific structured target by its ID. ### Parameters | Name | Type | Description | Notes | | -------------------------- | ------- | -------------------- | ----- | | **structured\_target\_id** | **str** | Structured target ID | | ### Return type [**GetStructuredTargetResponse**](https://docs.kalshi.com/python-sdk/models/GetStructuredTargetResponse) ### HTTP response details | Status code | Description | | ----------- | ---------------------------------------- | | **200** | Structured target retrieved successfully | | **401** | Unauthorized | | **404** | Not found | | **500** | Internal server error | # **get\_structured\_targets** > GetStructuredTargetsResponse get\_structured\_targets(ids=ids, type=type, competition=competition, page\_size=page\_size, cursor=cursor) Get Structured Targets Page size (min: 1, max: 2000) ### Parameters | Name | Type | Description | Notes | | --------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------- | | **ids** | [**List\[str\]**](https://docs.kalshi.com/python-sdk/models/str) | Filter by specific structured target IDs. Pass multiple IDs by repeating the parameter (e.g. \`?ids=uuid1\&ids=uuid2\`). | \[optional] | | **type** | **str** | Filter by structured target type | \[optional] | | **competition** | **str** | Filter by competition. Matches against the league, conference, division, or tour in the structured target details. | \[optional] | | **page\_size** | **int** | Number of items per page (min 1, max 2000, default 100) | \[optional] \[default to 100] | | **cursor** | **str** | Pagination cursor | \[optional] | ### Return type [**GetStructuredTargetsResponse**](https://docs.kalshi.com/python-sdk/models/GetStructuredTargetsResponse) ### HTTP response details | Status code | Description | | ----------- | ----------------------------------------- | | **200** | Structured targets retrieved successfully | | **401** | Unauthorized | | **500** | Internal server error | # Kalshi SDKs Source: https://docs.kalshi.com/sdks/overview Official SDKs for integrating with the Kalshi API ## Available SDKs Kalshi SDKs are updated periodically, but active traders should use the REST [OpenAPI specification](https://docs.kalshi.com/openapi.yaml), WebSocket [AsyncAPI specification](https://docs.kalshi.com/asyncapi.yaml), and the rest of the API documentation as the source of truth for maintaining their own clients. Full-featured Python SDK with async support TypeScript/JavaScript SDK for Node.js and browsers ## Versioning and Updates SDK versions are aligned with the [OpenAPI specification](https://docs.kalshi.com/openapi.yaml). New SDK releases are generally published on Tuesdays or Wednesdays each week, in advance of any corresponding API changes going live. However, release timing may vary and is not guaranteed. We recommend checking the SDK package repositories and the [API Changelog](/changelog) for the latest updates. These SDKs are intended to help developers get started quickly with the Kalshi API. For production applications, we recommend generating your own client libraries from the [OpenAPI specification](https://docs.kalshi.com/openapi.yaml) or implementing direct API integration to ensure full control over your implementation. ## Features All SDKs provide: * Full API coverage for trading, market data, and portfolio management * Authentication with RSA-PSS signing * Automatic request signing and timestamp handling * Type-safe models and responses * Error handling and retries * Comprehensive documentation and examples ## Installation ```bash Python (sync) theme={null} pip install kalshi_python_sync ``` ```bash Python (async) theme={null} pip install kalshi_python_async ``` ```bash TypeScript theme={null} npm install kalshi-typescript ``` The old `kalshi-python` package is deprecated. Please migrate to `kalshi-python-sync` or `kalshi-python-async`. ## Authentication All SDKs use the same authentication mechanism with API keys and RSA-PSS signing. You'll need: 1. An API key ID from your Kalshi account 2. A private key file for signing requests See the quickstart guide for your chosen SDK for detailed setup instructions. # Python SDK Quick Start Source: https://docs.kalshi.com/sdks/python/quickstart Get started with the Kalshi Python SDK ## Installation ```bash theme={null} pip install kalshi_python_sync ``` Or for async support: ```bash theme={null} pip install kalshi_python_async ``` The old `kalshi-python` package is deprecated. Please use `kalshi_python_sync` or `kalshi_python_async` instead. ## Quick Start ```python theme={null} from kalshi_python_sync import Configuration, KalshiClient # Configure the client config = Configuration( host="https://external-api.kalshi.com/trade-api/v2" ) # For authenticated requests # Read private key from file with open("path/to/private_key.pem", "r") as f: private_key = f.read() config.api_key_id = "your-api-key-id" config.private_key_pem = private_key # Initialize the client client = KalshiClient(config) # Make API calls balance = client.get_balance() print(f"Balance: ${balance.balance / 100:.2f}") ``` ## Source Code * PyPI (sync): [https://pypi.org/project/kalshi\_python\_sync/](https://pypi.org/project/kalshi_python_sync/) * PyPI (async): [https://pypi.org/project/kalshi\_python\_async/](https://pypi.org/project/kalshi_python_async/) # TypeScript SDK Quick Start Source: https://docs.kalshi.com/sdks/typescript/quickstart Get started with the Kalshi TypeScript SDK ## Installation ```bash theme={null} npm install kalshi-typescript ``` ## Quick Start ```typescript theme={null} import { Configuration, PortfolioApi } from 'kalshi-typescript'; // Configure the SDK const config = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: 'path/to/your/private-key.pem', // or use privateKeyPem basePath: 'https://external-api.kalshi.com/trade-api/v2' }); // Create API instance const portfolioApi = new PortfolioApi(config); // Make API calls const balance = await portfolioApi.getBalance(); console.log(`Balance: $${(balance.data.balance || 0) / 100}`); ``` ## Authentication The SDK uses RSA-PSS signing for authentication. You can provide your private key either as a file path or as a PEM string: ```typescript theme={null} // Using file path const config = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: 'path/to/private-key.pem', basePath: 'https://external-api.kalshi.com/trade-api/v2' }); // Using PEM string const config = new Configuration({ apiKey: 'your-api-key-id', privateKeyPem: '-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----', basePath: 'https://external-api.kalshi.com/trade-api/v2' }); ``` ## Source Code * NPM: [kalshi-typescript](https://www.npmjs.com/package/kalshi-typescript) # ApiKeys Source: https://docs.kalshi.com/typescript-sdk/api/ApiKeysApi TypeScript SDK methods for ApiKeys operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ------------------------------------- | ---------------------------- | ---------------- | | [**createApiKey**](#createapikey) | **POST** /api\_keys | Create API Key | | [**deleteApiKey**](#deleteapikey) | **DELETE** /api\_keys/ | Delete API Key | | [**generateApiKey**](#generateapikey) | **POST** /api\_keys/generate | Generate API Key | | [**getApiKeys**](#getapikeys) | **GET** /api\_keys | Get API Keys | # **createApiKey** > CreateApiKeyResponse createApiKey(createApiKeyRequest) Endpoint for creating a new API key with a user-provided public key. This endpoint allows users with Premier or Market Maker API usage levels to create API keys by providing their own RSA public key. The platform will use this public key to verify signatures on API requests. ### Parameters | Name | Type | Description | Notes | | ----------------------- | ----------------------- | ----------- | ----- | | **createApiKeyRequest** | **CreateApiKeyRequest** | | | ### Return type **CreateApiKeyResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ---------------------------------------- | ---------------- | | **201** | API key created successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized | - | | **403** | Forbidden - insufficient API usage level | - | | **500** | Internal server error | - | # **deleteApiKey** > deleteApiKey() Endpoint for deleting an existing API key. This endpoint permanently deletes an API key. Once deleted, the key can no longer be used for authentication. This action cannot be undone. ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | -------------------- | --------------------- | | **apiKey** | \[**string**] | API key ID to delete | defaults to undefined | ### Return type void (empty response body) ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------- | ---------------- | | **204** | API key successfully deleted | - | | **400** | Bad request - invalid API key ID | - | | **401** | Unauthorized | - | | **404** | API key not found | - | | **500** | Internal server error | - | # **generateApiKey** > GenerateApiKeyResponse generateApiKey(generateApiKeyRequest) Endpoint for generating a new API key with an automatically created key pair. This endpoint generates both a public and private RSA key pair. The public key is stored on the platform, while the private key is returned to the user and must be stored securely. The private key cannot be retrieved again. ### Parameters | Name | Type | Description | Notes | | ------------------------- | ------------------------- | ----------- | ----- | | **generateApiKeyRequest** | **GenerateApiKeyRequest** | | | ### Return type **GenerateApiKeyResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ------------------------------ | ---------------- | | **201** | API key generated successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # **getApiKeys** > GetApiKeysResponse getApiKeys() Endpoint for retrieving all API keys associated with the authenticated user. API keys allow programmatic access to the platform without requiring username/password authentication. Each key has a unique identifier and name. ### Parameters This endpoint does not have any parameters. ### Return type **GetApiKeysResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | --------------------------------------- | ---------------- | | **200** | List of API keys retrieved successfully | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # Communications Source: https://docs.kalshi.com/typescript-sdk/api/CommunicationsApi TypeScript SDK methods for Communications operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ----------------------------------------------- | --------------------------------------- | --------------------- | | [**acceptQuote**](#acceptquote) | **PUT** /communications/quotes//accept | Accept Quote | | [**confirmQuote**](#confirmquote) | **PUT** /communications/quotes//confirm | Confirm Quote | | [**createQuote**](#createquote) | **POST** /communications/quotes | Create Quote | | [**createRFQ**](#createrfq) | **POST** /communications/rfqs | Create RFQ | | [**deleteQuote**](#deletequote) | **DELETE** /communications/quotes/ | Delete Quote | | [**deleteRFQ**](#deleterfq) | **DELETE** /communications/rfqs/ | Delete RFQ | | [**getCommunicationsID**](#getcommunicationsid) | **GET** /communications/id | Get Communications ID | | [**getQuote**](#getquote) | **GET** /communications/quotes/ | Get Quote | | [**getQuotes**](#getquotes) | **GET** /communications/quotes | Get Quotes | | [**getRFQ**](#getrfq) | **GET** /communications/rfqs/ | Get RFQ | | [**getRFQs**](#getrfqs) | **GET** /communications/rfqs | Get RFQs | # **acceptQuote** > acceptQuote(acceptQuoteRequest) Endpoint for accepting a quote. This will require the quoter to confirm ### Parameters | Name | Type | Description | Notes | | ---------------------- | ---------------------- | ----------- | --------------------- | | **acceptQuoteRequest** | **AcceptQuoteRequest** | | | | **quoteId** | \[**string**] | Quote ID | defaults to undefined | ### Return type void (empty response body) ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **204** | Quote accepted successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | # **confirmQuote** > confirmQuote() Endpoint for confirming a quote. This will start a timer for order execution ### Parameters | Name | Type | Description | Notes | | ----------- | ------------- | ----------- | --------------------- | | **body** | **object** | | | | **quoteId** | \[**string**] | Quote ID | defaults to undefined | ### Return type void (empty response body) ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **204** | Quote confirmed successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | # **createQuote** > CreateQuoteResponse createQuote(createQuoteRequest) Endpoint for creating a quote in response to an RFQ ### Parameters | Name | Type | Description | Notes | | ---------------------- | ---------------------- | ----------- | ----- | | **createQuoteRequest** | **CreateQuoteRequest** | | | ### Return type **CreateQuoteResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **201** | Quote created successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **createRFQ** > CreateRFQResponse createRFQ(createRFQRequest) Endpoint for creating a new RFQ. You can have a maximum of 100 open RFQs at a time. ### Parameters | Name | Type | Description | Notes | | -------------------- | -------------------- | ----------- | ----- | | **createRFQRequest** | **CreateRFQRequest** | | | ### Return type **CreateRFQResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------------------------- | ---------------- | | **201** | RFQ created successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **409** | Conflict - resource already exists or cannot be modified | - | | **500** | Internal server error | - | # **deleteQuote** > deleteQuote() Endpoint for deleting a quote, which means it can no longer be accepted. ### Parameters | Name | Type | Description | Notes | | ----------- | ------------- | ----------- | --------------------- | | **quoteId** | \[**string**] | Quote ID | defaults to undefined | ### Return type void (empty response body) ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **204** | Quote deleted successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | # **deleteRFQ** > deleteRFQ() Endpoint for deleting an RFQ by ID ### Parameters | Name | Type | Description | Notes | | --------- | ------------- | ----------- | --------------------- | | **rfqId** | \[**string**] | RFQ ID | defaults to undefined | ### Return type void (empty response body) ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **204** | RFQ deleted successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | # **getCommunicationsID** > GetCommunicationsIDResponse getCommunicationsID() Endpoint for getting the communications ID of the logged-in user. ### Parameters This endpoint does not have any parameters. ### Return type **GetCommunicationsIDResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ---------------------------------------- | ---------------- | | **200** | Communications ID retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getQuote** > GetQuoteResponse getQuote() Endpoint for getting a particular quote ### Parameters | Name | Type | Description | Notes | | ----------- | ------------- | ----------- | --------------------- | | **quoteId** | \[**string**] | Quote ID | defaults to undefined | ### Return type **GetQuoteResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Quote retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | # **getQuotes** > GetQuotesResponse getQuotes() Endpoint for getting quotes ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | | **eventTicker** | \[**string**] | Event ticker to filter by. Only a single event ticker is supported. | (optional) defaults to undefined | | **marketTicker** | \[**string**] | Filter by market ticker | (optional) defaults to undefined | | **limit** | \[**number**] | Parameter to specify the number of results per page. Defaults to 500. | (optional) defaults to 500 | | **status** | \[**string**] | Filter quotes by status | (optional) defaults to undefined | | **quoteCreatorUserId** | \[**string**] | Filter quotes by quote creator user ID | (optional) defaults to undefined | | **userFilter** | **UserFilter** | Filter for quotes created by the authenticated user. | (optional) defaults to undefined | | **rfqUserFilter** | **UserFilter** | Filter for quotes responding to RFQs created by the authenticated user. | (optional) defaults to undefined | | **rfqCreatorUserId** | \[**string**] | Filter quotes by RFQ creator user ID | (optional) defaults to undefined | | **rfqCreatorSubtraderId** | \[**string**] | Filter quotes by RFQ creator subtrader ID (FCM members only) | (optional) defaults to undefined | | **rfqId** | \[**string**] | Filter quotes by RFQ ID | (optional) defaults to undefined | ### Return type **GetQuotesResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Quotes retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getRFQ** > GetRFQResponse getRFQ() Endpoint for getting a single RFQ by id ### Parameters | Name | Type | Description | Notes | | --------- | ------------- | ----------- | --------------------- | | **rfqId** | \[**string**] | RFQ ID | defaults to undefined | ### Return type **GetRFQResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | RFQ retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | # **getRFQs** > GetRFQsResponse getRFQs() Endpoint for getting RFQs ### Parameters | Name | Type | Description | Notes | | ----------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | | **eventTicker** | \[**string**] | Event ticker to filter by. Only a single event ticker is supported. | (optional) defaults to undefined | | **marketTicker** | \[**string**] | Filter by market ticker | (optional) defaults to undefined | | **subaccount** | \[**number**] | Subaccount number (0 for primary, 1-32 for subaccounts). If omitted, defaults to all subaccounts. | (optional) defaults to undefined | | **limit** | \[**number**] | Parameter to specify the number of results per page. Defaults to 100. | (optional) defaults to 100 | | **status** | \[**string**] | Filter RFQs by status | (optional) defaults to undefined | | **creatorUserId** | \[**string**] | Filter RFQs by creator user ID | (optional) defaults to undefined | | **userFilter** | **UserFilter** | | (optional) defaults to undefined | ### Return type **GetRFQsResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | RFQs retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # Events Source: https://docs.kalshi.com/typescript-sdk/api/EventsApi TypeScript SDK methods for Events operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ----------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------- | | [**getEvent**](#getevent) | **GET** /events/ | Get Event | | [**getEventForecastPercentilesHistory**](#geteventforecastpercentileshistory) | **GET** /series//events//forecast\_percentile\_history | Get Event Forecast Percentile History | | [**getEventMetadata**](#geteventmetadata) | **GET** /events//metadata | Get Event Metadata | | [**getEvents**](#getevents) | **GET** /events | Get Events | | [**getMarketCandlesticksByEvent**](#getmarketcandlesticksbyevent) | **GET** /series//events//candlesticks | Get Event Candlesticks | | [**getMultivariateEvents**](#getmultivariateevents) | **GET** /events/multivariate | Get Multivariate Events | # **getEvent** > GetEventResponse getEvent() Endpoint for getting data about an event by its ticker. An event represents a real-world occurrence that can be traded on, such as an election, sports game, or economic indicator release. Events contain one or more markets where users can place trades on different outcomes. All events are accessible through this endpoint, even if their associated markets are older than the historical cutoff. ### Parameters | Name | Type | Description | Notes | | --------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | | **eventTicker** | \[**string**] | Event ticker | defaults to undefined | | **withNestedMarkets** | \[**boolean**] | If true, markets are included within the event object. If false (default), markets are returned as a separate top-level field in the response. Historical markets settled before the historical cutoff will not be included. | (optional) defaults to false | ### Return type **GetEventResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ---------------------------- | ---------------- | | **200** | Event retrieved successfully | - | | **400** | Bad request | - | | **404** | Event not found | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # **getEventForecastPercentilesHistory** > GetEventForecastPercentilesHistoryResponse getEventForecastPercentilesHistory() Endpoint for getting the historical raw and formatted forecast numbers for an event at specific percentiles. ### Parameters | Name | Type | Description | Notes | | | | | ------------------ | ------------------ | --------------------------------------------------------------- | --------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------- | | **ticker** | \[**string**] | The event ticker | defaults to undefined | | | | | **seriesTicker** | \[**string**] | The series ticker | defaults to undefined | | | | | **percentiles** | **Array\** | Array of percentile values to retrieve (0-10000, max 10 values) | defaults to undefined | | | | | **startTs** | \[**number**] | Start timestamp for the range | defaults to undefined | | | | | **endTs** | \[**number**] | End timestamp for the range | defaults to undefined | | | | | **periodInterval** | \[\*\*0 | 1 | 60 | 1440\*\*]**Array\<0 \| 1 \| 60 \| 1440>** | Specifies the length of each forecast period, in minutes. 0 for 5-second intervals, or 1, 60, or 1440 for minute-based intervals. | defaults to undefined | ### Return type **GetEventForecastPercentilesHistoryResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------------------------- | ---------------- | | **200** | Event forecast percentile history retrieved successfully | - | | **400** | Bad request | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # **getEventMetadata** > GetEventMetadataResponse getEventMetadata() Endpoint for getting metadata about an event by its ticker. Returns only the metadata information for an event. ### Parameters | Name | Type | Description | Notes | | --------------- | ------------- | ------------ | --------------------- | | **eventTicker** | \[**string**] | Event ticker | defaults to undefined | ### Return type **GetEventMetadataResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ------------------------------------- | ---------------- | | **200** | Event metadata retrieved successfully | - | | **400** | Bad request | - | | **404** | Event not found | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # **getEvents** > GetEventsResponse getEvents() Get all events. This endpoint excludes multivariate events. To retrieve multivariate events, use the GET /events/multivariate endpoint. All events are accessible through this endpoint, even if their associated markets are older than the historical cutoff. ### Parameters | Name | Type | Description | Notes | | | | | --------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **limit** | \[**number**] | Parameter to specify the number of results per page. Defaults to 200. Maximum value is 200. | (optional) defaults to 200 | | | | | **cursor** | \[**string**] | Parameter to specify the pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | | | | | **withNestedMarkets** | \[**boolean**] | Parameter to specify if nested markets should be included in the response. When true, each event will include a \'markets\' field containing a list of Market objects associated with that event. Historical markets settled before the historical cutoff will not be included. | (optional) defaults to false | | | | | **withMilestones** | \[**boolean**] | If true, includes related milestones as a field alongside events. | (optional) defaults to false | | | | | **status** | \[\*\*'unopened' | 'open' | 'closed' | 'settled'\*\*]**Array\<'unopened' \| 'open' \| 'closed' \| 'settled'>** | Filter by event status. Possible values are \'unopened\', \'open\', \'closed\', \'settled\'. Leave empty to return events with any status. | (optional) defaults to undefined | | **seriesTicker** | \[**string**] | Filter by series ticker | (optional) defaults to undefined | | | | | **minCloseTs** | \[**number**] | Filter events with at least one market with close timestamp greater than this Unix timestamp (in seconds). | (optional) defaults to undefined | | | | | **minUpdatedTs** | \[**number**] | Filter events with metadata updated after this Unix timestamp (in seconds). Use this to efficiently poll for changes. | (optional) defaults to undefined | | | | ### Return type **GetEventsResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------------------------- | ---------------- | | **200** | Events retrieved successfully | - | | **400** | Bad request | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # **getMarketCandlesticksByEvent** > GetEventCandlesticksResponse getMarketCandlesticksByEvent() End-point for returning aggregated data across all markets corresponding to an event. ### Parameters | Name | Type | Description | Notes | | | | ------------------ | ------------- | ----------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------ | --------------------- | | **ticker** | \[**string**] | The event ticker | defaults to undefined | | | | **seriesTicker** | \[**string**] | The series ticker | defaults to undefined | | | | **startTs** | \[**number**] | Start timestamp for the range | defaults to undefined | | | | **endTs** | \[**number**] | End timestamp for the range | defaults to undefined | | | | **periodInterval** | \[\*\*1 | 60 | 1440\*\*]**Array\<1 \| 60 \| 1440>** | Specifies the length of each candlestick period, in minutes. Must be one minute, one hour, or one day. | defaults to undefined | ### Return type **GetEventCandlesticksResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------------------------------------- | ---------------- | | **200** | Event candlesticks retrieved successfully | - | | **400** | Bad request | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # **getMultivariateEvents** > GetMultivariateEventsResponse getMultivariateEvents() Retrieve multivariate (combo) events. These are dynamically created events from multivariate event collections. Supports filtering by series and collection ticker. ### Parameters | Name | Type | Description | Notes | | --------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **limit** | \[**number**] | Number of results per page. Defaults to 100. Maximum value is 200. | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. | (optional) defaults to undefined | | **seriesTicker** | \[**string**] | Filter by series ticker | (optional) defaults to undefined | | **collectionTicker** | \[**string**] | Filter events by collection ticker. Returns only multivariate events belonging to the specified collection. Cannot be used together with series\_ticker. | (optional) defaults to undefined | | **withNestedMarkets** | \[**boolean**] | Parameter to specify if nested markets should be included in the response. When true, each event will include a \'markets\' field containing a list of Market objects associated with that event. | (optional) defaults to false | ### Return type **GetMultivariateEventsResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ------------------------------------------ | ---------------- | | **200** | Multivariate events retrieved successfully | - | | **400** | Bad request - invalid parameters | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # Exchange Source: https://docs.kalshi.com/typescript-sdk/api/ExchangeApi TypeScript SDK methods for Exchange operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | --------------------------------------------------------- | --------------------------------------- | -------------------------- | | [**getExchangeAnnouncements**](#getexchangeannouncements) | **GET** /exchange/announcements | Get Exchange Announcements | | [**getExchangeSchedule**](#getexchangeschedule) | **GET** /exchange/schedule | Get Exchange Schedule | | [**getExchangeStatus**](#getexchangestatus) | **GET** /exchange/status | Get Exchange Status | | [**getSeriesFeeChanges**](#getseriesfeechanges) | **GET** /series/fee\_changes | Get Series Fee Changes | | [**getUserDataTimestamp**](#getuserdatatimestamp) | **GET** /exchange/user\_data\_timestamp | Get User Data Timestamp | # **getExchangeAnnouncements** > GetExchangeAnnouncementsResponse getExchangeAnnouncements() Endpoint for getting all exchange-wide announcements. ### Parameters This endpoint does not have any parameters. ### Return type **GetExchangeAnnouncementsResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | --------------------------------------------- | ---------------- | | **200** | Exchange announcements retrieved successfully | - | | **500** | Internal server error | - | # **getExchangeSchedule** > GetExchangeScheduleResponse getExchangeSchedule() Endpoint for getting the exchange schedule. ### Parameters This endpoint does not have any parameters. ### Return type **GetExchangeScheduleResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ---------------------------------------- | ---------------- | | **200** | Exchange schedule retrieved successfully | - | | **500** | Internal server error | - | # **getExchangeStatus** > ExchangeStatus getExchangeStatus() Endpoint for getting the exchange status. ### Parameters This endpoint does not have any parameters. ### Return type **ExchangeStatus** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Exchange status retrieved successfully | - | | **500** | Internal server error | - | | **503** | Service unavailable | - | | **504** | Gateway timeout | - | # **getSeriesFeeChanges** > GetSeriesFeeChangesResponse getSeriesFeeChanges() ### Parameters | Name | Type | Description | Notes | | ------------------ | -------------- | ----------- | -------------------------------- | | **seriesTicker** | \[**string**] | | (optional) defaults to undefined | | **showHistorical** | \[**boolean**] | | (optional) defaults to false | ### Return type **GetSeriesFeeChangesResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------------------------------------- | ---------------- | | **200** | Series fee changes retrieved successfully | - | | **400** | Bad request - invalid input | - | | **500** | Internal server error | - | # **getUserDataTimestamp** > GetUserDataTimestampResponse getUserDataTimestamp() There is typically a short delay before exchange events are reflected in the API endpoints. Whenever possible, combine API responses to PUT/POST/DELETE requests with websocket data to obtain the most accurate view of the exchange state. This endpoint provides an approximate indication of when the data from the following endpoints was last validated: GetBalance, GetOrder(s), GetFills, GetPositions ### Parameters This endpoint does not have any parameters. ### Return type **GetUserDataTimestampResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ------------------------------------------ | ---------------- | | **200** | User data timestamp retrieved successfully | - | | **500** | Internal server error | - | # Markets Source: https://docs.kalshi.com/typescript-sdk/api/MarketsApi TypeScript SDK methods for Markets operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | --------------------------------------------------- | -------------------------------------- | ----------------------- | | [**getMarket**](#getmarket) | **GET** /markets/ | Get Market | | [**getMarketCandlesticks**](#getmarketcandlesticks) | **GET** /series//markets//candlesticks | Get Market Candlesticks | | [**getMarketOrderbook**](#getmarketorderbook) | **GET** /markets//orderbook | Get Market Orderbook | | [**getMarkets**](#getmarkets) | **GET** /markets | Get Markets | | [**getTrades**](#gettrades) | **GET** /markets/trades | Get Trades | # **getMarket** > GetMarketResponse getMarket() Get a single market by its ticker. A market represents a specific binary outcome within an event that users can trade on (e.g., "Will candidate X win?"). Markets have yes/no positions, current prices, volume, and settlement rules. ### Example ```typescript theme={null} import { MarketsApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MarketsApi(configuration); let ticker: string; //Market ticker (default to undefined) const { status, data } = await apiInstance.getMarket( ticker ); ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | ------------- | --------------------- | | **ticker** | \[**string**] | Market ticker | defaults to undefined | ### Return type **GetMarketResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Market retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # **getMarketCandlesticks** > GetMarketCandlesticksResponse getMarketCandlesticks() Get candlestick data for a market within a series ### Example ```typescript theme={null} import { MarketsApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MarketsApi(configuration); let ticker: string; //The series ticker (default to undefined) let marketTicker: string; //The market ticker (default to undefined) let startTs: number; //Start timestamp for the range (optional) (default to undefined) let endTs: number; //End timestamp for the range (optional) (default to undefined) let periodInterval: string; //Period interval for candlesticks (e.g., 1m, 5m, 1h, 1d) (optional) (default to undefined) const { status, data } = await apiInstance.getMarketCandlesticks( ticker, marketTicker, startTs, endTs, periodInterval ); ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------------- | ------------------------------------------------------- | -------------------------------- | | **ticker** | \[**string**] | The series ticker | defaults to undefined | | **marketTicker** | \[**string**] | The market ticker | defaults to undefined | | **startTs** | \[**number**] | Start timestamp for the range | (optional) defaults to undefined | | **endTs** | \[**number**] | End timestamp for the range | (optional) defaults to undefined | | **periodInterval** | \[**string**] | Period interval for candlesticks (e.g., 1m, 5m, 1h, 1d) | (optional) defaults to undefined | ### Return type **GetMarketCandlesticksResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Candlesticks retrieved successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # **getMarketOrderbook** > GetMarketOrderbookResponse getMarketOrderbook() Get the orderbook for a market ### Example ```typescript theme={null} import { MarketsApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MarketsApi(configuration); let ticker: string; //Market ticker (default to undefined) let depth: number; //Depth of the orderbook to retrieve (optional) (default to 10) const { status, data } = await apiInstance.getMarketOrderbook( ticker, depth ); ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | ---------------------------------- | ------------------------- | | **ticker** | \[**string**] | Market ticker | defaults to undefined | | **depth** | \[**number**] | Depth of the orderbook to retrieve | (optional) defaults to 10 | ### Return type **GetMarketOrderbookResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Orderbook retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # **getMarkets** > GetMarketsResponse getMarkets() List and discover markets on Kalshi. A market represents a specific binary outcome within an event that users can trade on (e.g., "Will candidate X win?"). Markets have yes/no positions, current prices, volume, and settlement rules. This endpoint returns a paginated response. Use the 'limit' parameter to control page size (1-1000, defaults to 100). The response includes a 'cursor' field - pass this value in the 'cursor' parameter of your next request to get the next page. An empty cursor indicates no more pages are available. ### Example ```typescript theme={null} import { MarketsApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MarketsApi(configuration); let limit: number; //Number of results per page. Defaults to 100. Maximum value is 1000. (optional) (default to 100) let cursor: string; //Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. (optional) (default to undefined) let eventTicker: string; //Filter by event ticker (optional) (default to undefined) let seriesTicker: string; //Filter by series ticker (optional) (default to undefined) let maxCloseTs: number; //Filter items that close before this Unix timestamp (optional) (default to undefined) let minCloseTs: number; //Filter items that close after this Unix timestamp (optional) (default to undefined) let status: string; //Filter by market status. Comma-separated list. Possible values are \'initialized\', \'open\', \'closed\', \'settled\', \'determined\'. Note that the API accepts \'open\' for filtering but returns \'active\' in the response. Leave empty to return markets with any status. (optional) (default to undefined) let tickers: string; //Filter by specific market tickers. Comma-separated list of market tickers to retrieve. (optional) (default to undefined) const { status, data } = await apiInstance.getMarkets( limit, cursor, eventTicker, seriesTicker, maxCloseTs, minCloseTs, status, tickers ); ``` ### Parameters | Name | Type | Description | Notes | | ---------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **limit** | \[**number**] | Number of results per page. Defaults to 100. Maximum value is 1000. | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | | **eventTicker** | \[**string**] | Filter by event ticker | (optional) defaults to undefined | | **seriesTicker** | \[**string**] | Filter by series ticker | (optional) defaults to undefined | | **maxCloseTs** | \[**number**] | Filter items that close before this Unix timestamp | (optional) defaults to undefined | | **minCloseTs** | \[**number**] | Filter items that close after this Unix timestamp | (optional) defaults to undefined | | **status** | \[**string**] | Filter by market status. Comma-separated list. Possible values are \'initialized\', \'open\', \'closed\', \'settled\', \'determined\'. Note that the API accepts \'open\' for filtering but returns \'active\' in the response. Leave empty to return markets with any status. | (optional) defaults to undefined | | **tickers** | \[**string**] | Filter by specific market tickers. Comma-separated list of market tickers to retrieve. | (optional) defaults to undefined | ### Return type **GetMarketsResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Markets retrieved successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # **getTrades** > GetTradesResponse getTrades() Get all trades for all markets. A trade represents a completed transaction between two users on a specific market. Each trade includes the market ticker, price, quantity, and timestamp information. This endpoint returns a paginated response. Use the 'limit' parameter to control page size (1-1000, defaults to 100). The response includes a 'cursor' field - pass this value in the 'cursor' parameter of your next request to get the next page. An empty cursor indicates no more pages are available. ### Example ```typescript theme={null} import { MarketsApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MarketsApi(configuration); let limit: number; //Number of results per page. Defaults to 100. Maximum value is 1000. (optional) (default to 100) let cursor: string; //Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. (optional) (default to undefined) let ticker: string; //Filter by market ticker (optional) (default to undefined) let minTs: number; //Filter items after this Unix timestamp (optional) (default to undefined) let maxTs: number; //Filter items before this Unix timestamp (optional) (default to undefined) const { status, data } = await apiInstance.getTrades( limit, cursor, ticker, minTs, maxTs ); ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **limit** | \[**number**] | Number of results per page. Defaults to 100. Maximum value is 1000. | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | | **ticker** | \[**string**] | Filter by market ticker | (optional) defaults to undefined | | **minTs** | \[**number**] | Filter items after this Unix timestamp | (optional) defaults to undefined | | **maxTs** | \[**number**] | Filter items before this Unix timestamp | (optional) defaults to undefined | ### Return type **GetTradesResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------------------------- | ---------------- | | **200** | Trades retrieved successfully | - | | **400** | Bad request - invalid input | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # Milestones Source: https://docs.kalshi.com/typescript-sdk/api/MilestonesApi TypeScript SDK methods for Milestones operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ----------------------------------- | -------------------- | -------------- | | [**getMilestone**](#getmilestone) | **GET** /milestones/ | Get Milestone | | [**getMilestones**](#getmilestones) | **GET** /milestones | Get Milestones | # **getMilestone** > GetMilestoneResponse getMilestone() Get a single milestone by ID ### Example ```typescript theme={null} import { MilestonesApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MilestonesApi(configuration); let milestoneId: string; //Milestone ID (default to undefined) const { status, data } = await apiInstance.getMilestone( milestoneId ); ``` ### Parameters | Name | Type | Description | Notes | | --------------- | ------------- | ------------ | --------------------- | | **milestoneId** | \[**string**] | Milestone ID | defaults to undefined | ### Return type **GetMilestoneResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Milestone retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # **getMilestones** > GetMilestonesResponse getMilestones() Get all milestones ### Example ```typescript theme={null} import { MilestonesApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MilestonesApi(configuration); let status: string; //Filter by milestone status (optional) (default to undefined) let limit: number; //Number of items per page (minimum 1, maximum 500) (optional) (default to 100) const { status, data } = await apiInstance.getMilestones( status, limit ); ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | ------------------------------------------------- | -------------------------------- | | **status** | \[**string**] | Filter by milestone status | (optional) defaults to undefined | | **limit** | \[**number**] | Number of items per page (minimum 1, maximum 500) | (optional) defaults to 100 | ### Return type **GetMilestonesResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Milestones retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # MultivariateCollections Source: https://docs.kalshi.com/typescript-sdk/api/MultivariateCollectionsApi TypeScript SDK methods for MultivariateCollections operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | --------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------- | | [**getMultivariateEventCollection**](#getmultivariateeventcollection) | **GET** /multivariate\_event\_collections/ | Get Multivariate Event Collection | | [**getMultivariateEventCollections**](#getmultivariateeventcollections) | **GET** /multivariate\_event\_collections | Get Multivariate Event Collections | | [**lookupMultivariateEventCollectionBundle**](#lookupmultivariateeventcollectionbundle) | **POST** /multivariate\_event\_collections//lookup | Lookup Multivariate Event Collection Bundle | # **getMultivariateEventCollection** > GetMultivariateEventCollectionResponse getMultivariateEventCollection() Get a single multivariate event collection by ticker ### Example ```typescript theme={null} import { MultivariateCollectionsApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MultivariateCollectionsApi(configuration); let collectionTicker: string; //Collection ticker (default to undefined) const { status, data } = await apiInstance.getMultivariateEventCollection( collectionTicker ); ``` ### Parameters | Name | Type | Description | Notes | | -------------------- | ------------- | ----------------- | --------------------- | | **collectionTicker** | \[**string**] | Collection ticker | defaults to undefined | ### Return type **GetMultivariateEventCollectionResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Collection retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # **getMultivariateEventCollections** > GetMultivariateEventCollectionsResponse getMultivariateEventCollections() Get all multivariate event collections ### Example ```typescript theme={null} import { MultivariateCollectionsApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MultivariateCollectionsApi(configuration); let status: string; //Filter by multivariate collection status (optional) (default to undefined) const { status, data } = await apiInstance.getMultivariateEventCollections( status ); ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | ---------------------------------------- | -------------------------------- | | **status** | \[**string**] | Filter by multivariate collection status | (optional) defaults to undefined | ### Return type **GetMultivariateEventCollectionsResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Collections retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # **lookupMultivariateEventCollectionBundle** > LookupBundleResponse lookupMultivariateEventCollectionBundle(lookupBundleRequest) Lookup a bundle in a multivariate event collection ### Example ```typescript theme={null} import { MultivariateCollectionsApi, Configuration, LookupBundleRequest } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new MultivariateCollectionsApi(configuration); let collectionTicker: string; //Collection ticker (default to undefined) let lookupBundleRequest: LookupBundleRequest; // const { status, data } = await apiInstance.lookupMultivariateEventCollectionBundle( collectionTicker, lookupBundleRequest ); ``` ### Parameters | Name | Type | Description | Notes | | ----------------------- | ----------------------- | ----------------- | --------------------- | | **lookupBundleRequest** | **LookupBundleRequest** | | | | **collectionTicker** | \[**string**] | Collection ticker | defaults to undefined | ### Return type **LookupBundleResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Bundle lookup successful | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # Portfolio Source: https://docs.kalshi.com/typescript-sdk/api/PortfolioApi TypeScript SDK methods for Portfolio operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ----------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------- | | [**applySubaccountTransfer**](#applysubaccounttransfer) | **POST** /portfolio/subaccounts/transfer | Transfer Between Subaccounts | | [**createSubaccount**](#createsubaccount) | **POST** /portfolio/subaccounts | Create Subaccount | | [**getBalance**](#getbalance) | **GET** /portfolio/balance | Get Balance | | [**getDeposits**](#getdeposits) | **GET** /portfolio/deposits | Get Deposits | | [**getFills**](#getfills) | **GET** /portfolio/fills | Get Fills | | [**getPortfolioRestingOrderTotalValue**](#getportfoliorestingordertotalvalue) | **GET** /portfolio/summary/total\_resting\_order\_value | Get Total Resting Order Value | | [**getPositions**](#getpositions) | **GET** /portfolio/positions | Get Positions | | [**getSettlements**](#getsettlements) | **GET** /portfolio/settlements | Get Settlements | | [**getSubaccountBalances**](#getsubaccountbalances) | **GET** /portfolio/subaccounts/balances | Get All Subaccount Balances | | [**getSubaccountNetting**](#getsubaccountnetting) | **GET** /portfolio/subaccounts/netting | Get Subaccount Netting | | [**getSubaccountTransfers**](#getsubaccounttransfers) | **GET** /portfolio/subaccounts/transfers | Get Subaccount Transfers | | [**getWithdrawals**](#getwithdrawals) | **GET** /portfolio/withdrawals | Get Withdrawals | | [**updateSubaccountNetting**](#updatesubaccountnetting) | **PUT** /portfolio/subaccounts/netting | Update Subaccount Netting | # **applySubaccountTransfer** > object applySubaccountTransfer(applySubaccountTransferRequest) Transfers funds between the authenticated user's subaccounts. Use 0 for the primary account, or 1-32 for numbered subaccounts. ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------- | ----------- | ----- | | **applySubaccountTransferRequest** | **ApplySubaccountTransferRequest** | | | ### Return type **object** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Transfer completed successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **createSubaccount** > CreateSubaccountResponse createSubaccount() Creates a new subaccount for the authenticated user. This endpoint is currently only available to institutions and market makers. Subaccounts are numbered sequentially starting from 1. Maximum 32 subaccounts per user. ### Parameters This endpoint does not have any parameters. ### Return type **CreateSubaccountResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **201** | Subaccount created successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getBalance** > GetBalanceResponse getBalance() Endpoint for getting the balance and portfolio value of a member. Both values are returned in cents. ### Parameters | Name | Type | Description | Notes | | -------------- | ------------- | ----------------------------------------------------------------------- | -------------------------------- | | **subaccount** | \[**number**] | Subaccount number (0 for primary, 1-32 for subaccounts). Defaults to 0. | (optional) defaults to undefined | ### Return type **GetBalanceResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Balance retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getDeposits** > GetDepositsResponse getDeposits() Endpoint for getting the member's deposit history. ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **limit** | \[**number**] | Number of results per page. Defaults to 100. Maximum value is 500. | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | ### Return type **GetDepositsResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Deposits retrieved successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getFills** > GetFillsResponse getFills() Endpoint for getting all fills for the member. A fill is when a trade you have is matched. Fills that occurred before the historical cutoff are only available via `GET /historical/fills`. See [Historical Data](https://docs.kalshi.com/getting_started/historical_data) for details. ### Parameters | Name | Type | Description | Notes | | -------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **ticker** | \[**string**] | Filter by market ticker | (optional) defaults to undefined | | **orderId** | \[**string**] | Filter by order ID | (optional) defaults to undefined | | **minTs** | \[**number**] | Filter items after this Unix timestamp | (optional) defaults to undefined | | **maxTs** | \[**number**] | Filter items before this Unix timestamp | (optional) defaults to undefined | | **limit** | \[**number**] | Number of results per page. Defaults to 100. | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | | **subaccount** | \[**number**] | Subaccount number (0 for primary, 1-32 for subaccounts). If omitted, defaults to all subaccounts. | (optional) defaults to undefined | ### Return type **GetFillsResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ---------------------------- | ---------------- | | **200** | Fills retrieved successfully | - | | **400** | Bad request | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # **getPortfolioRestingOrderTotalValue** > GetPortfolioRestingOrderTotalValueResponse getPortfolioRestingOrderTotalValue() Endpoint for getting the total value, in cents, of resting orders. This endpoint is only intended for use by FCM members (rare). Note: If you're uncertain about this endpoint, it likely does not apply to you. ### Parameters This endpoint does not have any parameters. ### Return type **GetPortfolioRestingOrderTotalValueResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ------------------------------------------------ | ---------------- | | **200** | Total resting order value retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getPositions** > GetPositionsResponse getPositions() Restricts the positions to those with any of following fields with non-zero values, as a comma separated list. The following values are accepted: position, total\_traded ### Parameters | Name | Type | Description | Notes | | --------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **cursor** | \[**string**] | The Cursor represents a pointer to the next page of records in the pagination. Use the value returned from the previous response to get the next page. | (optional) defaults to undefined | | **limit** | \[**number**] | Parameter to specify the number of results per page. Defaults to 100. | (optional) defaults to 100 | | **countFilter** | \[**string**] | Restricts the positions to those with any of following fields with non-zero values, as a comma separated list. The following values are accepted - position, total\_traded | (optional) defaults to undefined | | **ticker** | \[**string**] | Filter by market ticker | (optional) defaults to undefined | | **eventTicker** | \[**string**] | Event ticker to filter by. Only a single event ticker is supported. | (optional) defaults to undefined | | **subaccount** | \[**number**] | Subaccount number (0 for primary, 1-32 for subaccounts). Defaults to 0. | (optional) defaults to undefined | ### Return type **GetPositionsResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Positions retrieved successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getSettlements** > GetSettlementsResponse getSettlements() Endpoint for getting the member's settlements historical track. ### Parameters | Name | Type | Description | Notes | | --------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **limit** | \[**number**] | Number of results per page. Defaults to 100. | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | | **ticker** | \[**string**] | Filter by market ticker | (optional) defaults to undefined | | **eventTicker** | \[**string**] | Event ticker to filter by. Only a single event ticker is supported. | (optional) defaults to undefined | | **minTs** | \[**number**] | Filter items after this Unix timestamp | (optional) defaults to undefined | | **maxTs** | \[**number**] | Filter items before this Unix timestamp | (optional) defaults to undefined | | **subaccount** | \[**number**] | Subaccount number (0 for primary, 1-32 for subaccounts). If omitted, defaults to all subaccounts. | (optional) defaults to undefined | ### Return type **GetSettlementsResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Settlements retrieved successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getSubaccountBalances** > GetSubaccountBalancesResponse getSubaccountBalances() Gets balances for all subaccounts including the primary account. ### Parameters This endpoint does not have any parameters. ### Return type **GetSubaccountBalancesResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Balances retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getSubaccountNetting** > GetSubaccountNettingResponse getSubaccountNetting() Gets the netting enabled settings for all subaccounts. ### Parameters This endpoint does not have any parameters. ### Return type **GetSubaccountNettingResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | --------------------------------------- | ---------------- | | **200** | Netting settings retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getSubaccountTransfers** > GetSubaccountTransfersResponse getSubaccountTransfers() Gets a paginated list of all transfers between subaccounts for the authenticated user. ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **limit** | \[**number**] | Number of results per page. Defaults to 100. | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | ### Return type **GetSubaccountTransfersResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Transfers retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **getWithdrawals** > GetWithdrawalsResponse getWithdrawals() Endpoint for getting the member's withdrawal history. ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | | **limit** | \[**number**] | Number of results per page. Defaults to 100. Maximum value is 500. | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor. Use the cursor value returned from the previous response to get the next page of results. Leave empty for the first page. | (optional) defaults to undefined | ### Return type **GetWithdrawalsResponse** ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Withdrawals retrieved successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # **updateSubaccountNetting** > updateSubaccountNetting(updateSubaccountNettingRequest) Updates the netting enabled setting for a specific subaccount. Use 0 for the primary account, or 1-32 for numbered subaccounts. ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------- | ----------- | ----- | | **updateSubaccountNettingRequest** | **UpdateSubaccountNettingRequest** | | | ### Return type void (empty response body) ### Authorization [kalshiAccessSignature](../README.md#kalshiAccessSignature), [kalshiAccessKey](../README.md#kalshiAccessKey), [kalshiAccessTimestamp](../README.md#kalshiAccessTimestamp) ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Netting setting updated successfully | - | | **400** | Bad request - invalid input | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | # Series Source: https://docs.kalshi.com/typescript-sdk/api/SeriesApi TypeScript SDK methods for Series operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ------------------------------------------- | ---------------- | -------------------- | | [**getSeries**](#getseries) | **GET** /series | Get Series | | [**getSeriesByTicker**](#getseriesbyticker) | **GET** /series/ | Get Series by Ticker | # **getSeries** > GetSeriesResponse getSeries() Get all market series ### Example ```typescript theme={null} import { SeriesApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new SeriesApi(configuration); let status: string; //Filter by series status (optional) (default to undefined) const { status, data } = await apiInstance.getSeries( status ); ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | ----------------------- | -------------------------------- | | **status** | \[**string**] | Filter by series status | (optional) defaults to undefined | ### Return type **GetSeriesResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Series retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # **getSeriesByTicker** > GetSeriesByTickerResponse getSeriesByTicker() Get a single series by its ticker ### Example ```typescript theme={null} import { SeriesApi, Configuration } from 'kalshi-typescript'; const configuration = new Configuration({ apiKey: 'your-api-key-id', privateKeyPath: '/path/to/private-key.pem' // or privateKeyPem: 'PEM string' }); const apiInstance = new SeriesApi(configuration); let ticker: string; //The series ticker (default to undefined) const { status, data } = await apiInstance.getSeriesByTicker( ticker ); ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------------- | ----------------- | --------------------- | | **ticker** | \[**string**] | The series ticker | defaults to undefined | ### Return type **GetSeriesByTickerResponse** ### Authorization [bearerAuth](../README.md#bearerAuth) ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | -------------------------------------- | ---------------- | | **200** | Series retrieved successfully | - | | **401** | Unauthorized - authentication required | - | | **404** | Resource not found | - | | **500** | Internal server error | - | [\[Back to top\]](#) [\[Back to API list\]](../README.md#documentation-for-api-endpoints) [\[Back to Model list\]](../README.md#documentation-for-models) [\[Back to README\]](../README.md) # StructuredTargets Source: https://docs.kalshi.com/typescript-sdk/api/StructuredTargetsApi TypeScript SDK methods for StructuredTargets operations All URIs are relative to *[https://external-api.kalshi.com/trade-api/v2](https://external-api.kalshi.com/trade-api/v2)* | Method | HTTP request | Description | | ------------------------------------------------- | ----------------------------- | ---------------------- | | [**getStructuredTarget**](#getstructuredtarget) | **GET** /structured\_targets/ | Get Structured Target | | [**getStructuredTargets**](#getstructuredtargets) | **GET** /structured\_targets | Get Structured Targets | # **getStructuredTarget** > GetStructuredTargetResponse getStructuredTarget() Endpoint for getting data about a specific structured target by its ID. ### Parameters | Name | Type | Description | Notes | | ---------------------- | ------------- | -------------------- | --------------------- | | **structuredTargetId** | \[**string**] | Structured target ID | defaults to undefined | ### Return type **GetStructuredTargetResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ---------------------------------------- | ---------------- | | **200** | Structured target retrieved successfully | - | | **401** | Unauthorized | - | | **404** | Not found | - | | **500** | Internal server error | - | # **getStructuredTargets** > GetStructuredTargetsResponse getStructuredTargets() Page size (min: 1, max: 2000) ### Parameters | Name | Type | Description | Notes | | --------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------ | -------------------------------- | | **ids** | **Array\** | Filter by specific structured target IDs. Pass multiple IDs by repeating the parameter (e.g. \`?ids=uuid1\&ids=uuid2\`). | (optional) defaults to undefined | | **type** | \[**string**] | Filter by structured target type | (optional) defaults to undefined | | **competition** | \[**string**] | Filter by competition. Matches against the league, conference, division, or tour in the structured target details. | (optional) defaults to undefined | | **pageSize** | \[**number**] | Number of items per page (min 1, max 2000, default 100) | (optional) defaults to 100 | | **cursor** | \[**string**] | Pagination cursor | (optional) defaults to undefined | ### Return type **GetStructuredTargetsResponse** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------------------------------------- | ---------------- | | **200** | Structured targets retrieved successfully | - | | **401** | Unauthorized | - | | **500** | Internal server error | - | # Communications Source: https://docs.kalshi.com/websockets/communications Real-time Request for Quote (RFQ) and quote notifications. Requires authentication. **Requirements:** - Authentication required - Market specification ignored - Optional sharding for fanout control: - `shard_factor` (1-100) and `shard_key` (0 <= key < shard_factor) - RFQ events (RFQCreated, RFQDeleted) always sent - Quote events (QuoteCreated, QuoteAccepted, QuoteExecuted) are only sent if you created the quote OR you created the RFQ **Use case:** Tracking RFQs you create and quotes on your RFQs, or quotes you create on others' RFQs. Use QuoteExecuted to correlate fill messages with quotes via client_order_id. # Connection Keep-Alive Source: https://docs.kalshi.com/websockets/connection-keep-alive WebSocket control frames for connection management. Kalshi sends Ping frames (`0x9`) every 10 seconds with body `heartbeat` to maintain the connection. Clients should respond with Pong frames (`0xA`). Clients may also send Ping frames to which Kalshi will respond with Pong. # Market & Event Lifecycle Source: https://docs.kalshi.com/websockets/market-&-event-lifecycle Market state changes and event creation notifications. **Requirements:** - No additional channel-level authentication beyond the authenticated WebSocket connection - Receives all market and event lifecycle notifications (`market_ticker` filters are not supported) - Event creation notifications **Use case:** Tracking market lifecycle including creation, de(activation), close date changes, determination, settlement, price level structure changes, and metadata updates # Market Positions Source: https://docs.kalshi.com/websockets/market-positions Real-time updates of your positions in markets. Requires authentication. **Requirements:** - Authentication required - Market specification optional (omit to receive all positions) - Filters are by `market_ticker`/`market_tickers` only; `market_id`/`market_ids` are not supported - Updates sent when your position changes due to trades, settlements, etc. **Monetary Values:** All monetary values are returned as fixed-point dollar strings (`_dollars` suffix). **Use case:** Portfolio tracking, position monitoring, P&L calculations # Market Ticker Source: https://docs.kalshi.com/websockets/market-ticker Market price, volume, and open interest updates. **Requirements:** - No additional channel-level authentication beyond the authenticated WebSocket connection - Market specification optional (omit to receive all markets) - Supports `market_ticker`/`market_tickers` and `market_id`/`market_ids` - Updates sent whenever any ticker field changes **Use case:** Displaying current market prices and statistics # Multivariate Lookups (Deprecated) Source: https://docs.kalshi.com/websockets/multivariate-lookups-deprecated Deprecated: this channel predates RFQs and should not be used for new integrations. Multivariate collection lookup notifications. **Requirements:** - No additional channel-level authentication beyond the authenticated WebSocket connection - No filtering parameters; subscription is global **Use case:** Tracking multivariate lookup interest for legacy integrations # Multivariate Market & Event Lifecycle Source: https://docs.kalshi.com/websockets/multivariate-market-&-event-lifecycle Multivariate event (MVE) market state changes and event creation notifications. **Requirements:** - No additional channel-level authentication beyond the authenticated WebSocket connection - Receives all multivariate market lifecycle notifications (`market_ticker` filters are not supported) - Only emits lifecycle updates for multivariate events - Event creation notifications **Use case:** Tracking multivariate market lifecycle including creation, de(activation), close date changes, determination, settlement # Order Group Updates Source: https://docs.kalshi.com/websockets/order-group-updates Real-time order group lifecycle and limit updates. Requires authentication. **Requirements:** - Authentication required - Market specification ignored - Updates sent when order groups are created, triggered, reset, deleted, or have limits updated **Use case:** Tracking order group lifecycle and limits # Orderbook Updates Source: https://docs.kalshi.com/websockets/orderbook-updates Real-time orderbook price level changes. Provides incremental updates to maintain a live orderbook. **Requirements:** - Authentication required - Market specification required: - Use `market_ticker` (string) for a single market - Use `market_tickers` (array of strings) for multiple markets - `market_id`/`market_ids` are not supported for this channel - Sends `orderbook_snapshot` first, then incremental `orderbook_delta` updates - Supports `update_subscription` with `add_markets` / `delete_markets` / `get_snapshot` actions - `get_snapshot` returns an `orderbook_snapshot` for the requested `market_tickers` without modifying the subscription **Use case:** Building and maintaining a real-time orderbook # Public Trades Source: https://docs.kalshi.com/websockets/public-trades Public trade notifications when trades occur. **Requirements:** - No additional channel-level authentication beyond the authenticated WebSocket connection - Market specification optional (omit to receive all trades) - Updates sent immediately after trade execution **Use case:** Trade feed, volume analysis # User Fills Source: https://docs.kalshi.com/websockets/user-fills Your order fill notifications. Requires authentication. **Requirements:** - Authentication required - Market specification optional via `market_ticker`/`market_tickers` (omit to receive all your fills) - Supports `update_subscription` with `add_markets` / `delete_markets` - Updates sent immediately when your orders are filled **Use case:** Tracking your trading activity # User Orders Source: https://docs.kalshi.com/websockets/user-orders Real-time order created and updated notifications. Requires authentication. **Requirements:** - Authentication required - Market specification optional via `market_tickers` (omit to receive all orders) - Supports `update_subscription` with `add_markets` / `delete_markets` actions - Updates sent when your orders are created, filled, canceled, or otherwise updated **Use case:** Tracking your resting orders, fills, and cancellations in real time # WebSocket Connection Source: https://docs.kalshi.com/websockets/websocket-connection Main WebSocket connection endpoint. All communication happens through this single connection. Authentication is required to establish the connection; include API key headers during the WebSocket handshake. Some channels carry only public market data, but the connection itself still requires authentication. Use the subscribe command to subscribe to specific data channels. For more information, see the [Getting Started](https://docs.kalshi.com/getting_started/quick_start_websockets) guide. # Introduction Source: https://docs.kalshi.com/welcome/index Welcome to the Kalshi API documentation
Make your first API call and start trading on Kalshi. Test your integration in our safe demo environment. Learn how to generate and manage your API credentials. Quick start guide for accessing market data. Learn about real-time data streaming via WebSockets. Explore our complete API documentation. Download the OpenAPI specification for API integration. Download the AsyncAPI specification for WebSocket integration. Understand API rate limits and best practices. Learn key terms and concepts used in the Kalshi exchange. Stay updated with the latest API changes. Explore educational resources and tutorials.