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

# LuminaClient

> The top-level client and its sub-resources.

## Construction

```ts theme={null}
import { LuminaClient } from '@lumina-org/sdk'

const lumina = new LuminaClient({
  apiKey: process.env.LUMINA_API_KEY!,
  apiUrl: 'https://lumina-api-production-ac85.up.railway.app',  // optional, this is the default
})
```

Construction is synchronous and never makes a network call. Call `.health()`
to verify the API is reachable.

### Constructor signature

```ts theme={null}
new LuminaClient({
  apiKey: string,          // required; pass "" for onboard / sandbox / health
  apiUrl?: string,         // defaults to https://lumina-api-production-ac85.up.railway.app
})
```

## `lumina.health()`

Returns API status, on-chain block height, and the canonical contract
address book. Public — no API key required.

```ts theme={null}
const health = await lumina.health()
//   {
//     status: 'ok',
//     chain: { chainId: 8453, blockNumber: 21345678 },
//     contracts: { bondVault, coverRouter, luminaOracleV2, marketplace, … },
//     version: 'V5.4',
//   }
```

## `lumina.getContracts()`

Cached, health-derived address book. First call hits `/health`; subsequent
calls return the cached map for the lifetime of the `LuminaClient`
instance.

```ts theme={null}
const c = await lumina.getContracts()
c.bondVault           // BondVault SET C address
c.coverRouter         // CoverRouter address
c.luminaOracleV2      // LuminaOracleV2 (TWAP) address
c.marketplace         // LuminaBondMarketplace address
```

Introduced in 0.5.2; unchanged in 0.6.0. Prefer this over hard-coding
addresses in your bot — redeployments propagate without an SDK bump.

## Sub-resources

| Property             | Class            | Endpoints                                                       |
| -------------------- | ---------------- | --------------------------------------------------------------- |
| `lumina.products`    | `ProductsAPI`    | `GET /products`, `GET /products/:id`, `GET /products/:id/quote` |
| `lumina.policies`    | `PoliciesAPI`    | `GET/POST /api/v1/policies`, `GET /policies/:prod/:id`          |
| `lumina.bonds`       | `BondsAPI`       | `GET /api/v1/bonds`, `POST /api/v1/bonds/redeem`                |
| `lumina.marketplace` | `MarketplaceAPI` | `GET /api/v1/marketplace/listings`                              |
| `lumina.agent`       | `AgentAPI`       | `POST /api/v1/agent/onboard`, `GET/DELETE /api/v1/agent/keys`   |
| `lumina.webhooks`    | `WebhooksAPI`    | `POST/GET/DELETE /api/v1/webhooks`                              |
| `lumina.sandbox`     | `SandboxAPI`     | `GET /sandbox/info`, `POST /sandbox/try`                        |

## Errors

Every non-2xx response throws `LuminaError`:

```ts theme={null}
import { LuminaError } from '@lumina-org/sdk'

try {
  await lumina.policies.purchase({ … })
} catch (err) {
  if (err instanceof LuminaError) {
    err.status   // HTTP status code (number)
    err.code     // API error code (string), e.g. 'invalid_api_key'
    err.message  // human-readable message
  }
}
```

Network-level errors (connection refused, timeout) are also wrapped as
`LuminaError` with `status === 0` and `code === 'network_error'`.

## Custom fetch (advanced)

Both Node 18+ and modern browsers ship `globalThis.fetch`, which is what the
SDK uses. There's no override hook on the client itself; if you need to
intercept requests (for instrumentation, mock-in-test, etc.) overwrite
`globalThis.fetch` before constructing the client.
