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

# Configuration and errors

> Authentication, workspace access, custom domains, request controls and troubleshooting

## Configure a client

```typescript theme={null}
import { Famulor } from 'famulor-sdk';

const client = new Famulor({
  apiKey: process.env.FAMULOR_API_KEY,
  baseUrl: 'https://app.famulor.io/api/v1',
  timeoutMs: 90_000,
  maxRetries: 2,
});
```

| Option | Default | Purpose |
| - | - | - |
| `apiKey` | — | Workspace API key. Use this or `accessToken`, exactly one. |
| `accessToken` | — | OAuth access token, or a function returning one synchronously or asynchronously. |
| `baseUrl` | `https://app.famulor.io/api/v1` | Full API base URL, including `/api/v1`. Use HTTPS for your hosted application. |
| `timeoutMs` | `90000` | Deadline for the whole request, including authentication, retries, waits and response reads, in milliseconds. |
| `maxRetries` | `2` | Maximum additional attempts for eligible reads. `0` disables retries. |
| `fetch` | Runtime `fetch` | Optional compatible Fetch implementation for server integrations or tests. |

The SDK does not read environment variables itself. In these examples, your application passes the credential from `process.env`.

## OAuth access tokens

For an application acting on behalf of a user, supply `accessToken` instead of `apiKey`. A callback can retrieve the current token before a request:

```typescript theme={null}
import { Famulor } from 'famulor-sdk';

const client = new Famulor({
  accessToken: async () => {
    const token = process.env.FAMULOR_ACCESS_TOKEN;
    if (!token) throw new Error('An OAuth access token is required.');
    return token;
  },
});

const { data } = await client.assistants.list({ limit: 10 });
console.log(data.length);
```

This example reads a token already supplied to the server. For a production integration, replace that lookup with your server's token store and refresh logic. The SDK does not run the OAuth consent flow or refresh tokens for you. See [OAuth client requirements](/api-reference/introduction#oauth-client-requirements).

OAuth requests follow the user's current workspace membership, role and approved scopes. API keys follow their own workspace, status and scopes. API Access is required for both. Do not supply both credential options.

## Timeouts and cancellation

Client defaults apply to every operation. Pass `timeoutMs`, `maxRetries` or `signal` in the last argument, after the method’s inputs, to override one request. For generated `client.api` methods, this is the second argument; resource shortcuts can place it first, second or third. See [Request option examples](/sdk/usage#override-one-request). The timeout covers the whole request, including token resolution, retries, retry delays and response reads. An `AbortSignal` lets your application cancel it earlier.

```typescript theme={null}
const controller = new AbortController();

const pending = client.calls.list(
  { limit: 10 },
  { signal: controller.signal, timeoutMs: 10_000, maxRetries: 0 },
);

controller.abort();

try {
  await pending;
} catch (error) {
  if (!controller.signal.aborted) throw error;
}
```

Cancelling a request stops waiting for its response. It does not undo an API action already accepted by the server.

## Retry behavior

Eligible **GET and HEAD** requests can be retried after a network failure or HTTP `429`, `502`, `503` or `504`. The SDK honors `Retry-After` when present and uses bounded backoff otherwise.

**Write requests are never retried automatically**, including after a rate limit. Raising `maxRetries` does not enable write retries. This protects actions such as placing calls, sending messages and purchasing resources from accidental duplication.

<Warning>
  A timeout or lost connection after a write can leave its outcome unknown. Check the resource state, call history or webhook before deciding to repeat the action. An arbitrary idempotency header does not make every operation safe to repeat.
</Warning>

## Handle errors

```typescript theme={null}
import {
  Famulor,
  FamulorApiError,
  FamulorNetworkError,
  FamulorTimeoutError,
} from 'famulor-sdk';

const client = new Famulor({ apiKey: process.env.FAMULOR_API_KEY });

try {
  const { data } = await client.assistants.list({ limit: 10 });
  console.log(data.length);
} catch (error) {
  if (error instanceof FamulorApiError) {
    console.error({
      status: error.status,
      code: error.code,
      message: error.message,
      requestId: error.requestId,
      retryAfter: error.retryAfter,
    });
  } else if (error instanceof FamulorTimeoutError) {
    console.error('Request timed out.', error.mayHaveExecuted);
  } else if (error instanceof FamulorNetworkError) {
    console.error('Network request failed.', error.mayHaveExecuted);
  } else {
    throw error;
  }
}
```

| Error | Meaning |
| - | - |
| `FamulorApiError` | The API returned a failure response. Inspect `status`, `code`, `message`, `requestId` and optional `retryAfter` in seconds. |
| `FamulorNetworkError` | A response could not be obtained. `mayHaveExecuted` indicates that a write may already have reached the server. |
| `FamulorTimeoutError` | The SDK's timeout expired. This extends `FamulorNetworkError`; check it first if handling timeouts separately. |
| `FamulorAbortError` | Your `AbortSignal` cancelled the request. A previously accepted write may still execute. |
| `FamulorResponseError` | The response cannot be decoded or does not have the expected pagination structure. Check `mayHaveExecuted` before repeating a write. |
| `FamulorError` | Base SDK error, also used for invalid local configuration or request parameters. |

Do not log credentials or whole sensitive request bodies. A request ID, when available, helps support locate the failed request.

## Troubleshooting

| Symptom | What to check |
| - | - |
| `401` | Check that the correct key or current OAuth token is supplied and has not been revoked or expired. |
| `403 api_access_required` | Enable API Access through the workspace plan or an add-on. |
| Other `403` | Check the operation's required scopes, the user's role and the workspace's feature access. The SDK does not bypass those checks. |
| `404` | Confirm the ID exists in the credential's workspace. A resource in another workspace is not accessible. |
| `429` | Respect `retryAfter`, reduce concurrency and avoid frequent polling. Extra keys do not increase the workspace's shared budget. |
| Call creation fails | Confirm the assistant is active, has an outbound-capable number and sufficient credits, and can call the intended destination. |
| Network or timeout error after a write | Verify whether the action occurred before repeating it. |
| Browser import is rejected | Move the SDK to your backend. For website conversations, use the [Web widget](/web-widget). |

Check the same credential independently with the [CLI](/cli/overview):

```bash theme={null}
famulor doctor
famulor list-assistants --limit 10
```

For HTTP behavior and scope requirements, consult the [REST API reference](/api-reference/introduction). For AI tool connections, use the [MCP guide](/mcp/overview).


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