SDKs

Typed SDKs

First-class TypeScript and Python clients. The MCP server and every example are built on them. Same resources, same shapes, in both languages — pick a language once below and every example on the site follows.

TypeScript — @multidex/sdk

install · typescript
pnpm add @multidex/sdk   # or npm i / yarn add

Zero runtime dependencies (native fetch, Node ≥ 20 or any modern browser). Config resolves from arguments, then the MULTI_API_KEY / MULTI_BASE_URL env vars.

Python — multidex-sdk

install · python
pip install multidex-sdk

Sync and async clients (built on httpx), pydantic models, and SSE streaming.

Create a client

import { MultiClient } from "@multidex/sdk";

const multi = new MultiClient({ apiKey: process.env.MULTI_API_KEY });
A key is only needed for account reads and execution — every market-data call below works without one.

Market data

Orderbooks, candles, and smart-routing recommendations. No key needed.

const book = await multi.markets.getOrderbook("BTC");
const candles = await multi.charts.getCandles("BTC", { interval: "1h", limit: 200 });
const routing = await multi.routing.getRecommendation("BTC", { side: "BUY" });

Streaming

Live trades, orderbook updates, and candles over SSE. TypeScript streams are async generators (stop with break or an AbortSignal); Python streams are iterators.

const ac = new AbortController();
for await (const ev of multi.streams.trades("BTC", { signal: ac.signal })) {
  console.log(ev.event, ev.data); // event: "trade"
}

Async (Python)

The async client mirrors the sync surface — same resources, awaited.

python
import asyncio
from multidex import AsyncMultiClient

async def main():
    async with AsyncMultiClient() as v:
        print(await v.markets.get_markets())
        async for ev in v.streams.candles("BTC", interval="1m"):
            print(ev.data); break

asyncio.run(main())

Execution

Execution needs an agent key with the orders:execute scope. Pass an idempotency key so retries never double-submit.

Place a smart-routed order

const order = await multi.orders.place(
  { symbol: "BTC", side: "BUY", type: "MARKET", quantity: "0.01" },
  { idempotencyKey: crypto.randomUUID() },
);

Open a position with a TP/SL bracket

takeProfitPrice / stopLossPrice are optional: after the entry fills, the server places a reduce-only TP (limit) and SL (stop-market) on the same venue.

const opened = await multi.orders.openPosition(
  {
    symbol: "BTC", direction: "LONG", size: "0.01",
    leverage: 3, orderType: "MARKET",
    takeProfitPrice: "75000", stopLossPrice: "60000",
  },
  { idempotencyKey: crypto.randomUUID() },
);

Batch orders

Up to 10 orders in one call, executed sequentially with per-order policy checks.

const batch = await multi.orders.placeBatch([
  { symbol: "BTC", side: "BUY", type: "MARKET", quantity: "0.01" },
  { symbol: "ETH", side: "SELL", type: "LIMIT", quantity: "0.5", price: "4200" },
]);

Portfolio

One-call cross-venue portfolio: positions, PnL, funding, risk summary.

const portfolio = await multi.portfolio.get();
console.log(portfolio.summary.totalUnrealizedPnlUsd, portfolio.summary.highestRisk);

Execution strategies

Server-run execution algos: twap (timed market slices) and scaled (a ladder of limit orders across a price range, via priceLow / priceHigh).

// TWAP: timed market slices
const twap = await multi.strategies.create({
  kind: "twap", symbol: "BTC", side: "BUY", totalQuantity: "0.1",
  sliceCount: 10, intervalMs: 60_000,
});

// Scaled ladder: limit orders spread across a price range
const scaled = await multi.strategies.create({
  kind: "scaled", symbol: "ETH", side: "BUY", totalQuantity: "1",
  sliceCount: 5, priceLow: "3800", priceHigh: "4000",
});

await multi.strategies.cancel(twap.id);

Pair trades

Long one asset, short another, in a single position.

const pair = await multi.pairs.open({ longSymbol: "ETH", shortSymbol: "BTC", notionalUsd: 500, leverage: 3 });
await multi.pairs.close(pair.id!);

Cross-chain swaps

Quote → prepare (sign yourself, non-custodial) or execute (headless). Amounts are in the smallest unit (wei / lamports).

const quote = await multi.swaps.quote({
  fromChain: 42161, toChain: 8453,
  fromToken: "0x0...", toToken: "0x833...",
  fromAmount: "1000000000000000",
});
const prepared = await multi.swaps.prepare({ quoteId: quote.bestQuote?.quoteId });

Error handling

Every failure throws/raises a typed error you can narrow: MultiAuthError (401/403), MultiRateLimitError (429, carries the retry-after delay), MultiAPIError, MultiTimeoutError, MultiNetworkError.

import { MultiAuthError, MultiRateLimitError } from "@multidex/sdk";

try {
  await multi.orders.place({ symbol: "BTC", side: "BUY", type: "MARKET", quantity: "0.01" });
} catch (err) {
  if (err instanceof MultiRateLimitError) {
    // err.retryAfterMs → back off, then retry with the same idempotency key
  } else if (err instanceof MultiAuthError) {
    // bad/expired key, or missing scope
  } else {
    throw err;
  }
}
Prefer no code? The same capabilities are available as MCP tools inside your agent harness. SDK resources: markets, trades, charts, routing, streams, orders, positions, portfolio, strategies, pairs, swaps.

Parity

  • Both SDKs default to https://multi-venym-labs.vercel.app/api; streams target the backend directly to avoid proxy buffering.
  • Both unwrap the { success, data } envelope and pass through raw array endpoints (candles).
  • Both retry idempotent GETs on 429/5xx with backoff, honoring Retry-After.