> ## 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.

# API introduction

> Authenticate with the REST API and start building

The Famulor REST API lets you manage the same customer resources available in the dashboard, including assistants, calls, campaigns, transcripts, knowledge, and workspace settings.

<Tip>
  For a multi-step business process — enrich a lead, then call, then update a CRM, then notify a channel — an [Automation](/automations/overview) is often less code to maintain than wiring the steps together yourself. Reach for the API directly when you need simple, immediate, programmatic control, like triggering a single call from your own app.
</Tip>

## Base URL

```text theme={null}
https://app.famulor.io/api/v1
```

If you use a white-label domain, replace `app.famulor.io` with that domain. The paths stay the same.

## API Access

REST requests require **API Access** through your workspace plan or a recurring add-on. If access is removed, existing API keys and OAuth credentials stay available to workspace administrators for review and revocation, but regular `/api/v1` requests return `403 api_access_required`.

After a failed plan payment, `POST /api/v1/billing/invoice-payment` and `POST /api/v1/billing/portal` remain available with a valid credential so an owner can recover billing. Authentication, role, and scope checks still apply.

## Authentication

Send a Bearer token in the `Authorization` header:

```bash theme={null}
curl https://app.famulor.io/api/v1/assistants \
  -H "Authorization: Bearer fam_XXXXXXXXXXXX"
```

Two credential types are supported:

* **Workspace API keys** (`fam_...`) — create them under **Settings → API & MCP** for server-to-server integrations. The full key is shown once. The dashboard has no scope picker, so a key created there always carries every scope. To mint a narrower key, call `POST /api/v1/api-keys` or `POST /api/v1/workspaces/{workspace_id}/api-keys` with an explicit `scopes` array — the new key's scopes must be a subset of the credential that creates it.
* **OAuth 2.0 access tokens** (`fam_at_...`) — use Authorization Code with PKCE-S256 for applications acting on behalf of a signed-in user.

User-authorised access follows the user's current workspace membership and role. Workspace API keys continue to follow their own status and scopes until an authorised workspace admin revokes them.

<Warning>
  Treat API keys like passwords. Never embed them in browser or mobile application code; use OAuth for user-facing applications.
</Warning>

### Key hygiene

* Store keys in environment variables or a secrets manager, never in source control.
* Scope each key to only what the integration needs — a key that only reads calls shouldn't also have `assistants:write`. Dashboard-created keys are always full-access; use the API path above to mint a scoped one.
* Rotate keys periodically and immediately after anyone with access to one leaves the team.
* Revoking a key from **Settings → API & MCP** takes effect immediately; requests already in flight may still complete.

### OAuth client requirements

A hand-built client drives the authorization and token endpoints directly:

```text theme={null}
https://app.famulor.io/api/oauth/authorize
https://app.famulor.io/api/oauth/token
```

Use HTTPS redirect URLs. Native applications may also use literal loopback HTTP addresses such as `127.0.0.1`. OAuth authorization requests must use PKCE-S256 and request only scopes registered for the client. When a request is rate-limited, retry after the delay indicated by the response.

The client either uses credentials pre-approved for your workspace, or registers itself dynamically with `POST /api/oauth/register` — supply between 1 and 10 unique `redirect_uris`. Endpoints, supported scopes, and grant types are discoverable at `/.well-known/oauth-authorization-server`.

A dynamically registered client that the user has not approved yet does not receive errors on its redirect URL: an invalid authorization request is answered on the authorization page instead. Once approved, later sign-ins receive only the tool groups the user selected; asking for more shows the consent screen again.

Access tokens are renewed with the `refresh_token` grant. Refresh tokens rotate on every use: requesting a new access token also issues a new refresh token and immediately invalidates the one you sent.

## Response format

Successful responses wrap the result in `data` and may include `meta`:

```json theme={null}
{
  "data": [{ "id": "…", "name": "Support Agent" }],
  "meta": { "pagination": { "limit": 50, "offset": 0, "total": 1 } }
}
```

Responses contain customer-facing workspace data only. Secrets are never returned after they are saved, and sensitive values are masked where useful. Recordings are provided through temporary links. Usage and billing are reported in the minutes and credits shown in your account.

## Pagination

List endpoints use `limit` and `offset`:

| Parameter | Default | Maximum | Description |
| - | - | - | - |
| `limit` | `50` | `200` | Number of items to return |
| `offset` | `0` | — | Number of items to skip |

Use `meta.pagination.total` to determine whether more pages are available.

## Errors

Failures return a stable code and a readable message:

```json theme={null}
{
  "error": {
    "code": "invalid_request",
    "message": "A destination phone number is required."
  }
}
```

| Status | Code | Meaning |
| - | - | - |
| `400` | `invalid_request` | Invalid request body or parameters |
| `401` | `unauthorized` | Missing, invalid, expired, or revoked credential |
| `403` | `forbidden` | The scope, role, or plan does not allow the action |
| `403` | `api_access_required` | API Access is not available for this workspace |
| `404` | `not_found` | Resource not found or not visible to this workspace |
| `409` | `conflict` | The resource is in a conflicting state |
| `429` | `rate_limited` | Too many requests; wait and retry |
| `500` | `internal_error` | Unexpected error |

