npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

kalshi-client

v1.0.0

Published

Production-grade, fully-typed TypeScript SDK for the Kalshi Predictions API (REST + WebSocket) — RSA-PSS request signing, typed resources, automatic retries, rate-limit awareness, and a reconnecting WebSocket client with sequence-gap recovery.

Readme

kalshi-client

Production-grade, fully-typed TypeScript SDK for the Kalshi Predictions API — REST + WebSocket, RSA-PSS request signing, typed resources for every endpoint group, automatic retries with jittered backoff, client-side rate limiting, and a self-healing WebSocket client with sequence-gap recovery.

Not officially affiliated with or endorsed by Kalshi Inc.

Features

  • Full REST coverage — Exchange, Markets, Events, Orders (V2 + legacy), Order Groups, Portfolio, Communications (RFQ), API Keys, Search
  • Typed WebSocket client — all public/private channels, auto-reconnect with jittered exponential backoff, automatic re-subscription, and sequence-gap detection/recovery for orderbook_delta and order_group_updates
  • RSA-PSS request signing built in — no need to hand-roll the crypto
  • Automatic retries on 429/5xx with jittered exponential backoff and Retry-After awareness
  • Optional client-side rate limiting (token bucket) to proactively stay under your tier's limits
  • Cursor pagination helpersclient.markets.listAll() style async generators for every list endpoint
  • Dual ESM + CJS build with full type declarations, zero runtime dependencies besides ws
  • Strict TypeScript throughout, noUncheckedIndexedAccess, no any in the public surface
  • Zero-cost tree-shakingsideEffects: false, per-resource classes

Install

npm install kalshi-client

Requires Node.js >= 18.

Quick start

import { KalshiClient } from 'kalshi-client';

// Public market data needs no credentials.
const client = new KalshiClient({ environment: 'demo' });

const { markets } = await client.markets.list({ status: 'open', limit: 10 });
console.log(markets.map((m) => m.ticker));

Authenticated usage

Generate an API key under Account & security → API Keys in the Kalshi UI (production or demo). You'll get an API Key ID and a downloadable .key file (PEM-encoded RSA private key).

import { KalshiClient } from 'kalshi-client';

const client = new KalshiClient({
  environment: 'demo', // or 'production'
  apiKeyId: process.env.KALSHI_API_KEY_ID!,
  privateKeyPath: process.env.KALSHI_PRIVATE_KEY_PATH!, // or privateKeyPem
});

const balance = await client.portfolio.getBalance();
console.log(`Balance: $${(balance.balance / 100).toFixed(2)}`);

Or build straight from environment variables (KALSHI_ENV, KALSHI_API_KEY_ID, KALSHI_PRIVATE_KEY / KALSHI_PRIVATE_KEY_PATH):

const client = KalshiClient.fromEnv();

Placing an order (V2)

import { randomUUID } from 'node:crypto';

const { order } = await client.orders.create({
  ticker: 'HIGHNY-24JAN01-T60',
  client_order_id: randomUUID(), // required idempotency key
  side: 'bid', // 'bid' | 'ask'
  count: '10.00',
  price: '0.5600',
  time_in_force: 'good_till_canceled',
  self_trade_prevention_type: 'taker_at_cross',
});

await client.orders.cancel(order.order_id);

Pagination

Every list endpoint has a raw cursor method (.list()) and a lazy-iterating convenience method (.listAll() / .listPositions() / etc.) that walks every page for you:

for await (const market of client.markets.listAll({ status: 'open' })) {
  console.log(market.ticker);
}

WebSocket streaming

const ws = client.createWebSocket();

ws.on('orderbook_snapshot', (msg) => console.log('snapshot', msg.msg));
ws.on('orderbook_delta', (msg) => console.log('delta', msg.msg));
ws.on('sequence_gap', (channel, expected, received) => {
  console.warn(`gap on ${channel}: expected ${expected}, got ${received}`);
  // The client automatically requests a fresh snapshot to resync.
});
ws.on('reconnecting', (attempt, delayMs) => console.log(`reconnecting #${attempt} in ${delayMs}ms`));

