v1.1.0
Post-1.0 enhancements and polish. 17 issues closed across four parallel waves of
work. No breaking changes to runtime behavior; two mypy-level type-system
tightenings are called out below.
Added
-
Model-first request API. Every POST/PUT/DELETE-with-body resource method
now accepts a pre-built request model as an alternative to individual kwargs.
Backward-compatible — the existing kwarg form continues to work unchanged
(#56).client.orders.amend(request=AmendOrderRequest(order_id=..., yes_price=...)) client.orders.amend(order_id=..., yes_price=...) # also works
Each method has typed
@overloadstubs (32 methods × 2 = 64 stubs) so mypy
catches misuse at type-check time, not runtime. -
DataFrame integration.
Page[T]gained.to_dataframe()and
.to_polars()methods with optional dependency extras (#12):pip install 'kalshi-sdk[pandas]' # or [polars] or [all]
page = client.markets.list(limit=100) df = page.to_dataframe()
Lazy imports;
Decimalanddatetimepreserved as native types via
model_dump(mode="python"). -
Record / replay mock transport (
kalshi.testing) for offline integration
testing (#13).RecordingTransportproxies real calls and saves
request/response pairs as JSON;ReplayTransportserves the fixtures with
no network. Sync and async transports both supported; signature/timestamp
headers are excluded from fingerprinting so signatures can drift between
record and replay.with KalshiClient.from_env(transport=RecordingTransport("fixtures")) as c: c.exchange.status() # records once with KalshiClient(transport=ReplayTransport("fixtures")) as c: c.exchange.status() # offline replay
-
Typed
Literalaliases for fixed-enum kwargs (#50). 13 new aliases
exported fromkalshiandkalshi.models:SideLiteral,ActionLiteral,
TimeInForceLiteral,SelfTradePreventionTypeLiteral,OrderStatusLiteral,
EventStatusLiteral,MarketStatusLiteral,MveFilterLiteral,
MveHistoricalFilterLiteral,MultivariateCollectionStatusLiteral,
IncentiveProgramStatusLiteral,IncentiveProgramTypeLiteral,
SettlementStatusLiteral. mypy now catches typos in resource kwargs at
authoring time. -
MkDocs documentation site (#14, #57). Material theme + mkdocstrings;
Getting Started, Authentication, WebSockets, Resources, Errors, Migration
guides plus auto-generated API reference. GitHub Pages deploy workflow at
.github/workflows/docs.yml. -
Constructor-variant integration tests (#54). Exercises every supported
KalshiClientconstruction path against the demo API (from_env,
key_id + private_key_path, in-memory PEM string, pre-builtKalshiAuth,
demo=True). Includes an async sibling test to catch signing-path drift. -
Per-method auth guards on
markets.orderbook(#49). Spec walk confirmed
this was the only public-resource GET endpoint missing_require_auth();
unauthenticated callers now get a clearAuthRequiredErrorinstead of a
confusing 401 from Kalshi.
Changed
-
Sync/async dedup refactor (#46). Extracted shared body-builder,
query-param-builder, and response-parser helpers across 13 resource modules.
Dispatcher logic and request-model construction now exist once per
method-pair instead of twice. Sync/async signatures,@overloadstubs, and
theasync for item in client.markets.list_all():ergonomic are all
preserved. -
Async
OrdersResource.batch_cancelrouted through shared
_delete_with_bodyhelper (#47). Previously called the transport directly,
bypassing the sync path's helper; any future retry / error-mapping change to
the helper now applies to both transports symmetrically. -
Sync
test_list_alliteration idiom standardized (#48). Sync tests now
use the same manual-counter loop as their async siblings; cosmetic only.
Fixed
- Async
multivariate.lookup_tickers204 spec-drift guard (#72). Sync had
a clearRuntimeError("spec drift: ...")on an unexpected 204; async would
surface a confusingTypeErrorfrommodel_validate(None). Extracted a
shared_parse_lookup_tickers_responsehelper so both paths share the
guard.
Test infrastructure
-
Typed
ExclusionKinddiscriminator on contract drift exclusions (#51).
Replaces the free-textreasonsubstring matching in
test_exclusion_map_is_currentwith explicit
Literal["body_param", "spec_deprecated", "paginator_handled", "wire_normalization", "kwarg_rename"]classification. All 47 existing
exclusions reclassified. -
Nested-model body-drift detection (#52). The drift test now recurses
into nestedBaseModelfields (e.g.TickerPairinside
CreateMarketInMultivariateEventCollectionRequest.selected_markets).
TickerPair.extra="allow"intentionally preserved becauseLookupPoint
responses echo provider keys; the existing pin test documents the carve-out. -
kwarg_renameExclusionKindsplit out ofwire_normalization(#68).
Python-naming-hygiene renames (milestone_type,target_type,
incentive_type— spec fieldtypeshadows the builtin) are now
classified separately from wire-format normalization.
Infrastructure
-
Weekly OpenAPI + AsyncAPI spec sync CI (#16). Cron + manual dispatch
workflow snapshots both specs, regenerates models, runs ruff / mypy /
pytest, opens a PR with version + endpoint diff if any changes detected.
Third-party actions pinned to commit SHAs because the workflow holds
contents: write+pull-requests: write. Concurrency-guarded against
same-branch races. -
Nightly integration CI against the demo API (#55). Secret-gated, skips
cleanly on forks, dedupes failure issues by stable title.
mypy-only breaking changes
These tighten types without changing runtime behavior. Existing valid calls are
unaffected; the type system will now reject calls that would have failed at
runtime anyway (or that were always wrong but mypy couldn't see it).
Page[T]TypeVar tightened fromTypeVar("T")to
TypeVar("T", bound=BaseModel). Matches the bound already used inside
kalshi/resources/_base.pyand the actual usage pattern across the SDK
(every concretePage[X]parameterizes with aBaseModelsubclass).- Resource-method kwargs for the 13 enum fields above are now
Literal[...]
instead ofstr | None. Callers passing arbitrary strings (typos, in-flight
variable values) now fail at mypy-check time.
Coverage at 1.1.0
- 89/89 REST endpoints implemented (sync + async); auth-guard audit complete
across public resources. - 11 WebSocket channels with sequence-gap detection, configurable backpressure,
and automatic reconnection. - 1407 unit tests passing (1455 collected, 48 skipped — up from 899 at
1.0.0), mypy--strictclean (76 source files), ruff clean. - Drift tests now detect query/path/body/WS-payload schema drift and nested
body-model drift. - Optional extras:
pandas,polars,all,docs.