This tutorial takes about ten minutes. You will create a client against the Polyester testnet, read public market data, subscribe to a live stream, and place and cancel a spot order with an API key.
Create a client
The SDK is configured with an environment — a frozen object describing the API, WebSocket, and chain endpoints. The testnet environment ships with the package:
import { PolyesterClient, POLYESTER_TESTNET_ENVIRONMENT } from "@polyester/sdk";
const client = new PolyesterClient({
environment: POLYESTER_TESTNET_ENVIRONMENT,
});Without an auth option the client can call every public service (market data, candles, order
books, chain analytics). We add credentials in step 4.
Read public market data
Fetch the market overview — one row per trading pair with last price and 24h stats:
const { markets } = await client.marketOverview.list({ limit: 10 });
for (const market of markets) {
console.log(`${market.symbol}: ${market.lastPrice}`);
}All prices and quantities in the SDK are decimal strings ("64250.5"), never floats. See Catalog & precision for why.
Resolve a symbol with the catalog
Some endpoints address markets by numeric symbolId rather than the pair symbol. The client's
built-in catalog maps between them (it loads reference data on first use):
await client.catalog.ensureReady();
const symbolId = client.catalog.market.requireSymbolIdByPairSymbol("BTC-USDC");Stream live candles
Every realtime stream follows the same contract: call subscribe(...) with event handlers, get
back an unsubscribe function.
const unsubscribe = client.candles.subscribe({
symbolId,
timeframe: "1m",
onEvent: (candle) => console.log("candle", candle.close),
onError: (ctx) => console.error("stream error", ctx),
});
// later
unsubscribe();Authenticate with an API key
Trading requires credentials. Recreate the client with an Ed25519 API key auth provider — the SDK signs every request for you:
import { PolyesterClient, POLYESTER_TESTNET_ENVIRONMENT, evmHexToBytes } from "@polyester/sdk";
const client = new PolyesterClient({
environment: POLYESTER_TESTNET_ENVIRONMENT,
auth: {
kind: "api-key-ed25519",
getKeyId: () => process.env.POLYESTER_API_KEY_ID ?? null,
getSecretKey: () => evmHexToBytes(process.env.POLYESTER_API_SECRET_HEX ?? "0x"),
},
});getKeyId returns your ak_... key ID; getSecretKey returns the 32-byte Ed25519 secret key.
Both may be async, so you can load them from a vault.
Place and cancel an order
Place a small post-only limit order, then cancel it:
const created = await client.orders.create({
symbol: "BTC-USDC",
side: "buy",
orderType: "limit",
timeInForce: "gtc",
price: "10000",
qty: "0.001",
postOnly: true,
clientOrderId: crypto.randomUUID(), // idempotency key — safe to retry with the same id
});
console.log("order accepted:", created);
const { orders } = await client.orders.listOpen({ symbol: "BTC-USDC" });
console.log(`${orders.length} open order(s)`);
await client.orders.cancel({
orderId: orders[0].orderId,
symbolId: orders[0].symbolId,
});The SDK validates the order client-side against the pair's tick size, step size, and minimums
before it is sent — invalid input throws a ValidationError or CatalogConversionError without
touching the network.
Where to go next
- Authentication — wallet login in the browser, API keys on servers, and session handling.
- Trading — attached risk, triggers, order modification, and pagination.
- Streaming — the realtime model in depth.
- Architecture — how the pieces fit together.