Skip to main content
The @kashdao/sdk package is the official TypeScript client for the REST API. It’s the recommended way to integrate from any TS/JS runtime: Node 22+, modern browsers, Deno, Bun, Cloudflare Workers or Vercel Edge. It uses native fetch and has one runtime dependency (Zod).

Construct the client

new KashClient() with no arguments reads KASH_API_KEY (and KASH_BASE_URL) from the environment where a process.env exists. Base URL selection. You normally don’t set baseUrl. It resolves in this order:
  1. an explicit baseUrl option;
  2. the KASH_BASE_URL environment variable;
  3. the key prefix: kash_test_* → https://api-staging.kash.bot/v1 (Solana devnet, simulated USDC), kash_live_* → https://api.kash.bot/v1;
  4. otherwise production, https://api.kash.bot/v1.
Both URLs are exported as PRODUCTION_BASE_URL and STAGING_BASE_URL. The key is validated against kash_(live|test)_ plus 32 alphanumerics at construction, so pasting a whsec_... webhook secret by mistake throws KashConfigurationError immediately. Other options: retryBaseDelayMs (default 200), retryMaxDelayMs (default 10 000), retryAfterMaxMs (default 60 000: a server Retry-After longer than this surfaces the error instead of sleeping), headers (extra default headers such as traceparent), fetch (custom implementation), hooks, conditionalRequests (default true, see below), conditionalCacheMaxEntries (default 256) and apiVersion. The client exposes typed sub-clients: kash.markets, kash.quotes, kash.trades, kash.redemptions, kash.portfolio, kash.webhooks, kash.account and kash.traces. kash.healthCheck() checks connectivity and never throws; it returns { ok, latencyMs, status?, version?, requestId? }.

Read markets

Market status is one of UNSEEDED, ACTIVE, RESOLVED or ABANDONED. Every market carries chainRef (for example solana:mainnet-beta); chainId is present only on EVM markets. Production trading runs on Solana. Use parseChainRef / tryParseChainRef to get a typed view of chainRef.

Get a quote

Quotes are split into buy and sell so you can’t pass the wrong unit to the wrong side. USDC amounts are atomic, 6 decimals; outcome-token amounts are WAD, 18 decimals. Both accept a string or a bigint.
Each quote also carries the post-trade state (pAfter, qAfter, reserveAfter) and an embedded market summary.

Place a trade

On API version 2026-08-19 (the SDK default), txHash on a Solana trade is the base58 transaction signature. waitForCompletion refuses a trade that is still pending_confirmation with a KashConflictError; confirm it first. Type guards such as isCompletedTrade, isTerminalTrade and isAwaitingConfirmation narrow a TradeResource by status. Idempotency. Every POST the SDK sends carries an Idempotency-Key. If you don’t pass one, the SDK generates one per call, so its own retries can never duplicate a write. Pass your own key when your code may retry the same logical order across calls.

Redeem a settled position

When a market resolves (or is cancelled), winning tokens stay in your account until you redeem them. One call redeems one (market, outcome) position:
Requires the trades:write scope. The request is accepted synchronously and the payout executes asynchronously. Calling it again for a position that already has a request returns that request with idempotent: true. A position that can’t be redeemed throws KashConflictError with code POSITION_NOT_CLAIMABLE.

Portfolio

watchPositions polls with conditional GETs and backs off while nothing changes (minIntervalMs 5 000, maxIntervalMs 60 000, backoffFactor 2 by default). With conditionalRequests on, the client sends If-None-Match on repeat GETs and resolves a 304 Not Modified from its in-memory copy.

Pagination — async iteration

List methods (markets.list, markets.predictions, trades.list, webhooks.list) return a Page<T> that’s both the first page and an AsyncIterable<T>:

Verify a webhook

constructEvent(body, signatureHeader, secret, opts?) checks the X-Kash-Signature HMAC and a 5-minute timestamp tolerance (override with opts.toleranceMs), accepts any matching v1= entry during a secret-rotation overlap, then parses the envelope { id, type, apiVersion, createdAt, data }. verifySignature runs the same check and returns { valid: true } or { valid: false, reason } without parsing. It throws KashConfigurationError for an empty secret and KashValidationError for a body that verifies but isn’t a known event. Webhook management: kash.webhooks.list({ status, limit, cursor }), kash.webhooks.redeliver(eventId) and kash.webhooks.rotateSecret() (returns { secret, rotatedAt, previousRetainedUntil }, the new secret shown once). These need the webhooks:manage scope.

Typed errors

Every error is a subclass of KashError:
retryAfterSeconds (on KashRateLimitError, KashServerError and KashMaintenanceError) is undefined when the server sent no Retry-After. KashValidationError and KashConfigurationError expose issues. The SDK retries 429, 5xx, network errors and timeouts on its own, up to maxRetries.

Lifecycle hooks

Tap into every request, response, retry and error for logging or observability. The SDK never logs by itself.
onResponse also carries requestId, apiVersion (the server’s X-API-Version), idempotentReplay, notModified and deprecation (parsed Sunset / Deprecation / Link rel="sunset" headers, or null).

Cloning a client

withConfig returns a new client with overridden fields. Useful for switching between API keys or per-scope timeouts:
withConfig re-validates, so an invalid override throws KashConfigurationError. Per-call overrides (timeoutMs, maxRetries, signal, headers) can also be passed as the last argument of any method.

Mock client for tests

@kashdao/sdk/testing exports an in-memory mock client (no network, no retries) with wire-shape-valid default fixtures:
Fixtures exported alongside it include DEFAULT_MARKET, DEFAULT_TRADE, DEFAULT_COMPLETED_TRADE, DEFAULT_QUOTE_BUY, DEFAULT_QUOTE_SELL, DEFAULT_REDEMPTION, DEFAULT_POSITION and DEFAULT_PORTFOLIO_SUMMARY.

API versions

The SDK sends X-Kash-Api-Version on every request. It defaults to 2026-08-19 (exported as SDK_API_VERSION), and you can override it:
The API supports two versions: Because production trading is on Solana, keep the SDK default unless you have a specific reason not to. An unsupported value returns 410 API_VERSION_UNSUPPORTED with the accepted list in the body’s supported member (err.extensions?.supported on the thrown error). Responses carry the version that served the request in X-API-Version, plus Sunset / Deprecation headers when a version is winding down; the onResponse hook surfaces both. The SDK also sends a User-Agent of the form @kashdao/sdk/<version> (<runtime>) (exported as USER_AGENT), with your userAgentSuffix appended.

Versioning and bundle size

The SDK is pre-1.0 (0.x): a minor version may include breaking changes, so pin a minor range in package.json. Each release is held to a size-limit budget, measured excluding Zod: 24 KB for the main entry and 8 KB for @kashdao/sdk/testing.

Source

Market disputes (/v1/markets/{id}/disputes) are served by the API but are not wrapped by the SDK. Call those endpoints directly with your X-API-Key.

Next

Build a trading bot

End-to-end walkthrough using this SDK.

CLI

kash — the command-line interface. Same primitives, scripting-friendly.

Endpoint Reference

The full live spec at /v1/docs.