# Configuration (https://docs.billwave.example/sdk/configuration)

Configuration [#configuration]

Configure the Billwave SDK with your API keys and environment settings.

Initialization [#initialization]

```ts
import { Billwave } from "@digvijay-x1/billwave";

const billwave = new Billwave({
  // billwave_sk_test_… selects sandbox, billwave_sk_live_… selects live
  secretKey: process.env.BILLWAVE_SECRET_KEY,
});
```

Configuration Options [#configuration-options]

| Option      | Type                  | Required | Description                                                                                                |
| ----------- | --------------------- | -------- | ---------------------------------------------------------------------------------------------------------- |
| `secretKey` | `string`              | ✅        | Your API secret key. Scoped keys (`billwave_sk_test_…` / `billwave_sk_live_…`) also select the environment |
| `mode`      | `"sandbox" \| "live"` | -        | Environment. Required for legacy (unscoped) keys; must agree with a scoped key                             |
| `apiUrl`    | `string`              | -        | Custom API URL for self-hosted deployments (stands in for `mode`)                                          |
| `debug`     | `boolean`             | -        | Enable debug logging                                                                                       |
| `catalog`   | `CatalogEntry[]`      | -        | Declarative plan/feature definitions                                                                       |

Environments [#environments]

Billwave has two fully isolated environments, each on its own host:

| Environment | Host                               | Key prefix          |
| ----------- | ---------------------------------- | ------------------- |
| **sandbox** | `https://sandbox.billwave.example` | `billwave_sk_test_` |
| **live**    | `https://api.billwave.example`     | `billwave_sk_live_` |

A key only works against its own environment — a sandbox key sent to the live API is rejected with `401 environment_mismatch` before anything is written. Every response also echoes where it landed: the `X-Billwave-Environment` header (`sandbox` or `live`) plus `X-Billwave-Organization`, and `check()`/`track()` results include `environment` in the body.

The SDK never defaults to live [#the-sdk-never-defaults-to-live]

The environment is resolved from, in order:

1. `apiUrl` — explicit host (self-hosted / local)
2. `mode` — explicit `"sandbox"` or `"live"`
3. the key prefix — `billwave_sk_test_…` → sandbox, `billwave_sk_live_…` → live

If none of these determine it (a legacy `billwave_sk_…` key with no `mode`), the client still constructs, but the **first request throws** an `BillwaveError` with code `config_error` instead of silently talking to production. If `mode` contradicts the key's scope, that is also a `config_error`.

```ts
// Scoped key: nothing else needed
const billwave = new Billwave({ secretKey: process.env.BILLWAVE_SECRET_KEY });
billwave.mode; // "sandbox" | "live", inferred from the key
billwave.apiUrl; // "https://sandbox.billwave.example/v1"

// Legacy key: say which environment you mean
const legacy = new Billwave({
  secretKey: process.env.BILLWAVE_SECRET_KEY, // billwave_sk_…
  mode: "sandbox",
});
```

Use the [dashboard](https://app.billwave.example) to create one key per environment; legacy keys keep working on both hosts but should be rotated.

Custom API URL [#custom-api-url]

For self-hosted deployments or custom endpoints, use `apiUrl`. This takes precedence over `mode`:

```ts
const billwave = new Billwave({
  secretKey: process.env.BILLWAVE_SECRET_KEY,
  apiUrl: "https://billing.mycompany.com",
  // mode is ignored when apiUrl is provided
});
```

URL Resolution Priority [#url-resolution-priority]

The SDK resolves the API URL in this order:

1. **Explicit `apiUrl`** (highest priority)
2. **`mode`** → `https://sandbox.billwave.example/v1` or `https://api.billwave.example/v1`
3. **Key prefix** → same hosts, inferred from `billwave_sk_test_` / `billwave_sk_live_`
4. Otherwise: **unresolved** — requests throw `config_error` (there is no default host)

Debug Mode [#debug-mode]

Enable debug mode for verbose logging:

```ts
const billwave = new Billwave({
  secretKey: process.env.BILLWAVE_SECRET_KEY,
  mode: "sandbox",
  debug: true,
});
```

With Catalog [#with-catalog]

Pass a declarative catalog for plan/feature management:

```ts
import { metered, boolean, plan } from "@digvijay-x1/billwave";

const billwave = new Billwave({
  secretKey: process.env.BILLWAVE_SECRET_KEY,
  mode: "live",
  catalog: [
    plan("pro", {
      name: "Pro",
      price: 2900,
      currency: "USD",
      interval: "monthly",
      features: [
        metered("api-calls").limit(10000),
        boolean("premium-support").enabled(),
      ],
    }),
  ],
});

// Sync catalog to server
await billwave.sync();
```

Runtime Configuration [#runtime-configuration]

Override configuration at runtime (useful for CLI tooling):

```ts
const billwave = new Billwave({
  secretKey: process.env.BILLWAVE_SECRET_KEY,
});

// Point at sandbox (both calls re-resolve billwave.mode / billwave.apiUrl)
billwave.setSecretKey(process.env.BILLWAVE_SANDBOX_SECRET_KEY);
billwave.setApiUrl("https://sandbox.billwave.example/v1");
```

Best Practices [#best-practices]

1. **Use environment variables** - Never hardcode API keys
2. **One scoped key per environment** - `billwave_sk_test_…` for sandbox, `billwave_sk_live_…` for live; the API refuses the wrong host
3. **Check the echo** - `X-Billwave-Environment` / `result.environment` tell you where a request actually landed
4. **Custom URL stands in for mode** - With `apiUrl`, `mode` is optional but must still agree with a scoped key

Examples [#examples]

Development Setup [#development-setup]

```ts
// config.ts
export const billwave = new Billwave({
  secretKey: process.env.BILLWAVE_SANDBOX_SECRET_KEY!,
  mode: "sandbox",
  debug: process.env.NODE_ENV === "development",
});
```

Production Setup [#production-setup]

```ts
// config.ts
export const billwave = new Billwave({
  secretKey: process.env.BILLWAVE_LIVE_SECRET_KEY!,
  mode: "live",
});
```

Dynamic Mode [#dynamic-mode]

```ts
// config.ts
const mode = process.env.BILLWAVE_MODE as "sandbox" | "live" | undefined;
const secretKey =
  mode === "sandbox"
    ? process.env.BILLWAVE_SANDBOX_SECRET_KEY
    : process.env.BILLWAVE_LIVE_SECRET_KEY;

export const billwave = new Billwave({
  secretKey: secretKey!,
  mode, // undefined is fine with scoped keys; a legacy key needs it set
});
```

Related [#related]

* [Catalog Sync](/sdk/catalog) - Define plans and features declaratively
* [Quickstart](/getting-started/quickstart) - Get started with Billwave