Skip to main content
This is the spine that ties the reference pages together. You’ll build a bot that watches a market, places a sized trade on a signal, verifies webhook events, tracks its positions, and redeems its winning positions after the market resolves. Everything here runs against staging (api-staging.kash.bot, Solana devnet with simulated USDC). Going live is the same code with a live key against api.kash.bot, where trading runs on Solana mainnet.
Use the @kashdao/sdk TypeScript client, not raw HTTP. It handles auth, retries, idempotency, typed errors, and webhook signature verification for you. Everything below is SDK-first.Building on the self-orchestrated surface instead — you run your own signer / market-making infra? Use the Protocol SDK. This tutorial is the managed REST path.

What you’ll build

A long-running loop that:
  1. Reads a market and quotes a position size.
  2. Places a trade with an idempotency key (safe to retry).
  3. Confirms the trade if it trips the high-value gate.
  4. Learns the outcome asynchronously via a signed webhook (or by polling).
  5. Tracks open positions.
  6. Redeems winning positions once the market resolves.

1. Prerequisites

  • A Kash web app account — sign up in the Kash web app.
  • An API key with these scopes (see Authentication): markets:read, markets:quote, trades:read, trades:write, portfolio:read, webhooks:manage. Keys are created in the web app (Settings → API Keys, mode Test for staging) and shown once — capture the plaintext. A kash_test_* key targets staging automatically.
  • Node 22+.

2. Construct the client

The SDK auto-routes to staging for a kash_test_ key and to production for a kash_live_ key — you don’t hard-code a base URL. It pins API version 2026-08-19, which is the version that lists and quotes Solana markets and identifies each market’s chain with chainRef.

3. Read a market and quote

Pick a market, then quote before you trade so you size against real on-chain liquidity. amountUsdcAtomic is USDC in atomic units (6 decimals → 10_000_000 = 10 USDC); outcome-token amounts are WAD (18 decimals).

4. Place a trade (idempotent)

Pass an idempotencyKey: if the request times out and your bot retries, you get the same trade back rather than a duplicate. The response carries idempotent: true when it’s a replay. (Without one, the SDK auto-generates a key per call, which protects its own retries but not a retry in your code.) amount is a USDC decimal string.
Reuse the same idempotencyKey for a given logical order across retries; generate a new one for each distinct order. See Idempotency.

5. Confirm high-value trades

Trades above your key’s per-trade threshold return a one-time confirmation token instead of executing immediately (the trade sits in pending_confirmation). Confirm it within 60 seconds to release execution.

6. Learn the outcome — webhooks (preferred) or poll

Webhooks are the production path: the API POSTs a signed event to your endpoint when the trade completes. Verify the signature with the SDK and dedupe on the event id — never trust an unverified body.
Prefer webhooks in production. For a script or a quick test, poll instead:
See Webhooks → Verifying for the full event catalog and signature scheme.

7. Track positions

positions() returns an array, not a page — everything at once, filterable by marketId. Each position carries shares (WAD) and costBasisAtomic (USDC). For a long-running bot, kash.portfolio.watchPositions() yields the positions now and again whenever they change, backing off while nothing moves.

8. Redeem winning positions

When a market resolves (or is cancelled), your winning outcome tokens stay in your account until they are claimed. Create a redemption for each (market, outcome) you hold; the redemption is then submitted from your self-custodial wallet and settles on-chain asynchronously.
It uses your trades:write scope and is idempotent: one open claim per (market, outcome), and a repeat returns the original request with idempotent: true. There is no redemption webhook. See the POSITION_NOT_CLAIMABLE and REDEMPTIONS_NOT_ENABLED codes.

9. Handle errors and rate limits

Every failure is a typed KashError subclass — branch on the class, not the message. The SDK already retries 429s, 5xx, network errors and timeouts (up to maxRetries, default 3) before throwing.
See Rate limits and the Error catalogue.

10. Going live

  • Swap the key for a kash_live_* key — the SDK re-routes to api.kash.bot automatically, and trades settle on Solana mainnet with real USDC.
  • Set the live key’s webhook URL to your production endpoint (in Settings → API Keys) and use that key’s KASH_WEBHOOK_SECRET.
  • Review rate limits for your tier.

See also

TypeScript SDK reference

Full @kashdao/sdk surface: clients, types, and error classes.

Endpoint reference

Every route, request/response shape, and status code.

Webhooks

Event catalog, signing scheme, retries, and secret rotation.

Protocol SDK (self-orchestrated)

Run your own signer / market-making infra instead of the managed REST path.