> For the complete documentation index, see [llms.txt](https://dev.strixlab.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dev.strixlab.io/get-started/quickstart.md).

# Quickstart

From an empty folder to a live order in about five minutes.

{% hint style="info" %}
**Prerequisites:** Node.js 18 or newer, a funded Strix Lab account, and a set of API keys. If you don't have an account yet, sign up at [strixlab.io](https://strixlab.io) and deposit USDC first.
{% endhint %}

{% stepper %}
{% step %}

### Install the SDK

{% tabs %}
{% tab title="npm" %}

```bash
npm install strix-sdk
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm add strix-sdk
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add strix-sdk
```

{% endtab %}

{% tab title="bun" %}

```bash
bun add strix-sdk
```

{% endtab %}
{% endtabs %}

Node 18–20 uses the bundled `ws` package for WebSockets; Node 21+ uses the built-in one. Either way, nothing else to install.
{% endstep %}

{% step %}

### Generate API keys

In the app, open **Settings → API Keys → Generate Keys**. You get three values:

<table><thead><tr><th width="190">Credential</th><th>Notes</th></tr></thead><tbody><tr><td><code>apiKey</code></td><td>Public identifier. Visible in settings any time.</td></tr><tr><td><code>apiSecret</code></td><td>Signs every request. Shown <strong>once</strong>.</td></tr><tr><td><code>apiPassphrase</code></td><td>Sent alongside the signature. Shown <strong>once</strong>.</td></tr></tbody></table>

Put them in a `.env` file and keep it out of version control.

{% code title=".env" %}

```bash
STRIX_BASE_URL=https://api.strixlab.io/api
STRIX_API_KEY=...
STRIX_API_SECRET=...
STRIX_API_PASSPHRASE=...
```

{% endcode %}
{% endstep %}

{% step %}

### Create a client

{% code title="client.ts" %}

```ts
import { StrixClient } from 'strix-sdk';

export const client = new StrixClient({
  baseUrl:       process.env.STRIX_BASE_URL!,      // required — no default
  apiKey:        process.env.STRIX_API_KEY!,
  apiSecret:     process.env.STRIX_API_SECRET!,
  apiPassphrase: process.env.STRIX_API_PASSPHRASE!,
});

console.log('REST:', process.env.STRIX_BASE_URL, '· WS:', client.wsUrl);
```

{% endcode %}

{% hint style="danger" %}
`baseUrl` has no default and the client throws `StrixConfigError` without it. That is deliberate: a trading client that guesses its venue can point you at the wrong one silently. Mainnet is `https://api.strixlab.io/api`; testnet staging is `https://api-staging.strixlab.io/api`.
{% endhint %}
{% endstep %}

{% step %}

### Find something to trade

Every tradeable outcome is identified by a **`tokenId`**. Fetch one:

{% code title="find-market.ts" %}

```ts
import { client } from './client';
import { getTokenIds } from 'strix-sdk';

const { items } = await client.events.list({ status: 'open', limit: 5 });

for (const event of items) {
  console.log(`\n${event.title}  (tick ${event.tickSize})`);
  for (const market of event.markets) {
    const { yesTokenId, noTokenId } = getTokenIds(market);
    console.log(`  ${market.title ?? 'binary'}`);
    console.log(`    YES ${yesTokenId}`);
    console.log(`    NO  ${noTokenId}`);
  }
}
```

{% endcode %}
{% endstep %}

{% step %}

### Check the book, then place an order

{% code title="first-order.ts" %}

```ts
import { client } from './client';

const tokenId = '<paste a tokenId here>';

// 1. What can we buy at right now?
const book = await client.orderbook.snapshot(tokenId, { depth: 5 });
console.log('best bid', book.bids[0], '· best ask', book.asks[0]);

// 2. Rest a bid one tick below the touch — a maker order pays no fee.
const order = await client.orders.place({
  tokenId,
  side:      'BUY',
  price:     0.45,   // 45¢ · must be a multiple of the market's tickSize
  quantity:  100,    // shares · price × quantity must be ≥ $1.00
  orderType: 'GTC',
});

console.log('resting:', order.orderHash, order.status);   // "OPEN"

// 3. Changed your mind.
await client.orders.cancel(order.orderHash);
```

{% endcode %}

{% hint style="warning" %}
**The response is an acknowledgement, not a fill.** Matching and on-chain settlement are asynchronous (roughly 15–20 seconds), so a crossing order still comes back as `status: "OPEN"` with `filledQuantity: "0"`. Never read that as "it didn't fill" — watch the [WebSocket user channel](/typescript-sdk/websockets.md#your-orders-and-fills) instead.
{% endhint %}
{% endstep %}

{% step %}

### Watch your fills in real time

{% code title="watch.ts" %}

```ts
import { client } from './client';

client.ws.user.connect();

client.ws.user.on('order.update',  (o) => console.log(`order ${o.id} → ${o.status} (${o.filledQuantity} filled)`));
client.ws.user.on('trade.settled', (t) => console.log(`filled ${t.quantity} @ ${t.price} · tx ${t.txHash}`));
client.ws.user.on('error',         (e) => console.error('ws error:', e.message));

process.on('SIGINT', () => { client.destroy(); process.exit(0); });
```

{% endcode %}
{% endstep %}
{% endstepper %}

### Where to next

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Core Concepts</strong></td><td>What a <code>tokenId</code> actually is, and why YES and NO are one book.</td><td><a href="/get-started/concepts.md">Core Concepts</a></td></tr><tr><td><strong>Orders</strong></td><td>Order types, market orders, batching, and cancelling safely.</td><td><a href="/typescript-sdk/orders.md">Orders</a></td></tr><tr><td><strong>Market-Maker Bot</strong></td><td>Put it together into a bot that quotes both sides.</td><td><a href="/guides/market-maker-bot.md">Build a Market-Maker Bot</a></td></tr></tbody></table>
