---
title: "SDK client setup"
canonical: https://trickest.com/docs/developer-tools/sdk/client-setup
description: "TrickestClient options, authentication, per-request overrides, idempotency, and the shared http client."
---

# SDK client setup

## Create a client

```ts
import { TrickestClient } from "@trickest/sdk";

const client = new TrickestClient({
  token: process.env.TRICKEST_TOKEN,
  baseUrl: "https://trickest.io",
  wsUrl: process.env.TRICKEST_WS_URL, // optional; agent WebSocket
  debug: false,
  retry: true, // or { maxRetries: 5, baseDelay: 500 } or false
});
```

### `TrickestClientOptions`

| Option    | Source order                            | Default                                                                            |
| --------- | --------------------------------------- | ---------------------------------------------------------------------------------- |
| `token`   | `options.token` → `TRICKEST_TOKEN`      | **required**                                                                       |
| `baseUrl` | `options.baseUrl` → `TRICKEST_BASE_URL` | `https://trickest.io`                                                              |
| `wsUrl`   | `options.wsUrl` → `TRICKEST_WS_URL`     | derived from `baseUrl` (`/ws`, `ws`/`wss`)                                         |
| `debug`   | `options.debug`                         | `false`; logs requests to stderr                                                   |
| `retry`   | `options.retry`                         | `true`; see [Errors & pagination](/docs/developer-tools/sdk/errors-and-pagination) |

If no token is available, the constructor throws immediately:

```text
No API token provided. Pass { token } to TrickestClient or set TRICKEST_TOKEN environment variable.
```

### Authorization scheme

The SDK picks the header scheme from the token shape; you do not configure it:

- Token contains `.` → `Authorization: Bearer <token>` (JWT)
- Otherwise → `Authorization: Token <token>` (API token)

Use the public platform origin for `baseUrl`, without `/api`. The SDK appends
API paths. In a remote sandbox, `localhost` refers to that sandbox, not the
platform. Keep the client and its token out of browser components.

## Lazy service namespaces

The client creates each service on **first access** and reuses it:

```ts
const me = await client.users.getMe(); // constructs UsersService once
const again = await client.users.getMe(); // reuses cached service
```

Access services through `client.*`; see the [method index](/docs/developer-tools/sdk/method-index).

## Per-request options (`RequestOptions`)

Most service methods accept a trailing `RequestOptions` object. Some combine
request and operation options: `runs.execute(workflowId, { inputs, retry })`
takes one options object, not a third argument. Check the method signature.

This example assumes a configured `client` and a caller-supplied `workflowId`:

```ts
import { z } from "zod";

const abortController = new AbortController();
const MyWorkflowSchema = z.object({ id: z.string(), name: z.string() });

await client.workflows.get(workflowId, {
  token: process.env.OTHER_USER_TOKEN, // override client token for this call
  timeout: 60_000,
  signal: abortController.signal,
  retry: false,
  headers: { "X-Custom": "value" },
  schema: MyWorkflowSchema, // Zod; parse response before return
});
```

| Field            | Purpose                                                                                           |
| ---------------- | ------------------------------------------------------------------------------------------------- |
| `timeout`        | Fetch timeout in ms (default 30_000); not an overall workflow deadline                            |
| `signal`         | `AbortSignal` for cancellation                                                                    |
| `retry`          | Override client retry for this request                                                            |
| `token`          | Act as a different user for one call                                                              |
| `schema`         | Zod schema; `schema.parse(body)` on success                                                       |
| `idempotencyKey` | Sends `Idempotency-Key` and permits write retries; server-side deduplication depends on the route |

### Idempotency

```ts
import { generateIdempotencyKey } from "@trickest/sdk";

const key = generateIdempotencyKey();
// Reuse one key for retries of this logical operation.
await client.workflows.create(
  spaceId,
  { name: "Research" },
  {
    idempotencyKey: key,
    retry: false,
  },
);
```

A key is a request header, not a client-side response cache. Confirm that the
write endpoint supports deduplication before enabling retries. The example
disables automatic retries; reusing the key alone cannot guarantee that a
server will avoid duplicate writes.

The client clears the HTTP timeout when response headers arrive. It does not
limit the time spent reading the response body. A response schema can throw a Zod error;
it does not change the method's declared TypeScript return type.

## `client.http`

The public `HttpClient` on `client.http` is what every service shares. Use it for ad-hoc
routes not wrapped by a namespace, streaming downloads, or custom pagination:

```ts
const raw = await client.http.get<unknown>("/api/auth/session");
console.log(raw);
```

Prefer the per-service `listPage` helpers for one page of results:

```ts
const { results: spaces } = await client.spaces.listPage({ pageSize: 10 });
```

For an unwrapped namespace route, call `client.http.get` and parse the page
yourself. There is no top-level `listPage` export.

Keep `client.http` calls on your trusted platform origin. These helpers attach
the configured token even when given an absolute URL. Use a separate `fetch`
without platform credentials for third-party URLs.

## Vault ID

Many calls are vault-scoped (memory, skills, audit, billing). Resolve your vault from the
session endpoint. The type below describes the fields this example reads;
validate external responses if your application requires a strict contract:

```ts
const session = await client.http.get<{
  user: { profile?: { vault_info?: { id?: string } } };
}>("/api/auth/session");
const vaultId = session.user?.profile?.vault_info?.id;
if (!vaultId) throw new Error("Session did not return a vault ID");
```

## Related

<CardGroup cols={2}>
  <Card
    title="Errors & pagination"
    icon="book"
    href="/docs/developer-tools/sdk/errors-and-pagination"
  >
    Error classes, retries, `list` vs `listPage`.
  </Card>
  <Card title="Sessions" icon="robot" href="/docs/developer-tools/sdk/sessions">
    `wsUrl` and `SessionHandle` for the agent.
  </Card>
</CardGroup>

---
_Markdown source of https://trickest.com/docs/developer-tools/sdk/client-setup._
