Releases: TexasCoding/kalshi-python-sdk
Release list
v7.0.0
Syncs the upstream OpenAPI/AsyncAPI specs 3.23.0 → 3.24.0 (Closes #467, #470).
One breaking rename on the subaccounts surface, a soft-deprecation, three new
endpoints, and additive drift fixes. Kalshi changed spec content without always
bumping info.version, so this also absorbs in-place edits made under the same string.
Changed (breaking)
- Position-transfer price is now fixed-point dollars, not integer cents. The
price_centsfield/kwarg (integer cents, 0-100) on
ApplySubaccountPositionTransferRequest,SubaccountTransfer, and
subaccounts.transfer_position()(sync + async) is renamedpriceand
typedOrderPrice/DollarDecimal(fixed-point dollars,Decimal). Pass
price=Decimal("0.50")where you previously passedprice_cents=50. The old
client-side cap (le=100cents) is gone —OrderPriceguards only
non-negativity and the$0.0001tick, leaving the upper bound to the server
(matchesCreateOrderRequest). Upstream renamed the wire fieldprice_cents
→price(FixedPointDollars) in 3.24.0.
Deprecated
exchange.announcements()(sync + async) now emits aDeprecationWarning.
Kalshi removedGET /exchange/announcementsand theAnnouncementschema from
the spec in 3.24.0, so the live endpoint 404s. The method and theAnnouncement
model are retained (soft-deprecated) pending confirmation the removal is
permanent — upstream has transiently dropped endpoints as publishing glitches
before (see #452). A future major release removes them once confirmed.
Added
communications.quotes.get_for_rfq(rfq_id, quote_id)(sync + async) —
GET /communications/rfqs/{rfq_id}/quotes/{quote_id}, the RFQ-scoped
get-a-quote (returnsGetQuoteResponse, the same payload as the flat
quotes.get).klear.margin.active_obligations()(sync + async) —
GET /margin/active_obligations, all currently-active settlement obligations
(GetActiveMarginObligationsResponse; the plural sibling of the single-obligation
active_obligation()).klear.margin.settlement_estimate_by_asset_class()(sync + async) —
GET /margin/settlement_estimate_by_asset_class, next-settlement estimates keyed
by asset class (GetSettlementEstimateByAssetClassResponse+
AssetClassSettlementEstimate).SubaccountNettingConfig.exchange_index(int, required) — exchange index
of the subaccount.portfolio.balance()(sync + async) gains an optionalexchange_index
query param — target a specific exchange shard (defaults to 0 server-side).ObligationEntry.asset_class(perps SCM / Klear;AssetClassLiteral=
Literal["Crypto"], required) — asset class of the settlement obligation.
v6.0.0
Syncs the upstream OpenAPI/AsyncAPI specs 3.22.0 → 3.23.0 (#463). The
headline change is breaking: Kalshi removed the multivariate lookup-history
endpoint from the spec, so the SDK removes the corresponding method and model.
Every other change is additive and backward-compatible.
Removed (breaking)
lookup_history()onclient.multivariate_collections(sync + async) and
theLookupPointmodel (no longer exported fromkalshi/
kalshi.models). Upstream removed the backingGET /multivariate_event_collections/{collection_ticker}/lookupoperation
(GetMultivariateEventCollectionLookupHistory) and theLookupPointschema in
3.23.0 — the endpoint now 404s. Thelookup_tickers()sibling (thePUTon the
same path) is unaffected.
Added
ApiKey.subaccount,CreateApiKeyRequest.subaccount,
GenerateApiKeyRequest.subaccount(int | None) — when set, restricts the
API key to a single subaccount.api_keys.create()/generate()(sync +
async) accept asubaccountkwarg that threads into the body. The request
models bound it to the spec's0-63range (ge=0, le=63) client-side; the
response model stays permissive.ApplySubaccountTransferRequest.exchange_index(int | None) — exchange
shard to apply the transfer on (specExchangeIndex; defaults to 0).SubaccountTransferadditive fields:exchange_indexandtransfer_type
("cash"/"position", both required), plus the position-transfer-only
market_ticker/side("yes"/"no") /count/price_cents.MarginPosition.is_portfolioandMarginRiskPosition.is_portfolio
(bool, required) — true when the position is hedged within a portfolio.MarginOrder.order_reason("liquidation"/"take_profit_stop_loss",
optional) — reason for a system-generated order.MarketLifecyclePayload.price_ranges(WSmarket_lifecycle_v2) — valid
price bands emitted alongsideprice_level_structure.subaccounts.transfer_position(...)(sync + async) — new
POST /portfolio/subaccounts/positions/transferendpoint (spec 3.23.0): moves
an open position (contracts) between subaccounts, distinct from the
cash-onlytransfer(). ReturnsApplySubaccountPositionTransferResponse
(position_transfer_id). New modelsApplySubaccountPositionTransferRequest/
ApplySubaccountPositionTransferResponseare exported fromkalshi/
kalshi.models.subaccounts.create(exchange_index=...)—POST /portfolio/subaccounts
gained an optionalCreateSubaccountRequestbody (spec 3.23.0);create()
now accepts an optionalexchange_indexto target a specific exchange shard.
NewCreateSubaccountRequestmodel exported fromkalshi/kalshi.models.
Fixed
- Defensive optional-ization of fields 3.23.0 removed/relaxed. The drift
suite is spec→SDK only, so a field the spec drops but the SDK still requires
is a latentValidationErrorif the server stops emitting it. Three such
fields are now... | None = None:Market.fractional_trading_enabled(removed from spec),MarketPosition.resting_orders_count(removed from spec),MarginPosition.margin_used(relaxed from required to optional).
v5.0.1
Spec-drift catch-up (#460). Kalshi added fields to the ExchangeStatus schema
in place — without bumping the OpenAPI version (still 3.22.0) — so the
nightly strict contract suite flagged additive drift the day after the 5.0.0
sync. All changes are additive and backward-compatible.
Fixed
ExchangeStatusadditive drift. Added two optional fields that upstream
introduced onGET /exchange/status:intra_exchange_transfers_active: bool | None— whether intra-exchange
transfers are currently permitted (omitted by older servers, hence optional).exchange_index_statuses: list[ExchangeIndexStatus]— per-index (shard)
status breakdown; defaults to[]when absent or null.
Added
ExchangeIndexStatusmodel (exported fromkalshiandkalshi.models):
per-exchange-index operational status withexchange_index,exchange_active,
trading_active, andintra_exchange_transfers_active.
v5.0.0
Syncs the upstream OpenAPI spec 3.21.0 → 3.22.0 (#454, #458). The headline
change is breaking: Kalshi removed the V1 order-write endpoints from the
spec, so the SDK removes the V1 order methods and their models. Order writes now
go exclusively through the V2 /portfolio/events/orders family (the *_v2
methods, which have existed since 3.18.0). See docs/migration.md for the
V1 → V2 mapping.
Removed (breaking)
- V1 order-write methods on
client.orders(sync + async):create,
cancel,batch_create,batch_cancel,amend,decrease. The underlying
endpoints (POST/DELETE /portfolio/orders,/portfolio/orders/batched,
/portfolio/orders/{id}/amend,/portfolio/orders/{id}/decrease) were
removed from the spec in 3.22.0. Use the*_v2equivalents instead. - V1 order models (no longer exported from
kalshi/kalshi.models):
CreateOrderRequest,AmendOrderRequest,AmendOrderResponse,
DecreaseOrderRequest,BatchCreateOrdersRequest,BatchCreateOrdersResponse,
BatchCreateOrdersResponseEntry,BatchCancelOrdersRequest,
BatchCancelOrdersResponse,BatchCancelOrdersResponseEntry,
BatchCancelOrdersRequestOrder, and theActionLiteral(buy/sell) alias. - Dead quote filters —
event_tickerandmarket_tickerwere removed from
GET /communications/quotesupstream, so they are removed from
client.communications.quotes.list/list_alland the
communications.list_quotes/list_all_quotesfacade methods.
Added
- RFQ-scoped quote actions (spec 3.22.0) on
client.communications.quotes
(sync + async):accept_for_rfq(rfq_id, quote_id, ...),
confirm_for_rfq(rfq_id, quote_id),delete_for_rfq(rfq_id, quote_id)—
backingPUT/DELETE /communications/rfqs/{rfq_id}/quotes/{quote_id}[/accept|/confirm]. cancel_v2market_tickerquery param — required whenexchange_index
is-1(auto-route by ticker).BatchCancelOrdersV2RequestOrder.market_ticker— same auto-route semantics
for batch V2 cancels.SubaccountBalance.exchange_index— the exchange shard a balance is held on.- Perps SCM (
kalshi.perps.klear): newMarketSettlementEstimatemodel;
SettlementEstimate.positions(per-market breakdown map); and
GetSettlementEstimateResponse.prev_settlement_prices(market → last
settlement price, centicents).
v4.2.0
Reconciles in-place upstream spec drift detected by the nightly run (#451):
the live OpenAPI/AsyncAPI specs gained fields after 4.1.0 vendored them, under
the same 3.21.0 version string. All changes are additive — new response
fields on existing models. Also widens the cryptography dependency ceiling.
Added
Event.settlement_sources— the official settlement sources for an event
(EventData.settlement_sources, openapi 3.21.0). Typed
NullableList[SettlementSource], so a JSONnullcoerces to[]while the
key-present contract holds (same nullable shape asSeries.settlement_sources).
Note: spec-required, so code that constructsEventdirectly (e.g. test
mocks) must now include it.- WS
MarketLifecyclePayloadstrike fields —strike_type,cap_strike,
andcustom_strikeonmarket_lifecycle_v2payloads (asyncapi). All optional;
present only onmetadata_updatedframes.strike_type(between/greater
/less) controls howfloor_strike/cap_strikeare interpreted;
custom_strikecarries structured strikes.
Changed
cryptographydependency ceiling widened<49→<50(#448) — permits
cryptography 49.x. The SDK's RSA-PSS signing path uses onlyhashes/
serialization/padding/rsa, none of which 49.0.0's removals affect.- Re-vendored
specs/openapi.yaml(addedEventData.settlement_sources) and
specs/asyncapi.yaml(added the lifecycle strike fields; refreshed WS
error-code docs).openapi.yamlwas held at its known-good 104-operation
state: the upstream publish transiently droppedCreateOrder/
BatchCreateOrders/AmendOrder, an upstream glitch that was not imported.
v4.1.0
Spec sync from upstream OpenAPI v3.20.0 → v3.21.0 (plus AsyncAPI/perps). All
changes are additive — new query params, response fields, and four new
endpoints. Also closes the nightly spec-drift CI gap (failures now open a
tracking issue).
Added
client.communications.block_trade_proposals— new sub-resource for the
block-trade-proposals API (openapi 3.21.0):list()/list_all()
(GET /communications/block-trade-proposals),create()
(POST /communications/block-trade-proposals), andaccept()
(POST /communications/block-trade-proposals/{id}/accept). New models
BlockTradeProposal/GetBlockTradeProposalsResponse/
ProposeBlockTradeRequest/ProposeBlockTradeResponse/
AcceptBlockTradeProposalRequest(exported fromkalshi).AccountResource.volume_progress()—GET /account/api_usage_level/volume_progress
returns trailing-30-day trading-volume progress toward volume-based API usage
tiers. New modelsAccountVolumeProgress/AccountApiUsageLevelVolumeProgress
/AccountApiUsageLevelVolumeGoal.events.list/list_allgain atickersfilter — comma-separated event
tickers (GET /events?tickers=...).communicationsquotes endpoints gainmin_ts/max_ts— filter quotes
by last-updated Unix timestamp onquotes.list/list_all(and the
deprecatedlist_quotes/list_all_quotesforwarders).- Perps
MarginMarketmark-price fields —settlement_mark_price,
liquidation_mark_price, andreference_price(each a nestedTickerPrice
of{price, ts_ms});MarginPosition.subaccount(the holding subaccount
number); and WSErrorPayload.market_tickers(multi-market error frames).
Note:MarginPosition.subaccountis spec-required, so code that constructs
MarginPositiondirectly (e.g. test mocks) must now include it.
Changed
- Re-vendored
specs/openapi.yaml(3.20.0 → 3.21.0),specs/asyncapi.yaml,
specs/perps_openapi.yaml, andspecs/perps_scm_openapi.yaml. - Upstream narrowed the
Settlement.market_resultenum —voidwas removed
(nowyes/no/scalar). No SDK change:Settlement.market_resultis a
plainstrwithextra="allow", so any value still parses; noted here for
accuracy. - Nightly spec-drift CI now files a tracking issue on failure. The scheduled
Spec Drift Detectionrun previously failed silently between the weekly
Weekly Spec Syncruns; it now opens (and dedups) a singlespec-driftissue
so upstream drift is tracked the day it appears.
Fixed
- Hardened the
TestWsSpecDriftcontract-test fixture (the class-scoped fixture
is now a@staticmethod) so the strict nightly run reports real WebSocket
drift instead of erroring the whole class under-W error::UserWarning.
v4.0.0
Spec-drift reconciliation against the latest upstream OpenAPI (3.20.0) and AsyncAPI
specs (closes #443). Includes one breaking change: the Self-Clearing-Member
"Klear" API migrated from cookie-session login to Bearer-token auth. Everything
else is additive.
Breaking
- Klear (SCM) auth is now a Bearer token. Upstream removed
POST /log_inand
switched the Klear API toAuthorization: Bearer <admin_user_id>:<access_token>.
KlearClient/AsyncKlearClientnow requireadmin_user_idandaccess_token
at construction (or viafrom_env(), which readsKALSHI_KLEAR_ADMIN_USER_ID/
KALSHI_KLEAR_ACCESS_TOKEN). Removed: thelogin()method, the
is_authenticatedproperty, theclient.authresource, and theLogInRequest/
LogInResponsemodels.KlearAuthis now a Bearer-credential holder
(KlearAuth(admin_user_id, access_token)). Generate a token at
https://klearing.kalshi.com (the "Security" page).
Added
cfbenchmarks_valueWebSocket channel — stream CF Benchmarks reference index
values (e.g.BRTI) with trailing 60-second and final-minute quarter-hour
averages viaKalshiWebSocket.subscribe_cfbenchmarks_value(index_ids=[...]). New
modelsCFBenchmarksValueMessage/CFBenchmarksValuePayload/
CFBenchmarksAvgData/CFBenchmarksIndexListMessage/
CFBenchmarksIndexListPayload(exported fromkalshi.ws.models).AccountResource.upgrade()—POST /account/api_usage_level/upgradeto
request a permanent Advanced API usage-level grant.AccountApiLimits.grants— the per-exchange-lane usage-level grant list, plus
a newApiUsageLevelGrantmodel (exchange_instance/level/source/
expires_ts), exported fromkalshi.MarginAccountResource.api_limits()—GET /account/limits/perpsfor the
Perps API tier limits (reusesAccountApiLimits).- Perps market notional/leverage fields —
MarginMarketgains
leverage_estimatesandvolume/volume_24h/open_interestnotional-value
fields;MarginMarketCandlestickand thetickerWS payload gain notional-value
fields, all tracking the spec.
Changed
- Re-vendored
specs/openapi.yaml,specs/asyncapi.yaml,specs/perps_openapi.yaml,
specs/perps_asyncapi.yaml, andspecs/perps_scm_openapi.yaml; the subaccount
range documented in prose is now 1–63 (no validation change).
v3.3.0
Adds a complete FIX protocol subsystem (FIXT.1.1 / FIX50SP2) for both the
prediction and perps products. Additive release: no changes to the existing REST,
WebSocket, or Perps surfaces.
Added
- FIX engine (
kalshi.fix) — a hand-rolled, async-first FIX client for both
products:FixClient(prediction) andMarginFixClient(margin, in
kalshi.perps.fix), re-exported from the top-levelkalshipackage alongside
FixConfig,FixEnvironment, andFixSessionType. Covers five session types —
order entry (NR/RT), drop copy, market data, post-trade settlement (prediction),
and RFQ (prediction), plus order-group management over the order-entry session —
on a session state machine with
RSA-PSS logon (reusing the REST key), heartbeat / test-request liveness,
sequence tracking with gap-fill / resend on the retransmission sessions, and
AWS-style full-jitter reconnect. (Epic #402.) - Typed FIX messages — Pydantic v2 models for every Kalshi FIX message across
order entry, order groups, market data, RFQ/quoting, drop copy, and market
settlement, withDollarDecimal/FixedPointCountmoney types (no float
drift) and a central inbound dispatch viadecode_app_message. FixOrderBook— aggregated order-book reconstruction from market-data
snapshots + incrementals;SettlementReassembler— paginated
settlement-report reassembly.FixSession.on_decode_errorhook +decode_app_message_strict— surface a
registered-but-malformed inbound message instead of silently dropping it (#432).- FIX documentation — new
docs/fix.mdguide, plus FIX coverage in the
README, errors, authentication, configuration, environment-variables, and the
API reference. - FIX dictionary drift test —
specs/kalshi-fix-dictionary.xmlchecked in
with a model↔dictionary drift test, the FIX analogue of the REST contract-drift
suite (#437).
Fixed
- Documentation accuracy pass:
fcm.positions_all()is now documented (the FCM
page previously stated it did not exist); theportfolioreads document their
subaccountparameter; themarkets.is_block_tradeversion note is corrected
to SDK v3.1.0; theOrderPriceandMultiplierDecimaltypes are documented;
and the docs landing page's WebSocket channel count is corrected to 11.
v3.2.0
Adds full SDK support for the Kalshi Perps (margin) API — a separate
perpetual-futures exchange — as standalone clients alongside the existing
prediction-API surface. Additive release: no changes to KalshiClient.
Added
PerpsClient/AsyncPerpsClient— standalone clients for the perps
exchange (external-api.kalshi.com/ demoexternal-api.demo.kalshi.co,
/trade-api/v2), with their ownPerpsConfigand a separateKALSHI_PERPS_*
credential namespace. They reuse the prediction-API RSA-PSS signer and HTTP
transport unchanged. The constructors andfrom_env()also accept
ws_base_url(set the WS endpoint independently from REST) andpassword
(passphrase for an encrypted key), and readKALSHI_PERPS_WS_BASE_URL/
KALSHI_PERPS_PRIVATE_KEY_PASSPHRASEfrom the environment; passingconfig=
together withdemo/base_url/ws_base_urlis rejected. Resource families:
exchange(status / enabled gate /
risk parameters),markets(list / get / orderbook / candlesticks),orders
(create / get / list / cancel / decrease / amend + FCM),order_groups,
portfolio(positions / fills / trades),margin(balance / risk /
notional risk limit / fee tiers),funding(rate estimate / historical /
history), andtransfers(intra-exchange-instance + margin subaccounts).
Margin order side isbid/ask; prices areDollarDecimal
(FixedPointDollars), countsFixedPointCount, andnumber/doubleratios
(leverage, funding rate, ROE, fee tiers) areMultiplierDecimal(exact
Decimal, string-serialized) — consistent across the REST, WS, and exchange
surfaces. Margin-account list responses tolerate a server-returnednull.PerpsWebSocket— the perps margin WebSocket
(external-api-margin-ws.kalshi.com,/trade-api/ws/v2/margin) with six typed
channels (subscribe_orderbook_delta,subscribe_ticker— carrying
funding_rate+next_funding_time_ms,subscribe_trade,subscribe_fill,
subscribe_user_orders,subscribe_order_group). Reuses the event-contract
WS connection / sequence-gap / backpressure machinery; perps WS timestamps are
Unix epoch milliseconds (*_msfields).KlearClient/AsyncKlearClient— the Self-Clearing-Member "Klear"
settlement API (api.klear.kalshi.com/ demodemo-api.kalshi.co,
/klear-api/v1) with a third auth model: cookie-session + MFA via
login(email=..., password=..., code=...). Resourcemargincovers reports,
active/historical obligations, settlement estimate, settlement + guaranty-fund
balances, settlement-balance history, and settlement-balance withdrawal.
Klear money fields are integer centicents; the single real-money write
(withdraw_settlement_balance) validates a positive amount at construction.
Credentials and the session cookie are never logged or shown inrepr().docs/perps.md(+ mkdocs nav), README "Perps (margin) trading" section, and
runnableexamples/perps_create_order.py/perps_stream_ticker.py/
perps_balance_risk.py.
Changed
- Prediction-API list endpoints
markets.candlesticks/bulk_candlesticks/
bulk_orderbooksnow validate a typed response envelope: a missing
spec-required array key raisesValidationError(surfacing spec drift instead
of silently returning[]), while a null array coerces to[](Kalshi's
empty-as-null convention — the priordata.get(...)extraction would
TypeErroron a null array). The perpsmarkets.list/markets.candlesticks
/funding.historical_rates/funding.historyresponses use the same
NullableListenvelopes, so null-handling is consistent across both surfaces.
The optionalorder_groups.liststays tolerant of a missing/null array.
Fixed
KalshiWebSocket._stop()now retrieves an already-finished receive-loop's
exception, so a session torn down after a permanent close no longer logs
asyncio's "Task exception was never retrieved" on garbage collection.
Internal
- Vendored the three perps specs (
specs/perps_openapi.yaml,
perps_asyncapi.yaml,perps_scm_openapi.yaml);scripts/sync_spec.pyand the
weekly spec-sync workflow now fetch/diff/checksum them and fold their sha256
into the drift fingerprint (preserving thecontents: read+issues: write
security model). - Parameterized the contract-drift harness per spec:
TestPerps*Drift/
TestPerpsScm*Driftvalidate the perps REST + SCM surfaces against their own
specs, alongside the existing prediction-API drift suites. - README /
docs/index.mdbanners note the perps surface (34 REST operations,
6 WS channels, 10 SCM operations).
v3.1.0
OpenAPI + AsyncAPI spec sync from v3.19.0 → v3.20.0 (#385). Adds the
new GET /events/fee_changes endpoint plus three smaller additive
changes upstream re-published into 3.20.0 after the drift issue was
filed (the OpenAPI checksum in #385 is therefore stale; the AsyncAPI
checksum still matches).
Added
events.fee_changes()/fee_changes_all()(sync + async) for
GET /events/fee_changes— the new paginated event-level fee-override
feed (event_ticker,limit,cursor). ReturnsPage[EventFeeChange]
(and an auto-paginating iterator).EventFeeChangeexposes
fee_type_override/fee_multiplier_override, both present-but-None
when an override is cleared.is_block_tradequery param onmarkets.list_trades/
list_all_trades(+ deprecatedlist_trades_all) and
historical.trades/trades_all. Omit for all trades,Truefor
only block trades,Falsefor only non-block.Trade.is_block_trade(bool) — new spec-required, non-nullable
response field; a missing key raises so a schema regression surfaces.- WebSocket
event_fee_updatemessage on the existing
market_lifecycle_v2channel (EventFeeUpdateMessage/
EventFeeUpdatePayload).subscribe_market_lifecycle()now yields
MarketLifecycleMessage | EventFeeUpdateMessage. Channel count is
unchanged (still 11) — this is a second message type on an existing
channel. Behavioral note for existing subscribers: discriminate on
.typebefore reading payload fields — anEventFeeUpdatePayloadhas no
market_ticker, so naive access raisesAttributeError. See the
migration callout indocs/websockets.md.
Internal
specs/openapi.yaml(sha256
b72a2aa138695d810f6ca85096bfe19e1b66ba5e9b2ed37753be284b5288d271)
andspecs/asyncapi.yaml(sha256
2f72d0a3fd25fe331210ed300f03ad4c1fedcb561b3ab425046b2dca6f4683ec)
snapshots bumped;kalshi/_generated/models.pyregenerated.- Spec also relaxed
CreateOrderV2Request.client_order_idand
EventData.product_metadatafrom required to optional, and added
ApiKeyScope/FeeTypeenums. No SDK-facade change: the V2 order
keepsclient_order_idrequired by design,Event.product_metadata
already tolerated server omission, and API-keyscopesstaysstr
for forward-compat. - README +
docs/index.mdbanners bumped to "99 operations … OpenAPI
v3.20.0".