await ws.connect();
await ws.subscribe({
  channels: ['orderbook_delta', 'ticker'],
  market_tickers: ['HIGHNY-24JAN01-T60'],
});

The socket handles reconnection and re-subscription automatically. All order mutation (create/cancel/amend) stays on REST — the WebSocket is read-only, matching Kalshi's API design.

Available channels

| Channel | Access | Notes | |---|---|---| | orderbook_delta | private | sequenced; snapshot + deltas | | ticker | public | price/volume/OI updates | | trade | public | public trade prints | | fill | private | your own fills | | market_positions | private | position updates | | market_lifecycle_v2 | public | market open/close/settle events | | multivariate_market_lifecycle | public | multivariate event lifecycle | | multivariate | public | multivariate market updates | | communications | private | RFQ/quote activity | | order_group_updates | private | sequenced; order group state | | user_orders | private | your order lifecycle |

Error handling

import { KalshiApiError, KalshiTimeoutError } from 'kalshi-client';

try {
  await client.orders.create({ /* ... */ });
} catch (err) {
  if (err instanceof KalshiApiError) {
    console.error(err.status, err.code, err.message);
    if (err.isRateLimited) {
      // handled automatically by retry, but you can inspect it
    }
  } else if (err instanceof KalshiTimeoutError) {
    console.error('request timed out');
  }
}

All SDK errors extend KalshiError, so catch (err) { if (err instanceof KalshiError) ... } catches everything the SDK throws.

Configuration reference

new KalshiClient({
  environment: 'production' | 'demo',   // default 'production'
  apiKeyId: string,
  privateKeyPem: string,                // PEM contents
  privateKeyPath: string,               // path to a .key file (mutually exclusive with privateKeyPem)
  baseUrl: string,                      // override REST base URL
  wsUrl: string,                        // override WebSocket base URL
  timeoutMs: number,                    // default 10000
  maxRetries: number,                   // default 3
  rateLimitPerSecond: number,           // default 0 (disabled)
  fetchImpl: typeof fetch,              // inject a custom fetch (testing)
  onRequest: (info) => void,            // observability hook
});

Resource map

| Resource | Methods | |---|---| | client.exchange | getStatus, getAnnouncements, getSchedule, getSeriesFeeChanges, getUserDataTimestamp, getApiLimits | | client.markets | list, listAll, get, getOrderbook, getOrderbooks, getTrades, getCandlesticks, getSeries, listSeries | | client.events | list, listAll, get, getMetadata, getForecastHistory, listMultivariateCollections | | client.orders | list, listAll, get, create, batchCreate, cancel, batchCancel, amend, decrease, getQueuePosition, getQueuePositions, legacy.create, legacy.batchCreate | | client.orderGroups | list, get, create, delete, reset, trigger, updateLimit | | client.portfolio | getBalance, getPositions, listPositions, getFills, listFills, getSettlements, getDeposits, getWithdrawals, getRestingOrderTotalValue, createSubaccount, getSubaccountBalances, transferBetweenSubaccounts, getSubaccountTransfers | | client.communications | listRfqs, createRfq, getRfq, deleteRfq, listQuotes, createQuote, getQuote, deleteQuote, acceptQuote, confirmQuote, getCommunicationsId | | client.apiKeys | list, create, generate, delete | | client.search | query |

See examples/ for runnable scripts, and inline TSDoc on every method (which REST path it hits) in your editor.

Development

npm install
npm run typecheck
npm run lint
npm test
npm run build

License

MIT — see LICENSE. This is an independent, community-built SDK and is not officially affiliated with, endorsed by, or maintained by Kalshi Inc. Always verify behavior against the official Kalshi API docs before trading with real funds.