TypeScript SDK

@inkle/sdk is a zero-dependency typed client for Node 18+ and the browser. It unwraps the response envelope, classifies errors, times out slow calls, and retries transient failures with backoff.

Install

bash
npm install @inkle/sdk

Create a client

ts
import { InkleClient } from "@inkle/sdk";

// Read-only
const inkle = new InkleClient();

// With trading and private reads
const bot = new InkleClient({
  apiKey: process.env.INKLE_API_KEY,
  timeoutMs: 30000, // per-request timeout (default 30s)
  maxRetries: 2,    // transient failures, exponential backoff (default 2)
});

Read markets

ts
const { items, count } = await inkle.markets.list({ status: "open" });
const market = await inkle.markets.get(items[0].id);
const { ticks } = await inkle.markets.priceTicks(market.id, { limit: 200 });

// A 10 $USDI buy on outcome 0
const quote = await inkle.markets.quote(market.id, 0, 10);
console.log(quote.shares, quote.avgPrice, quote.priceAfter);

Paginate large lists without holding everything in memory using the async iterator:

ts
for await (const m of inkle.markets.listAll({ status: "open" })) {
  console.log(m.question);
}

Trade

ts
const market = await bot.usdi.createLmsr({
  question: "Will it rain in Seoul tomorrow?",
  outcomeLabels: ["Yes", "No"],
  closesAt: new Date(Date.now() + 86400000).toISOString(),
  seed: 50,
});

await bot.usdi.bet(market.id, { outcomeIndex: 0, stake: 10 });
await bot.usdi.sell(market.id, { outcomeIndex: 0, shares: 4 });

const positions = await bot.usdi.myBets(market.id);

Handle errors

Every failure throws InkleApiError with a stable type (see the error codes). Branch on it:

ts
import { InkleApiError } from "@inkle/sdk";

try {
  await bot.usdi.bet(id, { outcomeIndex: 0, stake: 999999 });
} catch (e) {
  if (e instanceof InkleApiError) {
    switch (e.type) {
      case "invalid_request_error":
        console.error("Rejected:", e.message); // "insufficient $USDI balance"
        break;
      case "authentication_error":
        console.error("Bad or revoked key");
        break;
      case "rate_limit_error":
        console.error("Slow down"); // already retried by the SDK
        break;
      default:
        console.error(e.type, e.status, e.message);
    }
  }
}

Transient failures (429, 5xx, network, timeout) are retried automatically with exponential backoff and jitter, honoring a Retry-After header when the server sends one. Set maxRetries: 0 to opt out.

Cancel a request

ts
const controller = new AbortController();
setTimeout(() => controller.abort(), 2000);

await inkle.markets.list({ status: "open" }, { signal: controller.signal });

Portfolio & discovery

ts
// Your portfolio (read scope). Rows span both rails, so split
// them by tokenSymbol before totalling anything: USDC and $USDI
// are different currencies.
const positions = await bot.account.positions();
const onChain = positions.filter((p) => p.tokenSymbol !== "USDI");
const ledger = positions.filter((p) => p.tokenSymbol === "USDI");

const history = await bot.account.bets();
const created = await bot.account.markets();

// Public discovery (no key)
const results = await inkle.discover.search("bitcoin");
const trending = await inkle.discover.trending();
const board = await inkle.discover.leaderboard({ limit: 50 });

Namespaces

  • inkle.markets: public reads (list, listAll, get, priceTicks, publicBets, quote, sellQuote)
  • inkle.usdi: trading (createLmsr, createDirect, createFlash, bet, sell, myBets)
  • inkle.flash: on-chain flash pools (list, get, quote, price, bets)
  • inkle.discover: search, trending, leaderboard
  • inkle.account: me, positions, bets, markets