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

# API Credentials

> Create and use Account and Workspace API keys to connect VIVI to your own apps, scripts, and automations.

API keys let your own applications, scripts, and automations call the VIVI API securely, without a person having to log in. In the portal they're called **API Credentials**, and they come in two types: **Account API keys** and **Workspace API keys**.

This guide explains the difference between them, when to use each, and exactly how to create and use one.

<Warning>
  **API keys are not the same as the `vivi-api-key` header.** The `vivi-api-key` is generated by an [API channel](https://docs.vivi.bot/documentation/core-concepts/channels/api) and is used to send messages to **one specific agent**. The API keys on this page authenticate you to the **VIVI platform API** (managing agents, workspaces, knowledge bases, and more) and use an `Authorization: Bearer` token instead. If you only want to chat with a single agent, use an API channel.
</Warning>

***

## Account vs. Workspace API keys

Both kinds of keys work the same way technically. The difference is **how much they can access**.

<CardGroup cols={2}>
  <Card title="Account API key" color="#0066ff" icon="building">
    Acts as an **account administrator** with access to **every workspace** in your account. Best for organization-wide automation and managing multiple workspaces from one place.
  </Card>

  <Card title="Workspace API key" color="#0066ff" icon="folder">
    Limited to **one workspace** and to a **role you choose** (for example, Content Manager). Best for integrations tied to a single team, client, or project.
  </Card>
</CardGroup>

|                           | **Account API key**                                      | **Workspace API key**                                                          |
| ------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------ |
| **Access scope**          | The entire account (all workspaces)                      | A single workspace                                                             |
| **Permissions**           | Full account admin                                       | A workspace role you select (e.g. Workspace Admin, Content Manager, Chat User) |
| **Where you create it**   | **Manage Account → API Credentials**                     | **Workspace → Users → API Credentials**                                        |
| **Who can create it**     | Account admins                                           | Account admins **or** that workspace's admins                                  |
| **Change the role later** | No (always account admin)                                | Yes, you can update the assigned role anytime                                  |
| **Best for**              | Org-wide automation, provisioning, multi-workspace tools | Per-team integrations, least-privilege access, isolation                       |

<Tip>
  **Rule of thumb:** start with a **Workspace API key** and the narrowest role that does the job. Only reach for an **Account API key** when an integration genuinely needs to act across multiple workspaces. Smaller scope means less risk if a key is ever exposed.
</Tip>

For more on how accounts and workspaces relate, see [Accounts & Workspaces](https://docs.vivi.bot/documentation/accounts-billing/accounts-workspaces).

***

## How API keys work

A VIVI API key isn't a single password you paste into one field. It's a set of credentials your app exchanges for a temporary access token. When you create one, VIVI gives you four values to copy:

<ParamField path="clientId" type="string" required>
  The public identifier for your API key. Sent as `client_id` when requesting an access token.
</ParamField>

<ParamField path="clientSecret" type="string" required>
  The secret half of the key, sent as `client_secret`. **Shown only once, at creation**, so store it somewhere safe.
</ParamField>

<ParamField path="audience" type="string" required>
  Tells VIVI which API the token is for (for example, `https://vivi-cxp-api/`). Copy it exactly as shown in the portal.
</ParamField>

<ParamField path="tokenUrl" type="URL" required>
  The endpoint where you exchange your credentials for an access token.
</ParamField>

Using a key is a **two-step** process:

<Steps>
  <Step title="Exchange your credentials for an access token">
    Send your `clientId` and `clientSecret` to the `tokenUrl`. VIVI returns a short-lived **access token** (a JWT) that's valid for about **24 hours**.
  </Step>

  <Step title="Call the VIVI API with that token">
    Include the token on every request as `Authorization: Bearer <access_token>`. When it expires, repeat step 1 to get a new one.
  </Step>
</Steps>

<Note>
  Your app should **save the access token and reuse it** until it's close to expiring, rather than requesting a new one on every call.
</Note>

***

## Create an API key

<Steps>
  <Step title="Open the right page">
    * **Account API key:** go to **Manage Account** and open the **API Credentials** tab.
    * **Workspace API key:** open your workspace, go to **Users**, and open the **API Credentials** tab.
  </Step>

  <Step title="Create a new credential">
    Click **Create** and give it a clear **name** that explains what will use it (for example, `Zapier integration` or `Nightly report job`). For a **Workspace** key, also pick the **role** it should have.
  </Step>

  <Step title="Copy your four values immediately">
    VIVI shows your `clientId`, `clientSecret`, `audience`, and `tokenUrl` once, each with a copy button. The dialog also includes a ready-to-run `curl` example and a link to the [API reference](https://api.vivi.bot/redoc). Save the values in your secrets manager now.

    <Warning>
      The **`clientSecret` is shown only once.** After you close this dialog you'll only ever see the last 4 characters. If you lose it, you'll need to **rotate** the key (see below).
    </Warning>
  </Step>

  <Step title="Start using it">
    Use the values to request a token and call the API, as shown in the next section.
  </Step>
</Steps>

<Note>
  API keys are available on eligible plans (such as **Pro** or **Enterprise**) and can only be created by a human administrator. If you don't see the **API Credentials** tab, check your subscription or ask your account admin.
</Note>

***

## Use an API key

Replace the placeholders below with the values from the portal. The `audience` and `tokenUrl` must match **exactly** what VIVI showed you.

### Step 1: Get an access token

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "YOUR_TOKEN_URL" \
    -H "Content-Type: application/json" \
    -d '{
      "client_id": "YOUR_CLIENT_ID",
      "client_secret": "YOUR_CLIENT_SECRET",
      "audience": "YOUR_AUDIENCE",
      "grant_type": "client_credentials"
    }'
  ```

  ```python Python (requests) theme={null}
  import requests

  token_url = "YOUR_TOKEN_URL"

  payload = {
      "client_id": "YOUR_CLIENT_ID",
      "client_secret": "YOUR_CLIENT_SECRET",
      "audience": "YOUR_AUDIENCE",
      "grant_type": "client_credentials",
  }

  response = requests.post(token_url, json=payload, timeout=30)
  response.raise_for_status()

  access_token = response.json()["access_token"]
  print(access_token)
  ```

  ```python Python (httpx) theme={null}
  import asyncio
  import httpx

  token_url = "YOUR_TOKEN_URL"

  payload = {
      "client_id": "YOUR_CLIENT_ID",
      "client_secret": "YOUR_CLIENT_SECRET",
      "audience": "YOUR_AUDIENCE",
      "grant_type": "client_credentials",
  }


  async def main() -> None:
      async with httpx.AsyncClient(timeout=30) as client:
          response = await client.post(token_url, json=payload)
          response.raise_for_status()

      access_token = response.json()["access_token"]
      print(access_token)


  asyncio.run(main())
  ```

  ```javascript JavaScript theme={null}
  const tokenUrl = "YOUR_TOKEN_URL";

  const response = await fetch(tokenUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      client_id: "YOUR_CLIENT_ID",
      client_secret: "YOUR_CLIENT_SECRET",
      audience: "YOUR_AUDIENCE",
      grant_type: "client_credentials",
    }),
  });

  const { access_token: accessToken } = await response.json();
  console.log(accessToken);
  ```
</CodeGroup>

A successful response includes an `access_token` and how long it's valid (in seconds):

```json theme={null}
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6...",
  "token_type": "Bearer",
  "expires_in": 86400
}
```

### Step 2: Call the VIVI API

Send the token as a **Bearer** token on the `Authorization` header. The example below lists the workspaces in your account.

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.vivi.bot/accounts/YOUR_ACCOUNT_ID/workspaces" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
  ```

  ```python Python (requests) theme={null}
  import requests

  account_id = "YOUR_ACCOUNT_ID"
  url = f"https://api.vivi.bot/accounts/{account_id}/workspaces"

  headers = {"Authorization": f"Bearer {access_token}"}

  response = requests.get(url, headers=headers, timeout=30)
  response.raise_for_status()

  print(response.json())
  ```

  ```python Python (httpx) theme={null}
  import asyncio
  import httpx

  account_id = "YOUR_ACCOUNT_ID"
  url = f"https://api.vivi.bot/accounts/{account_id}/workspaces"

  headers = {"Authorization": f"Bearer {access_token}"}


  async def main() -> None:
      async with httpx.AsyncClient(timeout=30) as client:
          response = await client.get(url, headers=headers)
          response.raise_for_status()

      print(response.json())


  asyncio.run(main())
  ```

  ```javascript JavaScript theme={null}
  const accountId = "YOUR_ACCOUNT_ID";
  const url = `https://api.vivi.bot/accounts/${accountId}/workspaces`;

  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${accessToken}` },
  });

  console.log(await response.json());
  ```
