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

# Client configuration

> Create a Kardinal SDK client, pass your API key safely, switch between sandbox and production, and tune request timeouts and retries in Python or TypeScript.

## Creating a client

Every call goes through a client, created once and reused:

<CodeGroup>
  ```python Python theme={null}
  from kardinal import Kardinal

  k = Kardinal()  # api_key=None, base_url=None, timeout=30, max_retries=3
  ```

  ```ts TypeScript theme={null}
  import { Kardinal } from "@kardinal-ai/sdk";

  const k = new Kardinal(); // { apiKey, baseUrl, timeoutMs: 30_000, maxRetries: 3 }
  ```
</CodeGroup>

| Python | TypeScript | Environment variable | Default |
| - | - | - | - |
| `api_key` | `apiKey` | `KARDINAL_API_KEY` | None: required |
| `base_url` | `baseUrl` | `KARDINAL_BASE_URL` | `https://app.kardinal.ai/api/v2` |
| `timeout` (seconds) | `timeoutMs` (milliseconds) | — | 30 seconds |
| `max_retries` | `maxRetries` | — | 3 |
| — | `onWarning` | — | `console.warn` |

## API key resolution

An argument passed to the client wins over the environment variable, which wins over the default. Prefer the environment variable, or a value read from your secrets manager at startup, over a key written in the code.

Without a usable key, creating the client fails before any request:

* no key at all, neither as an argument nor in `KARDINAL_API_KEY`: `MissingApiKeyError`;
* an empty string passed explicitly: `EmptyApiKeyError`, rather than a silent fallback to the environment variable.

## Keeping the key server-side

An API key gives full access to its agency's plans, and is valid for 366 days. Use it from a server, a worker, or a script, never from code that runs in a browser or a mobile app:

* Never put the key in a front-end bundle. Frameworks copy into the bundle every environment variable with a public prefix, such as `NEXT_PUBLIC_`, `VITE_`, or `PUBLIC_`: name the variable `KARDINAL_API_KEY`, without such a prefix.
* Don't call the API from a browser at all. The TypeScript SDK targets Node.js only, and the API doesn't answer cross-origin requests.
* If a front end needs routes, expose your own endpoint that calls Kardinal from your server.

See [Storing your token](/guides/authentication#storing-your-token) for rotation and secrets management.

## Sandbox and production

Sandbox and production are two agencies of the same account, served by the same host: the key alone decides which agency a call applies to. Switching to production means switching the key, not the code — keep one `KARDINAL_API_KEY` value per deployment environment.

You don't need to set `base_url` / `baseUrl` or `KARDINAL_BASE_URL`: the default is the public API. See [Moving from sandbox to production](/guides/sandbox-to-production) for what else differs between the two agencies.

## Timeouts and retries

<Tabs>
  <Tab title="Python">
    `timeout`, in seconds, is passed to `httpx`, which applies it to each phase of a request separately (connecting, sending, each read of the response), not to the request as a whole.
  </Tab>

  <Tab title="TypeScript">
    `timeoutMs`, in milliseconds, is one deadline for the whole request, reading the response included.
  </Tab>
</Tabs>

`max_retries` / `maxRetries` is how many times a read, `update`, `delete`, `start`, or `stop` is retried after a network error, a `429`, or a `5xx`. `submit` is never retried: see [What the SDKs retry](/sdks/errors-and-warnings#what-the-sdks-retry).

## Closing the client

<Tabs>
  <Tab title="Python">
    The client holds an `httpx` connection pool. Use it as a context manager, or close it when you're done:

    ```python theme={null}
    with Kardinal() as k:
        plans = k.routing.plans.list()

    k = Kardinal()
    plans = k.routing.plans.list()
    k.close()
    ```
  </Tab>

  <Tab title="TypeScript">
    There's nothing to close: requests go through the `fetch` built into Node.js, with no connection pool of the SDK's own.
  </Tab>
</Tabs>

## Troubleshooting authentication

| Symptom | Likely cause | What to do |
| - | - | - |
| `MissingApiKeyError` when creating the client | `KARDINAL_API_KEY` isn't set in the environment the code runs in | Set it, or pass the key explicitly |
| `KardinalAuthError` on the first call | The key is invalid, expired, revoked, or was sent to a host it wasn't issued for | Run `kardinal auth check`; generate a new key in the Console if needed; leave `base_url` / `baseUrl` unset |
| Calls succeed, but your plans aren't where you expect | The key belongs to the other agency (`sandbox` instead of `production`, or the reverse) | `kardinal auth check` shows the agency of the key in use |

[`kardinal auth check`](/sdks/cli#authentication) reads the same environment variables as the client, so it diagnoses exactly the configuration your code runs with.


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