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

# Advanced

> Configure SDK clients, retries, errors, logging, and raw responses.

Use this page when you need to tune SDK behavior beyond the default authenticated setup. Options apply to both the TypeScript and Python SDKs; where they differ, both are shown.

## Client options

<CodeGroup>
  ```ts TypeScript theme={null}
  import Crosmos from "crosmos";

  const client = new Crosmos({
  	apiKey: process.env.CROSMOS_API_KEY,
  	baseURL: "https://api.crosmos.dev",
  	timeout: 60_000,
  	maxRetries: 2,
  });
  ```

  ```python Python theme={null}
  from crosmos import Crosmos

  client = Crosmos(
      api_key="csk_...",
      base_url="https://api.crosmos.dev",
      timeout=60.0,  # seconds, not milliseconds
      max_retries=2,
  )
  ```
</CodeGroup>

Python uses snake\_case equivalents: `apiKey` → `api_key`, `baseURL` → `base_url`, `maxRetries` → `max_retries`.

| Option                               | Description                                                    | Default                                         |
| ------------------------------------ | -------------------------------------------------------------- | ----------------------------------------------- |
| `apiKey` / `api_key`                 | JWT access token or Crosmos API key.                           | `CROSMOS_API_KEY`                               |
| `baseURL` / `base_url`               | API base URL.                                                  | `CROSMOS_BASE_URL` or `https://api.crosmos.dev` |
| `timeout`                            | Request timeout. TypeScript: milliseconds. Python: seconds.    | `60000` / `60.0`                                |
| `maxRetries` / `max_retries`         | Retry attempts for transient failures.                         | `2`                                             |
| `fetch` / `http_client`              | Custom HTTP client. TypeScript: fetch. Python: `httpx.Client`. | global `fetch` / `httpx.Client`                 |
| `defaultHeaders` / `default_headers` | Headers sent with every request.                               | none                                            |
| `defaultQuery` / `default_query`     | Query parameters sent with every request.                      | none                                            |
| `logLevel`                           | SDK log level (TypeScript only).                               | `CROSMOS_LOG` or `warn`                         |
| `logger`                             | Logger instance (TypeScript only).                             | `console`                                       |

## Environment variables

| Variable                 | Description                                                           |
| ------------------------ | --------------------------------------------------------------------- |
| `CROSMOS_API_KEY`        | API key used when `apiKey` / `api_key` is not passed directly.        |
| `CROSMOS_BASE_URL`       | API base URL used when `baseURL` / `base_url` is not passed directly. |
| `CROSMOS_LOG`            | Log level: `debug`, `info`, `warn`, `error`, or `off`.                |
| `CROSMOS_CUSTOM_HEADERS` | Newline-separated custom headers in `Name: value` format.             |

<Note>
  The SDK uses `CROSMOS_BASE_URL`. The MCP server uses `CROSMOS_API_BASE_URL`.
</Note>

## Per-request options

Most SDK methods accept per-request overrides.

<CodeGroup>
  ```ts TypeScript theme={null}
  const search = await client.search.hybrid(
  	{
  		space_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  		query: "What does the user prefer for TypeScript projects?",
  	},
  	{
  		timeout: 10_000,
  		maxRetries: 5,
  		headers: {
  			"X-Request-Source": "agent-worker",
  		},
  	},
  );
  ```

  ```python Python theme={null}
  search = client.search.hybrid(
      space_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      query="What does the user prefer for TypeScript projects?",
      timeout=10.0,
      max_retries=5,
      extra_headers={"X-Request-Source": "agent-worker"},
  )
  ```
</CodeGroup>

Use `AbortController` (TypeScript) or `client.with_options()` (Python) when you need to cancel a request or create a scoped client copy:

<CodeGroup>
  ```ts TypeScript theme={null}
  const controller = new AbortController();

  const request = client.search.hybrid(
  	{
  		space_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  		query: "What changed since yesterday?",
  	},
  	{
  		signal: controller.signal,
  	},
  );

  controller.abort();

  await request;
  ```

  ```python Python theme={null}
  scoped = client.with_options(max_retries=5, timeout=10.0)

  search = scoped.search.hybrid(
      space_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      query="What changed since yesterday?",
  )
  ```
</CodeGroup>

## Retries and timeouts

The SDK retries transient failures twice by default with exponential backoff and jitter.

Retries apply to connection errors, request timeouts, `408`, `409`, `429`, and `5xx` responses.

Disable retries globally:

<CodeGroup>
  ```ts TypeScript theme={null}
  const client = new Crosmos({
  	maxRetries: 0,
  });
  ```

  ```python Python theme={null}
  client = Crosmos(max_retries=0)
  ```
</CodeGroup>

Tune retries for one request:

