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

> ## Agent Instructions
> These are the docs for Sevalla, a platform for deploying applications, databases, static sites, object storage and load balancers. The dashboard is at https://app.sevalla.com.
> Bold text in steps is an exact dashboard label.
> To act on a Sevalla account, prefer the Sevalla MCP server (https://mcp.sevalla.com/mcp, see https://docs.sevalla.com/ai-agents/overview.md), then the Sevalla CLI (https://docs.sevalla.com/developer-tools/cli.md), then the REST API (https://api-docs.sevalla.com, OpenAPI spec at https://api.sevalla.com/v3/openapi.json).
> Every page index is at https://docs.sevalla.com/llms.txt.

# API keys

> Create API keys for the Sevalla API, CLI, MCP server, Terraform and GitHub Actions with a predefined role or custom capabilities, then rotate, disable, update or delete them.

An API key lets a script, CI job, AI agent or tool call the [Sevalla API](/developer-tools/api) on behalf of one company, with only the permissions you give it. You manage keys under **Tools** > **API keys** in the dashboard, or through the API and the [CLI](/developer-tools/cli).

## How API keys work

| Property | Value |
| - | - |
| Format | `svl_` followed by 64 hexadecimal characters |
| Shown in full | Once, when you create or rotate the key. Sevalla stores only a hash of it. Lists show it masked: its first 6 and last 4 characters, such as `svl_3f...9a2c`. |
| Scope | One company. Every request made with the key acts on that company's services. |
| Permissions | One [predefined role](#predefined-roles), or [custom capabilities](#custom-capabilities) that can be limited to specific resources |
| Expiration | None by default, or a date you set when you create the key. You can't change it later. |
| Status | **Active**, **Disabled** or **Expired**. An expired key can't be used even if it's enabled. |
| Last used | Updated on every request, shown in the **Last used** column (**Never** until the first request) |

Every Sevalla tool authenticates with an API key:

| Tool | How it gets the key |
| - | - |
| [Sevalla API](/developer-tools/api) | `Authorization: Bearer <key>` header on every request |
| [Sevalla CLI](/developer-tools/cli) | `sevalla login` creates a key for you, or set `SEVALLA_API_TOKEN` |
| [Sevalla MCP server](/ai-agents/overview) | OAuth sign-in creates a key for you, or send it as a bearer token |
| [Terraform provider](/developer-tools/terraform) | `SEVALLA_API_KEY` environment variable or the provider's `api_key` |
| [GitHub Actions](/developer-tools/github-actions) | The action's `sevalla-token` input, from a repository secret |

Create one key per tool or environment, so you can rotate or revoke one without breaking the others.

## Before you begin

* You need the **Company owner**, **Company admin** or **Company developer** role. Other roles can't see the **API keys** page. See [users and roles](/company/users-and-roles).
* The company needs a valid payment method, because API keys can create billable services. Without one, **Create API key** is disabled and the sheet shows **Add a payment method to create an API key**.

## Create an API key

<Steps>
  <Step title="Open API keys">
    In the sidebar, under **Tools**, click **API keys**, then click **Create API key**.
  </Step>

  <Step title="Name the key">
    In **Name**, enter where the key is used, so you recognize it later, for example `GitHub Actions`.
  </Step>

  <Step title="Choose when it expires">
    Under **Expiration**, keep **Never** or pick when the key stops working.
  </Step>

  <Step title="Set the permissions">
    Under **Permissions**, choose **Predefined role** and select a **Role**, or choose **Custom capabilities** and tick the permissions the key needs (see [Permissions](#permissions)).
  </Step>

  <Step title="Create and copy the key">
    Click **Create API key**. The sheet changes to **API key created** and shows the full key under **API token**. Click **Copy API token and close**, and store the key in a password manager or your CI secrets right away.
  </Step>
</Steps>

<Frame>
  <img className="block dark:hidden" src="https://assets.sevalla.com/screenshots/light/tools-api-keys-create-custom.png" alt="The Create API key sheet with a name, the Expiration presets and custom capabilities selected for App and Static site" width="576" />

  <img className="hidden dark:block" src="https://assets.sevalla.com/screenshots/dark/tools-api-keys-create-custom.png" alt="The Create API key sheet with a name, the Expiration presets and custom capabilities selected for App and Static site" width="576" />
</Frame>

The key appears in the list with the status **Active** and **Last used** set to **Never**.

<Warning>
  You can't see the key again after you close the sheet. If you lose it, [rotate the key](#rotate-an-api-key) to get a new one.
</Warning>

| Field | Values | Default |
| - | - | - |
| **Name** | Any text. Required (`Name is required`). | Empty |
| **Expiration** | **Never**, **12h**, **1d**, **2d**, **7d**, **30d** or **Custom**. **Custom** asks for a date (today to 5 years ahead) and a time, which must be in the future. | **Never** |
| **Permissions** | **Predefined role** with one **Role**, or **Custom capabilities** with at least one permission (`Select a role or at least one capability`) | **Predefined role**, no role selected |

## Permissions

A key gets either one predefined role or a set of custom capabilities, never both. Sevalla checks the key's permissions on every request, so changes apply to the next request. A request the key isn't allowed to make fails with `403` and names the missing permission, for example `This API key is missing the APP:UPDATE permission. Grant it to the key or use a key that has it.`

### Predefined roles

| Role | Permissions | What the key can do |
| - | - | - |
| **Company admin** | 44 | Create, read, update and delete everything, including billing and company settings |
| **Company billing** | 3 | Read and update billing, and read company settings |
| **Company developer** | 41 | Create, read, update and delete applications, databases, static sites, load balancers, buckets, pipelines, projects, webhooks, API keys and registry credentials, and read company settings. No access to billing. |
| **Company viewer** | 12 | Read everything, including billing. Can't create, update or delete anything. |

### Custom capabilities

Each capability is one action on one resource type, written `RESOURCE:ACTION` in the API (`APP:READ`, `DATABASE:CREATE`). In the dashboard, the **Capabilities** table has one row per resource and one column per action; the checkbox above a column selects that action for every resource.

| Resource | In the API | Actions | Limit to specific resources in the dashboard |
| - | - | - | - |
| **App** | `APP` | Create, Read, Update, Delete | Yes |
| **Database** | `DATABASE` | Create, Read, Update, Delete | Yes |
| **Static site** | `STATIC_SITE` | Create, Read, Update, Delete | Yes |
| **Object storage** | `OBJECT_STORAGE` | Create, Read, Update, Delete | Yes |
| **Load balancer** | `LOAD_BALANCER` | Create, Read, Update, Delete | Yes |
| **Pipeline** | `PIPELINE` | Create, Read, Update, Delete | No |
| **Project** | `PROJECT` | Create, Read, Update, Delete | No |
| **Webhook** | `WEBHOOK` | Create, Read, Update, Delete | Yes, by endpoint |
| **API key** | `API_KEY` | Create, Read, Update, Delete | Yes |
| **Registry credential** | `REGISTRY_CREDENTIAL` | Create, Read, Update, Delete | Yes |
| **Company** | `COMPANY` | Read, Update | No |
| **Billing** | `BILLING` | Read, Update | No |

Triggering, rolling back and cancelling deployments of an application needs `APP:UPDATE`; reading its deployments and logs needs `APP:READ`. The same holds for static sites with `STATIC_SITE`, and promoting a pipeline needs `PIPELINE:UPDATE`.

### Limit a permission to specific resources

When you tick a permission for a resource type that can be limited, **Resource scope** appears with a box for that type. Choose **All ... resources** (the default) or **Specific ... resources**, then tick the resources. If you choose specific resources but tick none, the form shows a message such as `Select at least one app, or apply to all.`

A limited permission works only on the resources you picked: a request for another resource of that type fails with `403`, and lists return only the picked resources. When you delete a resource, Sevalla removes the capabilities limited to it from every key. In the API, any capability can take a `resource_id`.

| Use | Permissions |
| - | - |
| Deploy one application from CI | `APP:READ` and `APP:UPDATE`, limited to that application |
| Deploy one static site from CI | `STATIC_SITE:READ` and `STATIC_SITE:UPDATE`, limited to that static site |
| A read-only agent or monitoring | The **Company viewer** role |

<Warning>
  A key with `API_KEY:CREATE` can create new keys with any role, including **Company admin**. Give that permission only to keys you'd trust with full access.
</Warning>

## Rotate an API key

Rotating gives the key a new token and keeps its name, permissions and expiration. The old token can keep working for a while, so you can update everything that uses it first.

<Steps>
  <Step title="Open the rotation">
    On the **API keys** page, open the key's menu (the three dots) and click **Rotate key**.
  </Step>

  <Step title="Choose how long the old token works">
    Under **Expiration**, pick **Now**, **1 hour**, **2 hours**, **4 hours**, **8 hours**, **24 hours** (the default), **48 hours**, **72 hours** or **7 days**. **Now** breaks every client that still uses the old token.
  </Step>

  <Step title="Rotate and copy the new token">
    Click **Rotate key**. The dialog changes to **New API token**. Click **Copy token and close**, then update every place that uses the key.
  </Step>
</Steps>

While the old token still works, the key's status shows a warning icon with **Old token still valid during rotation**. When the period ends, requests with the old token fail with `401`.

## Disable or enable an API key

Disabling a key blocks it at once without deleting it: every request with it fails with `401` until you enable it again.

<Steps>
  <Step title="Open the key's menu">
    On the **API keys** page, open the key's menu and click **Disable**, or **Enable** for a disabled key.
  </Step>

  <Step title="Confirm">
    Click **Disable** (or **Enable**) in the dialog.
  </Step>
</Steps>

The status changes to **Disabled** or **Active**. Enabling an expired key doesn't make it work again: create a new key instead.

When a company is suspended, for example after [failed payments](/billing/failed-payments#what-suspension-does), Sevalla disables every API key in the company. Reactivating the company doesn't enable them again: enable each key you still need on the **API keys** page. The [AI support](/support/ai-support) key stays disabled too; to restore it, turn AI support off and on again.

## Update an API key

Updating changes a key's name or permissions. The token stays the same, so nothing that uses the key needs to change. The expiration can't be changed.

<Steps>
  <Step title="Open the key">
    On the **API keys** page, open the key's menu and click **Update**.
  </Step>

  <Step title="Change the name or permissions">
    Change **Name** or **Permissions**, then click **Update API key**.
  </Step>
</Steps>

The new permissions apply from the key's next request.

## Delete an API key

Deleting a key revokes it for good: every request with it fails with `401`. You can't undo this.

<Steps>
  <Step title="Open the key's menu">
    On the **API keys** page, open the key's menu and click **Delete**.
  </Step>

  <Step title="Confirm">
    Type the key's name, then click **Delete API key**.
  </Step>
</Steps>

## Keys that Sevalla creates for you

Some sign-ins create a key in the company you pick, with the permissions you choose and no expiration. These keys appear in the list like any other, and you rotate, disable or delete them the same way.

| Created by | Key name |
| - | - |
| `sevalla login` in the [CLI](/developer-tools/cli#sign-in) | `API key` followed by the date and time of the sign-in |
| Signing in to the [MCP server](/ai-agents/overview#sign-in-with-oauth) from an AI client | `Sevalla MCP` followed by the client and the date and time |

[AI support](/support/ai-support) uses a managed key that isn't listed. While AI support is on, the page shows **AI support is enabled for this company** with a link to manage its permissions on the AI support page.

## Troubleshoot API keys

| Response | Cause | Fix |
| - | - | - |
| `401` `Unauthorized` | The key is missing, mistyped, disabled, expired or deleted, or it's an old token past its rotation period | Check the `Authorization: Bearer` header and the key's status, or create a new key |
| `403` `This API key is missing the ... permission ...` | The key lacks the permission, or it has the permission for other resources only (the message then reads `permission for this resource`) | [Update the key's permissions](#update-an-api-key) |
| `400` `An API key cannot modify itself` | A key tried to update, rotate, disable or delete itself through the API | Use another key, or the dashboard |

## API and CLI

| Task | API | CLI |
| - | - | - |
| List keys | [List API keys](https://api-docs.sevalla.com/v3/api-keys/list-api-keys) | `sevalla api-keys list` |
| Create a key | [Create API key](https://api-docs.sevalla.com/v3/api-keys/create-api-key) | `sevalla api-keys create --name <name> --capabilities APP:READ,APP:UPDATE` |
| Get a key | [Get API key](https://api-docs.sevalla.com/v3/api-keys/get-api-key) | `sevalla api-keys get <id>` |
| See what the current key can do | [Get current API key](https://api-docs.sevalla.com/v3/api-keys/get-current-api-key) | Not available |
| Check the current key | [Validate API key](https://api-docs.sevalla.com/v3/api-keys/validate-api-key) | `sevalla api-keys validate` |
| Update a key | [Update API key](https://api-docs.sevalla.com/v3/api-keys/update-api-key) | `sevalla api-keys update <id> --name <name>` |
| Rotate a key | [Rotate API key](https://api-docs.sevalla.com/v3/api-keys/rotate-api-key) | `sevalla api-keys rotate <id> --ttl <hours>` |
| Disable or enable a key | [Toggle API key](https://api-docs.sevalla.com/v3/api-keys/toggle-api-key) | `sevalla api-keys toggle <id>` |
| Delete a key | [Delete API key](https://api-docs.sevalla.com/v3/api-keys/delete-api-key) | `sevalla api-keys delete <id> --confirm` |
| List roles and permissions | [List API key roles](https://api-docs.sevalla.com/v3/resources/list-api-key-roles), [List API key permissions](https://api-docs.sevalla.com/v3/resources/list-api-key-permissions) | Not available |

In the API, a new key needs `role_ids` or `capabilities` (at least one), `expired_at` is optional, and rotation takes `old_token_ttl_hours` from `0` to `168`. The CLI's `create` takes custom capabilities only, not roles, and its `rotate` defaults to `--ttl 0`, which ends the old token at once.


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