</CodeGroup>

<Note>
  Explore every available endpoint in the [VIVI API Reference](https://api.vivi.bot/redoc).
</Note>

<Warning>
  Never send your `clientSecret` to VIVI API endpoints. It's used **only** at the `tokenUrl` to request an access token.
</Warning>

<Tip>
  **Acting on behalf of a user (optional).** With an **Account API key**, you can add an `X-User-Id: <user-id>` header so new records are attributed to that specific VIVI user. This affects ownership only and never grants extra permissions.
</Tip>

***

## Permissions

API keys don't have their own separate permissions. They inherit them from the role described in the comparison above: an **Account API key** acts as an account admin, while a **Workspace API key** uses the role you assigned it (which you can change later).

For details on the available roles, see [Users](https://docs.vivi.bot/documentation/accounts-billing/users).

***

## Manage existing keys

All of these actions live on the same **API Credentials** tab where you created the key.

<CardGroup cols={2}>
  <Card title="Rotate the secret" color="#0066ff" icon="rotate">
    Generates a **new `clientSecret`** (shown once) and retires the old one. Use it if a secret may have leaked, or on a regular schedule. Tokens already issued stay valid until they expire (\~24 hours), so update your app promptly.
  </Card>

  <Card title="Deactivate the key" color="#0066ff" icon="trash">
    Permanently disables the key. Any app using it will start receiving **401 Unauthorized** errors. Use this when an integration is retired or a key is compromised.
  </Card>

  <Card title="Change the role" color="#0066ff" icon="user-gear">
    For **Workspace API keys**, you can assign a different workspace role after creation. Account API keys are always account admin and can't change roles.
  </Card>

  <Card title="Identify a key" color="#0066ff" icon="key">
    Each key shows the **last 4 characters** of its secret. Use this to tell which key is installed in which external system.
  </Card>
</CardGroup>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="I get 401 Unauthorized when calling the API">
    Common causes: the token has **expired** (request a new one), the `Authorization` header isn't formatted as `Bearer <token>`, or the key was **deactivated**. Request a fresh token and try again. (Rotating a secret doesn't invalidate tokens that were already issued, so it won't cause this on its own.)
  </Accordion>

  <Accordion title="I get 403 Forbidden">
    The key authenticated successfully but **doesn't have permission** for that resource. A **Workspace API key** can only act inside its own workspace and within its assigned role. If you need broader access, raise the workspace role or use an **Account API key**.
  </Accordion>

  <Accordion title="My token request fails (invalid_client / invalid_request)">
    Check that you're posting to the correct `tokenUrl` with `Content-Type: application/json`, and that `clientId`, `clientSecret`, and `audience` are copied **exactly** as shown in the portal (no extra spaces). The `grant_type` must be `client_credentials`. If the secret was lost, **rotate** the key to get a new one.
  </Accordion>

  <Accordion title="I closed the dialog and lost my client secret">
    Secrets can't be recovered. VIVI only stores the last 4 characters. Open the **API Credentials** tab, **rotate** the key, and copy the new secret immediately.
  </Accordion>

  <Accordion title="I don't see the API Credentials tab">
    API keys require an eligible plan (such as **Pro** or **Enterprise**) and administrator permissions. For account keys you must be an **Account Admin**; for workspace keys, an **Account Admin** or that workspace's admin. Confirm your subscription, or ask an account admin to create the key for you.
  </Accordion>

  <Accordion title="Should I use vivi-api-key instead?">
    Only for an [API channel](https://docs.vivi.bot/documentation/core-concepts/channels/api), which sends messages to a single agent. For everything else on the main VIVI API, use the API keys on this page with an `Authorization: Bearer` token.
  </Accordion>
</AccordionGroup>

***

## Best Practices

* **Use the least privilege that works.** Prefer a **Workspace API key** with a narrow role over an **Account API key** whenever possible.
* **Store secrets safely.** Keep the `clientSecret` in a secrets manager or environment variable, never in source code, spreadsheets, or chat messages.
* **One key per integration.** Give each app or job its own key with a descriptive name, so you can rotate or deactivate it without affecting anything else.
* **Cache and refresh tokens.** Reuse the access token until it nears expiry instead of fetching a new one on every request.
* **Rotate regularly.** Rotate secrets on a schedule, and immediately if you suspect exposure.
* **Deactivate what you don't use.** Disable keys for retired integrations or departed team members.
