> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trycurious.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Install and configure the server SDK

> @trycurious/node: the server SDK for Node, Deno, Bun, Cloudflare Workers and Supabase Edge Functions. Install it, construct a client, and tune its options.

`@trycurious/node` runs on Node 22+, Deno, Bun, Cloudflare Workers and Supabase Edge Functions. It has no runtime dependencies and uses only web-standard `fetch`. Secret keys only: a publishable key is refused at construction with `invalid_key_type`. The browser package is `@trycurious/js`.

> [!NOTE]
>
> The package is built and tested but not yet published to npm. This page documents the surface it ships with.

## What it does for you

* `decide()` races the request against a deadline, serves your fallback when it passes or anything fails, never throws by default, and never retries, because a retried decide creates a second decision. [Decide](https://docs.trycurious.ai/sdks/node/decide.md).
* `track()` mints an idempotency id once per event and keeps it across every retry; `flush()` hands delivery to your runtime's lifecycle. [Events and identify](https://docs.trycurious.ai/sdks/node/events.md).
* `identify()` and `declare()` are ordered mutations: sent immediately, retried only on transient failures, and they throw a typed error.
* Types are generated from the API contract, every response's `X-Request-Id` is on the result, and no message ever contains a key, a user field, content or a raw body. [Errors](https://docs.trycurious.ai/sdks/node/errors.md).

## Install

```bash theme={null}
npm install @trycurious/node
```

```ts theme={null}
import { Curious } from "npm:@trycurious/node@0"; // Deno and Supabase Edge Functions; pin an exact version in production
```

## Construct

```ts theme={null}
import { Curious } from "@trycurious/node";

const curious = new Curious({
  apiKey: process.env.CURIOUS_SECRET_KEY!, // required, curious_sk_…
  decideTimeoutMs: 1500,                   // default
  onError(error) {
    logger.warn({ code: error.code, requestId: error.requestId }, "curious");
  },
});
```

Construct one client per process and reuse it: the event queue and the flush timer live on the instance.

## Options

| Option | Default | Meaning |
| - | - | - |
| `apiKey` | required | A secret key. Read it from the environment. |
| `baseUrl` | `https://api.trycurious.ai/v1` | Must be an `http(s)` URL. |
| `decideTimeoutMs` | `1500` | The decide deadline; the fallback serves when it passes. |
| `requestTimeoutMs` | `10000` | Deadline for events, identify and declare requests. |
| `region` | `"us-west-2"` | Sent as the `X-Region` header; `null` sends none. |
| `eventFlushSize` | `100` | Events per batch request, at most 200. |
| `eventFlushIntervalMs` | `5000` | How long a queued event waits before a flush on its own. |
| `eventQueueLimit` | `1000` | Beyond this, `track()` returns `{ queued: false }` and reports `queue_full`; nothing earlier is evicted. |
| `eventMaxAttempts` | `5` | Delivery attempts per event and per identify call. |
| `onError` | | Called with every failure the SDK absorbs, as a redacted summary. A throwing hook never breaks serving. |
| `onFlush` | | Called with each flush's summary. |
| `fetch` | global `fetch` | Inject for tests or unusual runtimes. |
| `throwOnError` | `false` | Expert: make `decide()` throw instead of serving the fallback. Never in a delivery path. |

Positive numbers are validated at construction; an invalid option throws `invalid_configuration` before any request is made.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.