TypeScript SDK

drazill — typed, native fetch, with a WebSocket client and webhook verification.

The drazill package is generated from the contract and MIT-licensed. Requires Node.js 18+ (uses native fetch and FormData). Drazill is the canonical client export.

Install

npm install drazill

The package is unscoped — drazill, not @drazill/sdk — so it matches the Python package name on PyPI exactly.

An unconfigured client talks to staging (https://staging.drazill.com/api/v1), never production — pass baseUrl or set DRAZILL_BASE_URL to target another environment.

Quickstart

Point the client at an environment with DRAZILL_BASE_URL (defaults to staging). List open markets:

quickstart_markets.ts
const client = new Drazill({ apiKey: API_KEY, baseUrl: BASE_URL });
console.log(`→ Drazill API @ ${BASE_URL}\n`);
// 1) List a page of open markets.
const page = await client.markets.listMarkets({ status: "ACTIVE", limit: 5, sort_by: "volume" });
console.log(`Open markets (${page.total} total, showing ${page.items.length}):`);
for (const m of page.items) {
console.log(` • ${m.title}`);
console.log(` id=${m.id} slug=${m.slug} volume=${m.total_volume}`);
}

Lifted verbatim from the tested example sdks/typescript/examples/quickstart_markets.ts. See Quickstart for the full walkthrough.

Place an order idempotently

Preview a quote, then place the order binding the quote token and an idempotency key, so a client-side retry can’t double-place:

quickstart_trade.ts
const idempotencyKey = `quickstart-trade-${crypto.randomUUID()}`;
const result = (await client.orders.placeOrder(
{
market_id: market.id,
outcome_id: outcomeId,
side: "BUY",
type: "MARKET",
quantity: ORDER_QTY,
preview_quote_token: quote.quote_token,
},
{ include_receipt: true },
{ idempotencyKey },
)) as any;

WebSocket

Connect, then subscribe per channel with a handler. prices:{outcome_id} gives price ticks, orderbook:{outcome_id} gives depth, trades:{market_id} gives the tape:

Realtime
const ws = client.ws();
ws.connect();
ws.subscribe("orderbook:OUTCOME_UUID", (data) => console.log("Order book:", data));
ws.subscribe("trades:MARKET_UUID", (data) => console.log("New trade:", data));
ws.subscribe("prices:OUTCOME_UUID", (data) => console.log("Price:", data));
ws.on("connected", () => console.log("Connected"));
ws.on("disconnected", () => console.log("Disconnected"));
ws.on("error", (data) => console.log("Error:", data));
ws.disconnect();

(client is the initialized Drazill client from the quickstart.)

Verify webhooks

Verify the signature before trusting an inbound webhook, then construct the typed event:

webhooks.ts
export async function handleWebhook(
rawBody: string,
headers: Headers,
secret: string,
) {
const isValid = await verifyWebhookSignature(rawBody, headers, secret);
if (!isValid) {
throw new Error("Invalid Drazill webhook signature");
}
return constructWebhookEvent(rawBody, headers, secret);
}

The full webhook contract (signing, retries, replay) is under Webhooks.

Retries, pagination & errors

The client accepts a maxRetries option (retries 5xx and 429, honouring Retry-After), exports cursor iterators (paginateCursor / paginateOffset) for for await iteration, and throws typed errors (ApiError, AuthenticationError, RateLimitError, ValidationError) — RateLimitError.retryAfter carries the backoff. See the SDK README and Rate limits.