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

# Projects API

> Create projects and issue API keys for your end customers

The Projects API is for platforms that serve many end customers. Give each end
customer its own KugelAudio project, with its own
[pronunciation dictionaries](/features/dictionaries) and its own API key, and
automate onboarding and offboarding without the dashboard.

A synthesis request made with a project's API key applies that project's
dictionaries without naming the project, so each end customer's vocabulary is
used automatically. See [`project_id`](/api-reference/tts/generate#request-body)
for the details.

## Organization admin key

Every endpoint on this page needs an API key with the **Organization projects**
permission. Create it like any other key (see
[Getting your API key](/api-reference/authentication#getting-your-api-key)),
choose the permission setting **Restricted**, and set **Organization projects**
to **Read** (list projects) or **Write** (everything on this page).

* Only organization owners and admins can grant this permission.
* It is never part of the **All** setting; it must be granted explicitly.
* The key acts as the person who created it, and only while that person is an
  owner or admin of the organization. Otherwise every call answers
  `403 PERMISSION_DENIED`; create a new key.

Send the key in the same `Authorization: Bearer` header as every other endpoint.
Keep it on your server: it can create and delete projects.

## Onboard an end customer

**1. Create a project** with your admin key:

```bash theme={null}
curl -X POST "https://api.kugelaudio.com/v1/projects" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Autohaus Schmidt"}'
```

```json theme={null}
{ "id": 314, "name": "Autohaus Schmidt", "slug": "314", "created_at": "2026-10-09T09:00:00+00:00" }
```

**2. Issue the customer's API key.** For a key that only synthesizes speech and
maintains its own dictionaries, grant `tts` and `dictionaries`:

```bash theme={null}
curl -X POST "https://api.kugelaudio.com/v1/projects/314/api-keys" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Autohaus Schmidt TTS", "permissions": {"tts": "write", "dictionaries": "write"}}'
```

Store `secret` from the response now; it is never shown again.

**3. Create a dictionary and add an entry** with the new key (see the
[Dictionaries API](/api-reference/endpoints/dictionaries)):

```bash theme={null}
curl -X POST "https://api.kugelaudio.com/v1/dictionaries" \
  -H "Authorization: Bearer YOUR_CUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Vehicle models", "language": "de"}'

curl -X POST "https://api.kugelaudio.com/v1/dictionaries/DICT_ID/entries" \
  -H "Authorization: Bearer YOUR_CUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"word": "GTI", "replacement": "G T I"}'
```

**4. Generate speech** with the new key and no `project_id`. The customer's
active dictionaries apply:

```bash theme={null}
curl -X POST "https://api.kugelaudio.com/v1/tts/generate" \
  -H "Authorization: Bearer YOUR_CUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Ihr GTI ist abholbereit.", "voice_id": 1071, "language": "de"}' \
  --output output.pcm
```

## Offboard an end customer

[Delete the project](#delete-project). This revokes its API keys and deletes its
dictionaries and request logs in one call.

## Response Objects

Project responses contain:

| Field | Type | Description |
| - | - | - |
| `id` | integer | Project ID |
| `name` | string | Display name |
| `slug` | string | The project's name in dashboard URLs. A project created over the API starts with its `id` as slug |
| `created_at` | string | Creation timestamp |

API key responses contain:

| Field | Type | Description |
| - | - | - |
| `id` | integer | API key ID, used to revoke the key |
| `project_id` | integer | Project the key belongs to |
| `name` | string \| null | Display name |
| `key_prefix` | string | Fixed prefix every key starts with |
| `key_last4` | string | Last four characters of the key |
| `permissions` | object \| null | Resource to level; `null` means full access within the project |
| `created_at` | string | Creation timestamp |
| `secret` | string | The full API key. Returned only in the response that issues it |

***

## List Projects

Return every project of the key's organization, oldest first. Needs
**Organization projects: Read**.

<ParamField path="GET" method="/v1/projects" />

### Response

```json theme={null}
{
  "projects": [
    { "id": 12, "name": "Default", "slug": "default", "created_at": "2026-01-15T10:00:00+00:00" },
    { "id": 314, "name": "Autohaus Schmidt", "slug": "314", "created_at": "2026-10-09T09:00:00+00:00" }
  ]
}
```

### Example

```bash cURL theme={null}
curl -X GET "https://api.kugelaudio.com/v1/projects" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY"
```

***

## Create Project

Needs **Organization projects: Write**. Returns `201` with the project object.
An organization can have at most 1000 projects.

<ParamField path="POST" method="/v1/projects" />

### Body

<ParamField body="name" type="string" required>
  Display name (1-200 characters, not blank).
</ParamField>

### Example

```bash cURL theme={null}
curl -X POST "https://api.kugelaudio.com/v1/projects" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Autohaus Schmidt"}'
```

***

## Delete Project

Needs **Organization projects: Write**.

<ParamField path="DELETE" method="/v1/projects/{project_id}" />

<Warning>
  Deleting a project is irreversible. It deletes the project's API keys,
  dictionaries and request logs. A key cannot delete the project it belongs to.
</Warning>

### Response

```json theme={null}
{ "deleted": true }
```

### Example

```bash cURL theme={null}
curl -X DELETE "https://api.kugelaudio.com/v1/projects/314" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY"
```

***

## Issue API Key

Issue a new API key for a project of your organization. Needs
**Organization projects: Write**. Returns `201` with the API key object,
including `secret`.

<ParamField path="POST" method="/v1/projects/{project_id}/api-keys" />

### Body

<ParamField body="name" type="string">
  Display name (maximum 200 characters).
</ParamField>

<ParamField body="permissions" type="object">
  Resource to level. Omit it for full access within the project (text to
  speech, realtime sessions, speech enhancement, voices and
  dictionaries). Resources and levels:

  | Resource | Levels |
  | - | - |
  | `tts` | `none`, `write` |
  | `realtime` | `none`, `write` |
  | `enhance` | `none`, `write` |
  | `voices` | `none`, `read`, `write` |
  | `dictionaries` | `none`, `read`, `write` |

  What each resource covers is in [Key permissions](/api-reference/authentication#key-permissions).
  An issued key can never hold the `projects` permission. For a
  text-to-speech key per end customer, use `{"tts": "write", "dictionaries": "write"}`.
</ParamField>

### Response

```json theme={null}
{
  "id": 9001,
  "project_id": 314,
  "name": "Autohaus Schmidt TTS",
  "key_prefix": "sk-kug-proj",
  "key_last4": "a9d2",
  "permissions": { "tts": "write", "dictionaries": "write" },
  "created_at": "2026-10-09T09:01:00+00:00",
  "secret": "sk-kug-proj_..."
}
```

### Example

```bash cURL theme={null}
curl -X POST "https://api.kugelaudio.com/v1/projects/314/api-keys" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Autohaus Schmidt TTS", "permissions": {"tts": "write", "dictionaries": "write"}}'
```

***

## Revoke API Key

Revoke an active API key of a project of your organization. Needs
**Organization projects: Write**. A key cannot revoke itself.

<ParamField path="DELETE" method="/v1/projects/{project_id}/api-keys/{key_id}" />

<Note>
  API keys are cached briefly, so a revoked key can keep working for about a
  minute.
</Note>

### Response

```json theme={null}
{ "deleted": true }
```

### Example

```bash cURL theme={null}
curl -X DELETE "https://api.kugelaudio.com/v1/projects/314/api-keys/9001" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY"
```

***

## Error responses

Errors use the standard [error body](/api-reference/errors).

| Status | Code | Meaning |
| - | - | - |
| 400 | `VALIDATION_ERROR` | Missing, blank or invalid field, an unknown permission resource or level, or a request to issue a key with the `projects` permission. |
| 401 | `UNAUTHORIZED` | API key missing or invalid. |
| 403 | `PERMISSION_DENIED` | The key lacks the **Organization projects** permission, or its creator is no longer an owner or admin of the organization. |
| 404 | `NOT_FOUND` | The project does not exist or belongs to another organization, or the API key does not exist or is already revoked. |
| 409 | `VALIDATION_ERROR` | The organization already has 1000 projects, the key tried to delete its own project, or the key tried to revoke itself. |
| 503 | `INTERNAL_ERROR` | Project management is unavailable on this deployment (for example a self-hosted one). |

## Next steps

<CardGroup cols={2}>
  <Card title="Dictionaries" icon="book" href="/features/dictionaries">
    How dictionaries shape pronunciation
  </Card>

  <Card title="Dictionaries API" icon="code" href="/api-reference/endpoints/dictionaries">
    Manage each customer's dictionaries
  </Card>
</CardGroup>


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