## White-label customer management

Authorised resellers can use the `platform` endpoints to manage their own end customers, issue and revoke customer API tokens, transfer credits, and manage their custom domain. These endpoints require the `platform:read` or `platform:write` scopes; custom-domain operations use the corresponding settings scope.

| Endpoint | Purpose |
| - | - |
| `GET /api/v1/platform/users` | List your end customers |
| `POST /api/v1/platform/users` | Register an end customer |
| `GET /api/v1/platform/users/{user_id}` | Read an end customer's account summary |
| `POST /api/v1/platform/users/{user_id}/token` | Issue an API token for that customer |
| `POST /api/v1/platform/users/login` | Authenticate a customer |
| `POST /api/v1/platform/users/{user_id}/logout` | Revoke that customer's API tokens |
| `POST /api/v1/platform/users/{user_id}/balance` | Transfer credits between your reseller balance and the customer |
| `GET /api/v1/custom-domain` | Read custom-domain status |
| `POST /api/v1/custom-domain` | Add a custom domain and receive the required DNS records |
| `POST /api/v1/custom-domain/verify` | Check DNS and activate a ready domain |
| `DELETE /api/v1/custom-domain` | Remove the custom domain |

See the [White Label API guide](/admin/whitelabel-api) for examples.

## CLI

Every API operation is also a command in the [Famulor CLI](/cli/overview), with your API key stored in the system keychain:

```bash theme={null}
npm install --global famulor
famulor auth login
famulor list-assistants --output table
```

The CLI uses the same API keys, scopes, API Access and rate limits as the REST API.

## MCP

The same customer-facing capabilities are available as AI tools through the [MCP endpoint](/mcp/overview):

```text theme={null}
https://app.famulor.io/mcp
```

MCP uses the same API keys, OAuth consent, scopes, and workspace access. Its availability is controlled separately by **Connect AI / MCP**, not by API Access.

## Realtime variants and native voices

Create or update an assistant with `mode: "realtime"` and `realtime_variant: "full_duplex"` to opt in when your workspace has access. Omitting the variant keeps Standard for new assistants and preserves it on updates. The reasoning model is managed centrally; assistant Pipeline model preferences do not override it.

Use `GET /api/v1/voices?mode=realtime&realtime_variant=full_duplex` to discover compatible voices. Pass a returned voice `id` as `realtime_voice`; Full Duplex also uses it for greetings, consent and tool announcements. Keep `tts_voice` as the saved Pipeline fallback voice. Uploaded greeting audio keeps its recorded voice. Voice identifiers are opaque; never infer a provider from an identifier. An unavailable voice or variant is rejected.

For TTS voices, use `GET /api/v1/voices?mode=tts&language=de` and omit `realtime_variant`. Combining `mode=tts` with any realtime variant returns `400`. In the CLI: `famulor list-voices --mode tts --language de`; for Full Duplex: `famulor list-voices --mode realtime --realtime-variant full_duplex --language de`.

When a recorded native sample is available, `preview_url` is a relative API path. Resolve it against your API origin and download it with the same Bearer token and `voices:read` scope. `GET /api/v1/voices/{id}/preview?realtime_variant=full_duplex` returns WAV audio without generating a new sample. The MCP voice catalog includes the same preview reference.

Stored TTS samples use `GET /api/v1/voices/{id}/preview?mode=tts`, or `famulor get-voice-preview --id <voice-id> --mode tts` in the CLI. Use the returned `preview_url`; a missing sample is `null`. Downloading an existing sample does not synthesize new audio.

Where your plan permits model selection, `GET /api/v1/models?type=realtime&realtime_variant=full_duplex` lists compatible speech models. This does not expose a reasoning-model selector. Current credit rates are included in the usage response, and Full Duplex and avatar surcharges are additive when both are active.

**Region availability:** Full Duplex follows the models enabled for your selected workspace region, including **EU**, **US** and **Global**. It requires Beta access, Realtime plan access and compatible speech and reasoning models. The editor, API and MCP use the same availability rules.

MCP uses the same assistant fields. Its `get_voices` tool accepts `mode` and `realtime_variant`; `get_models` accepts `realtime_variant`. See [Engine modes](/assistants/engine-modes) for supported settings and limitations.

## Rate limits

REST requests share a fixed one-minute budget across all endpoints: **120 requests per API key or OAuth access token**, and **600 requests per workspace**, by default. Your plan may have different limits. Creating additional keys or switching domains does not increase the workspace budget. A separate limit of **1,800 requests per minute per IP address** protects credential verification; integrations behind the same IP share that limit.

When a budget is exhausted, the API returns `429` with `error.code: "rate_limited"` and a `Retry-After` header containing the number of seconds to wait. Pause requests for that duration, then retry with backoff and a small random delay. Avoid continuously polling the same resource; use webhooks where available.

If request protection is temporarily unavailable, the API returns `503` with a retry delay. Dashboard requests and MCP use their own access and request policies.


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