<CodeGroup>
  ```ts TypeScript theme={null}
  await client.search.hybrid(
  	{
  		space_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  		query: "What does the user remember about Austin?",
  	},
  	{
  		maxRetries: 4,
  	},
  );
  ```

  ```python Python theme={null}
  client.search.hybrid(
      space_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      query="What does the user remember about Austin?",
      max_retries=4,
  )
  ```
</CodeGroup>

## Handling errors

<CodeGroup>
  ```ts TypeScript theme={null}
  try {
  	const search = await client.search.hybrid({
  		space_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  		query: "What is the user's preferred editor?",
  	});

  	console.log(search.candidates);
  } catch (error) {
  	if (error instanceof Crosmos.APIError) {
  		console.log(error.status);
  		console.log(error.name);
  		console.log(error.headers);
  		console.log(error.error);
  		throw error;
  	}

  	throw error;
  }
  ```

  ```python Python theme={null}
  from crosmos import APIError

  try:
      search = client.search.hybrid(
          space_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          query="What is the user's preferred editor?",
      )

      print(search.candidates)
  except APIError as e:
      print(e.status_code)
      print(e.message)
      raise
  ```
</CodeGroup>

| Status      | Error class                                         |
| ----------- | --------------------------------------------------- |
| `400`       | `BadRequestError`                                   |
| `401`       | `AuthenticationError`                               |
| `403`       | `PermissionDeniedError`                             |
| `404`       | `NotFoundError`                                     |
| `409`       | `ConflictError`                                     |
| `422`       | `UnprocessableEntityError`                          |
| `429`       | `RateLimitError`                                    |
| `>=500`     | `InternalServerError`                               |
| no response | `APIConnectionError` or `APIConnectionTimeoutError` |

## Raw responses

Every resource method returns a typed response. Use helper methods when you need the underlying HTTP response.

<CodeGroup>
  ```ts TypeScript theme={null}
  const { data, response } = await client.search
  	.hybrid({
  		space_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  		query: "What does the user prefer?",
  	})
  	.withResponse();

  console.log(data.candidates);
  console.log(response.headers);
  ```

  ```python Python theme={null}
  response = client.search.with_raw_response.hybrid(
      space_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      query="What does the user prefer?",
  )

  print(response.headers.get("X-Request-Id"))
  search = response.parse()  # returns typed Search object
  print(search.candidates)
  ```
</CodeGroup>

Use `.asResponse()` (TypeScript) or `.with_streaming_response` (Python) when you only need the raw response without parsing:

<CodeGroup>
  ```ts TypeScript theme={null}
  const response = await client.search
  	.hybrid({
  		space_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  		query: "What does the user prefer?",
  	})
  	.asResponse();

  console.log(response.status);
  ```

  ```python Python theme={null}
  with client.search.with_streaming_response.hybrid(
      space_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      query="What does the user prefer?",
  ) as response:
      print(response.status_code)
      for line in response.iter_lines():
          print(line)
  ```
</CodeGroup>

## Pydantic responses

Python response objects are Pydantic models. Use `.to_dict()` and `.to_json()` to serialize them.

```python theme={null}
search = client.search.hybrid(
    space_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    query="What does the user prefer?",
)

data = search.to_dict()    # dict
json_str = search.to_json()  # JSON string
```

## Custom HTTP client

<CodeGroup>
  ```ts TypeScript theme={null}
  import Crosmos from "crosmos";
  import fetch from "my-fetch";

  const client = new Crosmos({
  	fetch,
  });
  ```

  ```python Python theme={null}
  import httpx
  from crosmos import Crosmos, DefaultHttpxClient

  client = Crosmos(
      http_client=DefaultHttpxClient(
          proxy="http://my.proxy:8080",
          transport=httpx.HTTPTransport(local_address="0.0.0.0"),
      ),
  )
  ```
</CodeGroup>

Use `fetchOptions` (TypeScript) for runtime-specific transport settings:

```ts theme={null}
const client = new Crosmos({
	fetchOptions: {
		// Runtime-specific RequestInit options go here.
	},
});
```

## Runtime support

**TypeScript:** Uses the runtime's global `fetch` implementation by default. Supports modern browsers, Node.js 20 LTS or later, Bun 1.0 or later, Deno 1.28 or later, Cloudflare Workers, Vercel Edge Runtime, Jest with the `node` environment, and Nitro 2.6 or later. React Native is not supported.

**Python:** Supports Python 3.8 and later. Uses `httpx` for HTTP transport and `pydantic` for response validation. The `AsyncCrosmos` client uses `anyio` and is compatible with `asyncio` and `trio`. An optional `aiohttp` backend is available for projects already using `aiohttp`:

```python theme={null}
from crosmos import AsyncCrosmos, DefaultAioHttpClient

async with AsyncCrosmos(http_client=DefaultAioHttpClient()) as client:
    search = await client.search.hybrid(
        space_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        query="What does the user prefer?",
    )
```
