@sdk.markets/sdk is currently a preview package. These docs show the SDK surface we're building toward.Join the waitlist
markets sdk

TypeScript SDK

The target structure for @sdk.markets/sdk.

@sdk.markets/sdk is the core package. It owns:

  • domain types
  • platform client configuration
  • viem client integration
  • direct onchain market actions
  • hosted flow helpers
  • async job helpers
  • typed event watching

It should be usable from:

  • browser apps
  • React Native Expo apps
  • backend jobs
  • scripts
  • agents
  • tests

Integration modes

The SDK is meant to support multiple integration styles over time:

  • hosted platform sessions for CLI, apps, and managed execution
  • browser and mobile wallet clients for direct user-owned execution
  • backend wallet providers
  • server-to-server integrations where an app backend owns auth, policy, and transaction execution

Current hosted package surface

The current package exposes a hosted API client that mirrors the CLI's hosted mode. React Native Expo apps should use the hosted-only subpath so they do not pull direct onchain helpers into the mobile bundle:

import { createHostedClient } from "@sdk.markets/sdk/hosted";
import { toHostedCreateMarketInput } from "@sdk.markets/sdk/inputs";

const client = createHostedClient({
  baseUrl: "https://platform.markets",
  projectKey,
  actorToken,
});

@sdk.markets/sdk/hosted includes:

  • createHostedClient
  • hosted auth helpers: startLogin, pollLogin, whoami, bootstrap
  • hosted account helpers: wallet, balance
  • hosted market helpers: create, createAndWait, parseCloseTime
  • hosted job helpers: jobs.get

@sdk.markets/sdk/inputs includes the shared input conversion used by the CLI:

const input = toHostedCreateMarketInput({
  question: "Will our Expo app create a market?",
  options: ["Yes", "No"],
  closeTime: "tomorrow 8 pm",
  resolutionMode: "AiOracle",
  resolutionSources: ["https://example.com/source"],
});

const market = await client.markets.createAndWait(input);

The input helpers validate question/options, close time, admins, quorum, creator fees, and AI oracle sources before producing the hosted API payload.

Backend wallet execution

Apps that already route user actions through their own backend can keep wallet execution there. This is the server-to-server integration path. In this setup the client app does not need a platform actorToken; the backend authenticates the user, applies product policy, chooses the wallet, and sends the transaction with its own wallet provider.

Use the direct Markets client to prepare the transaction and parse the receipt while your backend wallet provider performs the send:

import { Markets, toCreateMarketInput } from "@sdk.markets/sdk";
import { createPublicClient, http } from "viem";
import { baseSepolia } from "viem/chains";

const markets = new Markets({
  chain: baseSepolia,
  publicClient: createPublicClient({
    chain: baseSepolia,
    transport: http(process.env.BASE_SEPOLIA_RPC_URL),
  }),
});

const input = toCreateMarketInput(payload, userWalletAddress);
const request = markets.prepareCreateTransaction(input, userWalletAddress);

const hash = await sendWithBackendWallet(request);
const receipt = await publicClient.waitForTransactionReceipt({ hash });
const marketAddress = markets.parseCreateReceipt(receipt);

If the backend exposes a generic sender, createWithExecutor can wrap the full flow:

const result = await markets.createWithExecutor(input, {
  account: userWalletAddress,
  sendTransaction: sendWithBackendWallet,
});

This mode is separate from hosted platform sessions. Hosted mode uses sdk.markets auth and hosted execution. Server-to-server mode lets an existing backend keep its own auth, wallet selection, policy checks, signing provider, and transaction submission while still using the SDK for market types, calldata, and receipt parsing.

Top-level client

import { MarketsClient } from "@sdk.markets/sdk";

const client = new MarketsClient({
  environment: "sandbox",
  apiKey: process.env.NEXT_PUBLIC_MARKETS_API_KEY!,
});

MarketsClient is the top-level facade over the lower-level hosted and direct clients. Hosted methods use the project API key plus the actor session. Direct methods use viem clients when you opt into explicit chain access. Server-to-server methods can prepare calldata or use an executor provided by your backend wallet provider.

For direct reads and writes, the same client can also be configured with viem clients:

const directClient = new MarketsClient({
  environment: "sandbox",
  apiKey: process.env.NEXT_PUBLIC_MARKETS_API_KEY!,
  publicClient,
  walletClient,
});

Modules

client.markets

Hosted market creation plus parimutuel reads and lifecycle actions.

Current surface:

client.markets.get(address)
client.markets.getMany(addresses)
client.markets.getStatus({ marketAddress })
client.markets.getUserPosition({ marketAddress, user })
client.markets.canFinalize({ marketAddress })
client.markets.isChallengeWindowActive({ marketAddress })
client.markets.isResolved({ marketAddress })

client.markets.create(hostedCreateInput)
client.markets.createAndWait(hostedCreateInput)
client.markets.createDirect(input)
client.markets.createWithExecutor(input, executor)
client.markets.prepareCreateTransaction(input, account)
client.markets.parseCreateReceipt(receipt)
client.markets.buyIn({ marketAddress, option, amount, approveIfNeeded })
client.markets.addToWhitelist({ marketAddress, users })
client.markets.removeFromWhitelist({ marketAddress, user })
client.markets.submitResolution({ marketAddress, option, evidenceUrl })
client.markets.submitAdminVote({ marketAddress, option })
client.markets.submitDispute({ marketAddress })
client.markets.finalize({ marketAddress })
client.markets.redeem({ marketAddress })
client.markets.refund({ marketAddress })
client.markets.voidMarket({ marketAddress })

client.drafts

Hosted validation and draft generation.

Planned surface:

client.drafts.validate(input)
client.drafts.generate(input)
client.drafts.get(id)
client.drafts.getValidation(id)

This is the main product entry point: generate or validate a draft first, then create the market through client.markets.create(...) or client.markets.createAndWait(...).

The client.drafts namespace exists in the current package, but its methods throw explicit "not available" errors until the hosted draft endpoints are published.

client.account

Wallet- and token-aware helpers.

Current surface:

client.account.getUsdcBalance({ address })
client.account.getUsdcAllowance({ owner, spender })
client.account.approveUsdc({ spender, amount })
client.account.getWalletState()

client.jobs

Async job helpers for hosted execution.

client.jobs.get(jobId)

Read-only usage

The core SDK should work without a wallet client when you only need reads:

const client = new MarketsClient({ publicClient });

const market = await client.markets.get(marketAddress);

Write methods should fail with explicit errors if no wallet client is available.

Direct versus hosted flows

The SDK supports both:

  • hosted flows as the default product path
  • direct flows for explicit contract reads and writes when you need lower-level control

For parimutuel hosted creation, the normal auth model is:

  • project API key
  • authenticated end-user session
  • managed wallet execution behind the scenes

Explicit wallet signatures are still relevant later for advanced signed-hosted flows such as CLOB orders, but they should not be the default hosted path here.

Event model

Typed event watchers should remain part of the core package:

const stop = client.markets.watchMarketEvent(
  marketAddress,
  "ResolutionSubmitted",
  (logs) => {
    console.log(logs);
  },
);

stop();

Why the SDK stays Privy-agnostic

Privy is our intended wallet UX, but the core package should only depend on viem-compatible clients. That keeps it portable:

  • browser app with Privy
  • CLI or script with a raw wallet client
  • backend worker with a service signer
  • tests with local wallets

Privy-specific behavior belongs in app/provider composition and the React package, not the core SDK itself.

On this page