Install
Select a method below to install the server.
unkey_v2_deployments_create_deployment_v3
Create a deployment for an app in a project.
Omit the source to use the app's configured default. A Git app builds its default branch. An OCI app deploys its default image.
Optionally provide one source override:
- `oci`: deploy a prebuilt OCI image without a build. Mutable tags are resolved to immutable digests before rollout.
- `git`: build and deploy from the app's connected GitHub repository, a branch, a specific commit, or a fork commit. Requires the app to have a repository connected.
- `deployment`: re-run an existing deployment by its id. Git deployments rebuild from the recorded commit; OCI deployments reuse the recorded resolved image.
Returns immediately with a `deploymentId`. The build and rollout run asynchronously. Poll `deployments.getDeployment` to watch status until it is ready.
**Authentication**: requires a root key with permission to create deployments.
▾
Create a deployment for an app in a project.
Omit the source to use the app's configured default. A Git app builds its default branch. An OCI app deploys its default image.
Optionally provide one source override:
- `oci`: deploy a prebuilt OCI image without a build. Mutable tags are resolved to immutable digests before rollout.
- `git`: build and deploy from the app's connected GitHub repository, a branch, a specific commit, or a fork commit. Requires the app to have a repository connected.
- `deployment`: re-run an existing deployment by its id. Git deployments rebuild from the recorded commit; OCI deployments reuse the recorded resolved image.
Returns immediately with a `deploymentId`. The build and rollout run asynchronously. Poll `deployments.getDeployment` to watch status until it is ready.
**Authentication**: requires a root key with permission to create deployments.
Open-world
unkey_v2_workspace_get_usage
Get the usage of your workspace for one calendar month (UTC): billable API
operations, compute usage per environment, and active keys per app.
Use this to track usage during the month or to look back at a past
month. The response has no prices. Your invoice is the source of truth.
Compute usage can be up to 15 minutes late, and it can change for up to 7
days.
Send `{}` for the current month to date, or
`{"period": {"year": 2026, "month": 9}}` for a full past month. The month
must start within the last 90 days.
**Required Permissions**
Your root key must have this permission:
- `unkey:v1:<workspace_id>:usage#read`
▾
Get the usage of your workspace for one calendar month (UTC): billable API
operations, compute usage per environment, and active keys per app.
Use this to track usage during the month or to look back at a past
month. The response has no prices. Your invoice is the source of truth.
Compute usage can be up to 15 minutes late, and it can change for up to 7
days.
Send `{}` for the current month to date, or
`{"period": {"year": 2026, "month": 9}}` for a full past month. The month
must start within the last 90 days.
**Required Permissions**
Your root key must have this permission:
- `unkey:v1:<workspace_id>:usage#read`
Open-world
unkey_v2_workspace_get_limits
Get every limit of your workspace, with the current value against each
limit that has one.
Use this before an operation that a limit can reject, for example to see how
many custom domains or log drains remain, or how much CPU, memory, and disk
a new deployment can still reserve.
The request takes no parameters. Each limit has a `limit`, which is `null`
when unlimited, and a `current` value when the limit has one. Billable
operations count the current calendar month in UTC. The Compute limits are
present only when the workspace has a Compute plan.
**Required Permissions**
Your root key must have the following permission:
- `unkey:v1:<workspace_id>:limits#read`
▾
Get every limit of your workspace, with the current value against each
limit that has one.
Use this before an operation that a limit can reject, for example to see how
many custom domains or log drains remain, or how much CPU, memory, and disk
a new deployment can still reserve.
The request takes no parameters. Each limit has a `limit`, which is `null`
when unlimited, and a `current` value when the limit has one. Billable
operations count the current calendar month in UTC. The Compute limits are
present only when the workspace has a Compute plan.
**Required Permissions**
Your root key must have the following permission:
- `unkey:v1:<workspace_id>:limits#read`
Open-world
unkey_v2_projects_update_project
Update an existing project in your workspace, identified by its id.
The project name, slug, and delete protection setting can be changed. Omitted fields are left unchanged. Changing the slug affects the deployment domains generated for this project.
**Required Permissions**
Your root key must have one of the following permissions:
- `project.*.update_project` (to update any project)
- `project.<project_id>.update_project` (to update a specific project)
▾
Update an existing project in your workspace, identified by its id.
The project name, slug, and delete protection setting can be changed. Omitted fields are left unchanged. Changing the slug affects the deployment domains generated for this project.
**Required Permissions**
Your root key must have one of the following permissions:
- `project.*.update_project` (to update any project)
- `project.<project_id>.update_project` (to update a specific project)
Open-world
unkey_v2_projects_list_projects
Retrieve a paginated list of projects in your workspace.
Use this to build project management dashboards or to enumerate projects for administrative purposes. Results are ordered by project id and returned in pages. When `hasMore` is true, pass the returned `cursor` to fetch the next page.
**Required Permissions**
Your root key must have the following permission:
- `project.*.read_project` (to read projects in your workspace)
▾
Retrieve a paginated list of projects in your workspace.
Use this to build project management dashboards or to enumerate projects for administrative purposes. Results are ordered by project id and returned in pages. When `hasMore` is true, pass the returned `cursor` to fetch the next page.
**Required Permissions**
Your root key must have the following permission:
- `project.*.read_project` (to read projects in your workspace)
Open-world
unkey_v2_projects_get_project
Retrieve a single project in your workspace by its id.
Use this to fetch project details after creation, verify a project exists before performing operations, or resolve a project's metadata from its id.
**Required Permissions**
Your root key must have one of the following permissions:
- `project.*.read_project` (to read any project)
- `project.<project_id>.read_project` (to read a specific project)
▾
Retrieve a single project in your workspace by its id.
Use this to fetch project details after creation, verify a project exists before performing operations, or resolve a project's metadata from its id.
**Required Permissions**
Your root key must have one of the following permissions:
- `project.*.read_project` (to read any project)
- `project.<project_id>.read_project` (to read a specific project)
Open-world
unkey_v2_projects_delete_project
Delete an existing project in your workspace, identified by its id.
Deletion is asynchronous and eventually consistent. The project and all of its associated resources (apps, environments, deployments, custom domains) are torn down by a background workflow. A successful response indicates the deletion was enqueued, not that every resource has already been removed.
Projects with delete protection enabled cannot be deleted until protection is disabled.
**Required Permissions**
Your root key must have one of the following permissions:
- `project.*.delete_project` (to delete any project)
- `project.<project_id>.delete_project` (to delete a specific project)
▾
Delete an existing project in your workspace, identified by its id.
Deletion is asynchronous and eventually consistent. The project and all of its associated resources (apps, environments, deployments, custom domains) are torn down by a background workflow. A successful response indicates the deletion was enqueued, not that every resource has already been removed.
Projects with delete protection enabled cannot be deleted until protection is disabled.
**Required Permissions**
Your root key must have one of the following permissions:
- `project.*.delete_project` (to delete any project)
- `project.<project_id>.delete_project` (to delete a specific project)
Open-world
unkey_v2_projects_create_project
Create a project to group deployments and applications under a workspace-scoped slug.
The slug you provide is the stable, caller-defined handle used to reference this project in subsequent operations (get, update, delete). It must be unique within your workspace.
**Important**: The slug cannot collide with an existing project in your workspace. A duplicate slug returns a 409 conflict.
**Required Permissions**
Your root key must have the following permission:
- `project.*.create_project` (to create projects in your workspace)
▾
Create a project to group deployments and applications under a workspace-scoped slug.
The slug you provide is the stable, caller-defined handle used to reference this project in subsequent operations (get, update, delete). It must be unique within your workspace.
**Important**: The slug cannot collide with an existing project in your workspace. A duplicate slug returns a 409 conflict.
**Required Permissions**
Your root key must have the following permission:
- `project.*.create_project` (to create projects in your workspace)
Open-world
unkey_v2_logs_get_api_request_metrics
Count the requests that the Unkey API served for your workspace per time bucket, split by status class.
The filters have the same shape as in `logs.listApiRequests`, without `requestId`. In one field, values under `is`, `contains`, `startsWith`, and `endsWith` are combined with OR. Values under `isNot` and `notContains`, and the range operators `gt`, `gte`, `lt`, and `lte`, are combined with AND. Different fields are combined with AND. Every text match is exact and case-sensitive.
`filters.time` sets the window. A missing lower bound is the start of your log retention, and a missing upper bound is now. Unkey picks the bucket width from the window. It is the distance between the `time` of two points. The first bucket starts at or before the window start and counts its whole width. Windows reach back at most 100 days, and requests outside the log retention of your workspace are not counted.
**Required Permissions**
Your root key must have the following permission:
- `unkey:v1:<workspace_id>:logs/apiRequests#read`
▾
Count the requests that the Unkey API served for your workspace per time bucket, split by status class.
The filters have the same shape as in `logs.listApiRequests`, without `requestId`. In one field, values under `is`, `contains`, `startsWith`, and `endsWith` are combined with OR. Values under `isNot` and `notContains`, and the range operators `gt`, `gte`, `lt`, and `lte`, are combined with AND. Different fields are combined with AND. Every text match is exact and case-sensitive.
`filters.time` sets the window. A missing lower bound is the start of your log retention, and a missing upper bound is now. Unkey picks the bucket width from the window. It is the distance between the `time` of two points. The first bucket starts at or before the window start and counts its whole width. Windows reach back at most 100 days, and requests outside the log retention of your workspace are not counted.
**Required Permissions**
Your root key must have the following permission:
- `unkey:v1:<workspace_id>:logs/apiRequests#read`
Open-world
unkey_v2_github_install_app
Start installing the Unkey GitHub App for your workspace. Returns a GitHub
App install URL: open it in a browser to install the app and grant
repository access. After installation GitHub returns to Unkey, which binds
the installation to your workspace and lands you in the workspace settings.
Installation is workspace-wide and takes no parameters. Once installed, link
repositories to individual apps with the `git` field on `apps.createApp` and
`apps.updateApp`.
**Required Permissions**
Your root key must have the following permission:
- `workspace.*.install_github`
▾
Start installing the Unkey GitHub App for your workspace. Returns a GitHub
App install URL: open it in a browser to install the app and grant
repository access. After installation GitHub returns to Unkey, which binds
the installation to your workspace and lands you in the workspace settings.
Installation is workspace-wide and takes no parameters. Once installed, link
repositories to individual apps with the `git` field on `apps.createApp` and
`apps.updateApp`.
**Required Permissions**
Your root key must have the following permission:
- `workspace.*.install_github`
Open-world
unkey_v2_gateway_update_policy
Update a single policy in place without resending the environment's full
policy list. The policy keeps its id and its position in the evaluation
order, and all other policies are untouched.
Omitted fields keep their stored values; at least one updatable field
must be provided. Setting `match` to null removes all match expressions
so the policy applies to every request. Providing one of `keyauth`,
`ratelimit`, `firewall` or `openapi` replaces the policy's rule
entirely, including switching its type; at most one may be set.
Policy ids are regenerated whenever `gateway.setPolicies` replaces the
list, so fetch current ids via `gateway.listPolicies` first.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.update_policy` (for any environment)
- `environment.<environment_id>.update_policy` (for a specific environment)
▾
Update a single policy in place without resending the environment's full
policy list. The policy keeps its id and its position in the evaluation
order, and all other policies are untouched.
Omitted fields keep their stored values; at least one updatable field
must be provided. Setting `match` to null removes all match expressions
so the policy applies to every request. Providing one of `keyauth`,
`ratelimit`, `firewall` or `openapi` replaces the policy's rule
entirely, including switching its type; at most one may be set.
Policy ids are regenerated whenever `gateway.setPolicies` replaces the
list, so fetch current ids via `gateway.listPolicies` first.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.update_policy` (for any environment)
- `environment.<environment_id>.update_policy` (for a specific environment)
Open-world
unkey_v2_gateway_set_policies
Replace an environment's gateway policies in a single atomic request.
Policies run at the edge before requests reach your app: verify API keys,
rate limit, block requests outright, or validate them against your
OpenAPI spec.
Policies are an ordered list: the gateway evaluates them top to bottom
and the first rejection short-circuits the request.
Each policy sets exactly one of `keyauth`, `ratelimit`, `firewall` or
`openapi`, plus optional `match` expressions restricting which requests
it applies to.
Every call is a full replace: the environment's policies become exactly
the request list in the given order, and the server generates a fresh id
for each one. An empty list removes all policies. The operation is
atomic: if any policy is invalid, nothing is written.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.set_policies` (for any environment)
- `environment.<environment_id>.set_policies` (for a specific environment)
▾
Replace an environment's gateway policies in a single atomic request.
Policies run at the edge before requests reach your app: verify API keys,
rate limit, block requests outright, or validate them against your
OpenAPI spec.
Policies are an ordered list: the gateway evaluates them top to bottom
and the first rejection short-circuits the request.
Each policy sets exactly one of `keyauth`, `ratelimit`, `firewall` or
`openapi`, plus optional `match` expressions restricting which requests
it applies to.
Every call is a full replace: the environment's policies become exactly
the request list in the given order, and the server generates a fresh id
for each one. An empty list removes all policies. The operation is
atomic: if any policy is invalid, nothing is written.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.set_policies` (for any environment)
- `environment.<environment_id>.set_policies` (for a specific environment)
Open-world
unkey_v2_gateway_list_policies
Retrieve an environment's gateway policies in evaluation order: the
gateway evaluates them top to bottom and the first rejection
short-circuits the request.
The full policy list is returned in a single response.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.read_policies` (for any environment)
- `environment.<environment_id>.read_policies` (for a specific environment)
▾
Retrieve an environment's gateway policies in evaluation order: the
gateway evaluates them top to bottom and the first rejection
short-circuits the request.
The full policy list is returned in a single response.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.read_policies` (for any environment)
- `environment.<environment_id>.read_policies` (for a specific environment)
Open-world
unkey_v2_environments_update_settings
Update the build, runtime, and regional settings for an environment.
All settings fields are optional. Omit a field to leave it unchanged. For
nullable fields (`dockerfile`, `healthcheck`, `openapiSpecPath`), send null
to clear the value. When `regions` is present it replaces the full set of
regions for the environment.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.update_environment` (to update any environment)
- `environment.<environment_id>.update_environment` (to update a specific environment)
▾
Update the build, runtime, and regional settings for an environment.
All settings fields are optional. Omit a field to leave it unchanged. For
nullable fields (`dockerfile`, `healthcheck`, `openapiSpecPath`), send null
to clear the value. When `regions` is present it replaces the full set of
regions for the environment.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.update_environment` (to update any environment)
- `environment.<environment_id>.update_environment` (to update a specific environment)
Open-world
unkey_v2_environments_set_environment_variables
Create or update environment variables for an environment in a single atomic
request.
By default this is an upsert: each variable in the payload is created if new
or fully overwritten if the key already exists, and any variable not in the
payload is left untouched. This lets you change one variable without
re-sending the others, which matters for write-only secrets you can no longer
read back.
Set `prune: true` to make it a full replace instead: after upserting, every
variable not in the payload is deleted. Sending `prune: true` with an empty
`variables` list resets the environment by deleting every variable.
Each variable is written exactly as sent, never merged, so omitted optional
fields fall back to their defaults rather than the previous value. Values are
always encrypted at rest. Set `kind: recoverable` to allow a value to be read
back; it defaults to `writeonly`, which can never be read back through the API.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.set_environment_variables` (for any environment)
- `environment.<environment_id>.set_environment_variables` (for a specific environment)
▾
Create or update environment variables for an environment in a single atomic
request.
By default this is an upsert: each variable in the payload is created if new
or fully overwritten if the key already exists, and any variable not in the
payload is left untouched. This lets you change one variable without
re-sending the others, which matters for write-only secrets you can no longer
read back.
Set `prune: true` to make it a full replace instead: after upserting, every
variable not in the payload is deleted. Sending `prune: true` with an empty
`variables` list resets the environment by deleting every variable.
Each variable is written exactly as sent, never merged, so omitted optional
fields fall back to their defaults rather than the previous value. Values are
always encrypted at rest. Set `kind: recoverable` to allow a value to be read
back; it defaults to `writeonly`, which can never be read back through the API.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.set_environment_variables` (for any environment)
- `environment.<environment_id>.set_environment_variables` (for a specific environment)
Open-world
unkey_v2_environments_remove_environment_variables
Remove environment variables from an environment in a single atomic request.
This operation only deletes keys by name. Keys in the payload that exist are
removed; keys that are not present are ignored, since their absence already
matches the requested state. To replace or update values, use
`setEnvironmentVariables` instead. The whole operation is atomic: if any part
fails the environment is left unchanged.
Duplicate keys in the payload collapse to a single removal. Values are never
read or returned.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.remove_environment_variables` (for any environment)
- `environment.<environment_id>.remove_environment_variables` (for a specific environment)
▾
Remove environment variables from an environment in a single atomic request.
This operation only deletes keys by name. Keys in the payload that exist are
removed; keys that are not present are ignored, since their absence already
matches the requested state. To replace or update values, use
`setEnvironmentVariables` instead. The whole operation is atomic: if any part
fails the environment is left unchanged.
Duplicate keys in the payload collapse to a single removal. Values are never
read or returned.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.remove_environment_variables` (for any environment)
- `environment.<environment_id>.remove_environment_variables` (for a specific environment)
Open-world
unkey_v2_environments_list_environments
Retrieve the environments within an app.
Use this to enumerate every environment in an app. Identify the app by its project slug and app slug. Results are ordered by environment id. An app has only a handful of environments, so all of them are returned in a single response.
**Required Permissions**
Your root key must have the following permission:
- `environment.*.read_environment` (to read environments in any app)
▾
Retrieve the environments within an app.
Use this to enumerate every environment in an app. Identify the app by its project slug and app slug. Results are ordered by environment id. An app has only a handful of environments, so all of them are returned in a single response.
**Required Permissions**
Your root key must have the following permission:
- `environment.*.read_environment` (to read environments in any app)
Open-world
unkey_v2_environments_list_environment_variables
Retrieve the environment variables for an environment.
Identify the environment by its project, app, and environment identifiers.
Results are ordered by variable id and paginated; when `hasMore` is true,
pass the returned `cursor` to fetch the next page.
`recoverable` variables are returned with their decrypted plaintext value.
`writeonly` variables never expose a value: only the key, kind, and
description are returned.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.read_environment_variables` (for any environment)
- `environment.<environment_id>.read_environment_variables` (for a specific environment)
▾
Retrieve the environment variables for an environment.
Identify the environment by its project, app, and environment identifiers.
Results are ordered by variable id and paginated; when `hasMore` is true,
pass the returned `cursor` to fetch the next page.
`recoverable` variables are returned with their decrypted plaintext value.
`writeonly` variables never expose a value: only the key, kind, and
description are returned.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.read_environment_variables` (for any environment)
- `environment.<environment_id>.read_environment_variables` (for a specific environment)
Open-world
unkey_v2_environments_get_environment
Retrieve a single environment by its id.
Use this to fetch environment details after creation or to verify an environment exists before performing operations.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.read_environment` (to read any environment)
- `environment.<environment_id>.read_environment` (to read a specific environment)
▾
Retrieve a single environment by its id.
Use this to fetch environment details after creation or to verify an environment exists before performing operations.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.read_environment` (to read any environment)
- `environment.<environment_id>.read_environment` (to read a specific environment)
Open-world
unkey_v2_domains_verify_domain
Restart verification for a custom domain.
Address the domain by its ID or by its name. Names are unique per workspace, so
`api.acme.com` is enough.
Call this after you correct the DNS records of a domain that shows `failed`, or to give a
`pending` domain a new 24-hour verification period. The domain goes back to `pending` and
the 24-hour period starts again.
The endpoint returns when Unkey accepts the retry. Poll `domains.getDomain` for the result.
A domain that is already `verified` returns a 412.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.verify_domain` (to verify domains in any environment)
- `environment.<environment_id>.verify_domain` (to verify domains in a specific environment)
▾
Restart verification for a custom domain.
Address the domain by its ID or by its name. Names are unique per workspace, so
`api.acme.com` is enough.
Call this after you correct the DNS records of a domain that shows `failed`, or to give a
`pending` domain a new 24-hour verification period. The domain goes back to `pending` and
the 24-hour period starts again.
The endpoint returns when Unkey accepts the retry. Poll `domains.getDomain` for the result.
A domain that is already `verified` returns a 412.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.verify_domain` (to verify domains in any environment)
- `environment.<environment_id>.verify_domain` (to verify domains in a specific environment)
Open-world
unkey_v2_domains_list_domains
List your custom domains with their verification status and DNS records.
Filter by project, app, or environment using IDs or slugs, or send `{}` to list
domains across your workspace.
Use any filter on its own or combine filters to narrow the results.
Results match all supplied filters. Omitting `environment` includes all matching environments.
Results include only domains you have permission to read, sorted by ID.
When `hasMore` is true, send the returned `cursor` to get the next page.
`status: verified` means the domain is verified. Unkey has configured routing and requested a
certificate. Each domain includes its full `dnsRecords`. Each record has a `verified` flag.
The flag shows which records Unkey has read back, so you can see which records are still
missing without a second call. Some providers hide a record from DNS lookups, for example a
proxied or flattened routing record. Such a record stays `false` while it serves traffic.
**Required Permissions**
Use a root key with the `environment.*.read_domain` permission.
A successful request returns an empty list if no matching domains are readable by your key.
▾
List your custom domains with their verification status and DNS records.
Filter by project, app, or environment using IDs or slugs, or send `{}` to list
domains across your workspace.
Use any filter on its own or combine filters to narrow the results.
Results match all supplied filters. Omitting `environment` includes all matching environments.
Results include only domains you have permission to read, sorted by ID.
When `hasMore` is true, send the returned `cursor` to get the next page.
`status: verified` means the domain is verified. Unkey has configured routing and requested a
certificate. Each domain includes its full `dnsRecords`. Each record has a `verified` flag.
The flag shows which records Unkey has read back, so you can see which records are still
missing without a second call. Some providers hide a record from DNS lookups, for example a
proxied or flattened routing record. Such a record stays `false` while it serves traffic.
**Required Permissions**
Use a root key with the `environment.*.read_domain` permission.
A successful request returns an empty list if no matching domains are readable by your key.
Open-world
unkey_v2_domains_get_domain
Retrieve a custom domain and its verification status.
Address the domain by its id or by its name. Names are unique per workspace, so
`api.acme.com` is sufficient. You do not need to supply a project, app, or environment.
Use this endpoint to poll after `domains.createDomain`. Verification runs in the background
and checks DNS approximately each minute.
`status: verified` means the domain is verified. Unkey has configured routing and requested a
certificate. Each entry in `dnsRecords` has a `verified` flag. The flag shows which records
Unkey has read back, so you can see which records are still missing. Some providers hide a
record from DNS lookups, for example a proxied or flattened routing record. Such a record stays
`false` while it serves traffic. `verificationError` gives the reason for the last failed
attempt.
`dnsRecords` contains the same values that `domains.createDomain` returned. Use it to recover
the values without creating the domain again.
**Important**: verification stops 24 hours after the domain was created, and the status becomes
`failed`. The window starts at `createdAt`, not at the last attempt.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.read_domain` (to read domains in any environment)
- `environment.<environment_id>.read_domain` (to read domains in a specific environment)
▾
Retrieve a custom domain and its verification status.
Address the domain by its id or by its name. Names are unique per workspace, so
`api.acme.com` is sufficient. You do not need to supply a project, app, or environment.
Use this endpoint to poll after `domains.createDomain`. Verification runs in the background
and checks DNS approximately each minute.
`status: verified` means the domain is verified. Unkey has configured routing and requested a
certificate. Each entry in `dnsRecords` has a `verified` flag. The flag shows which records
Unkey has read back, so you can see which records are still missing. Some providers hide a
record from DNS lookups, for example a proxied or flattened routing record. Such a record stays
`false` while it serves traffic. `verificationError` gives the reason for the last failed
attempt.
`dnsRecords` contains the same values that `domains.createDomain` returned. Use it to recover
the values without creating the domain again.
**Important**: verification stops 24 hours after the domain was created, and the status becomes
`failed`. The window starts at `createdAt`, not at the last attempt.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.read_domain` (to read domains in any environment)
- `environment.<environment_id>.read_domain` (to read domains in a specific environment)
Open-world
unkey_v2_domains_delete_domain
Delete a custom domain from your workspace.
Address the domain by its id or by its name. Names are unique per workspace, so
`api.acme.com` is enough.
Unkey stops serving the domain. Later requests fail with a certificate error. The DNS
records at your provider stay in place.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.delete_domain` (to delete domains in any environment)
- `environment.<environment_id>.delete_domain` (to delete domains in a specific environment)
▾
Delete a custom domain from your workspace.
Address the domain by its id or by its name. Names are unique per workspace, so
`api.acme.com` is enough.
Unkey stops serving the domain. Later requests fail with a certificate error. The DNS
records at your provider stay in place.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.delete_domain` (to delete domains in any environment)
- `environment.<environment_id>.delete_domain` (to delete domains in a specific environment)
Open-world
unkey_v2_domains_create_domain
Attach a custom domain to an environment and start verifying it.
The domain is created in the `pending` state and does not serve traffic until verification succeeds. Verification runs in the background and polls DNS, so it is eventually consistent.
The response returns `dnsRecords`: every record needed to finish setup, already resolved for whether this domain is an apex or a subdomain. Create every entry exactly as given. One record establishes routing and one proves ownership, and both are needed: whether ownership can be inferred from the routing record depends on how your provider publishes it, and a name another workspace has already verified can only be claimed through the ownership record. Neither is knowable before the records exist.
When your DNS provider supports Domain Connect, the response also carries a `domainConnect` object; opening its `url` applies the same records at the provider in one step. The object is absent when the shortcut is unavailable.
Domains are unique per workspace, so the same name cannot be attached to two environments. Attaching a domain that already exists in your workspace returns a 409 conflict.
How many domains you may attach is set by your plan. Attaching one beyond that allowance returns a 403; upgrade the plan or remove a domain you no longer need.
**Important**: verification stops after 24 hours without the required DNS records, and the domain moves to `failed`.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.create_domain` (to attach domains to any environment)
- `environment.<environment_id>.create_domain` (to attach domains to a specific environment)
▾
Attach a custom domain to an environment and start verifying it.
The domain is created in the `pending` state and does not serve traffic until verification succeeds. Verification runs in the background and polls DNS, so it is eventually consistent.
The response returns `dnsRecords`: every record needed to finish setup, already resolved for whether this domain is an apex or a subdomain. Create every entry exactly as given. One record establishes routing and one proves ownership, and both are needed: whether ownership can be inferred from the routing record depends on how your provider publishes it, and a name another workspace has already verified can only be claimed through the ownership record. Neither is knowable before the records exist.
When your DNS provider supports Domain Connect, the response also carries a `domainConnect` object; opening its `url` applies the same records at the provider in one step. The object is absent when the shortcut is unavailable.
Domains are unique per workspace, so the same name cannot be attached to two environments. Attaching a domain that already exists in your workspace returns a 409 conflict.
How many domains you may attach is set by your plan. Attaching one beyond that allowance returns a 403; upgrade the plan or remove a domain you no longer need.
**Important**: verification stops after 24 hours without the required DNS records, and the domain moves to `failed`.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.create_domain` (to attach domains to any environment)
- `environment.<environment_id>.create_domain` (to attach domains to a specific environment)
Open-world
unkey_v2_deployments_stop_deployment
Stop a running preview deployment. Stopped deployments keep their
configuration and can be resumed later with `startDeployment`.
The deployment must be ready and running, and must belong to a
non-production environment; production deployments cannot be stopped.
A deployment that is already draining from a previous stop is rejected
with a precondition error.
Stopping is asynchronous: this endpoint only enqueues the stop and returns
immediately. Poll `getDeployment` until the status reaches `stopped`.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.stop_deployment` (to stop deployments in any environment)
- `environment.<environment_id>.stop_deployment` (to stop deployments in a specific environment)
▾
Stop a running preview deployment. Stopped deployments keep their
configuration and can be resumed later with `startDeployment`.
The deployment must be ready and running, and must belong to a
non-production environment; production deployments cannot be stopped.
A deployment that is already draining from a previous stop is rejected
with a precondition error.
Stopping is asynchronous: this endpoint only enqueues the stop and returns
immediately. Poll `getDeployment` until the status reaches `stopped`.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.stop_deployment` (to stop deployments in any environment)
- `environment.<environment_id>.stop_deployment` (to stop deployments in a specific environment)
Open-world
unkey_v2_deployments_start_deployment
Start a deployment that was previously stopped with `stopDeployment`, so it
serves traffic again. The deployment keeps the configuration it had when it
was stopped; nothing is rebuilt or redeployed.
The deployment must currently be stopped, and must belong to a
non-production environment. Production deployments are never stopped, so
they cannot be started.
Starting is asynchronous: this endpoint only enqueues the start and returns
immediately. Poll `getDeployment` until the status reaches `ready`.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.start_deployment` (to start deployments in any environment)
- `environment.<environment_id>.start_deployment` (to start deployments in a specific environment)
▾
Start a deployment that was previously stopped with `stopDeployment`, so it
serves traffic again. The deployment keeps the configuration it had when it
was stopped; nothing is rebuilt or redeployed.
The deployment must currently be stopped, and must belong to a
non-production environment. Production deployments are never stopped, so
they cannot be started.
Starting is asynchronous: this endpoint only enqueues the start and returns
immediately. Poll `getDeployment` until the status reaches `ready`.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.start_deployment` (to start deployments in any environment)
- `environment.<environment_id>.start_deployment` (to start deployments in a specific environment)
Open-world
unkey_v2_deployments_rollback_deployment
Roll live traffic back to a previous deployment. `deploymentId` is the
deployment to roll back TO; the app's current deployment is used as
the rollback source automatically.
The target deployment must be ready, not already shutting down, belong to
the production environment, and must not itself be the current deployment.
After a rollback the app is marked as rolled back, which prevents new
deployments from automatically taking over live traffic. Promote the
rolled-back deployment (or a newer one) to clear this state.
Rollback runs as a durable workflow: this endpoint returns once the
rollback is accepted. Poll `getDeployment` or `listDeployments` to observe
the result.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.rollback_deployment` (to roll back deployments in any environment)
- `environment.<environment_id>.rollback_deployment` (to roll back deployments in a specific environment)
▾
Roll live traffic back to a previous deployment. `deploymentId` is the
deployment to roll back TO; the app's current deployment is used as
the rollback source automatically.
The target deployment must be ready, not already shutting down, belong to
the production environment, and must not itself be the current deployment.
After a rollback the app is marked as rolled back, which prevents new
deployments from automatically taking over live traffic. Promote the
rolled-back deployment (or a newer one) to clear this state.
Rollback runs as a durable workflow: this endpoint returns once the
rollback is accepted. Poll `getDeployment` or `listDeployments` to observe
the result.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.rollback_deployment` (to roll back deployments in any environment)
- `environment.<environment_id>.rollback_deployment` (to roll back deployments in a specific environment)
Open-world
unkey_v2_deployments_promote_deployment
Promote a deployment to become the current deployment for its environment.
All sticky domains are reassigned from the current deployment to the
promoted one, and the previous deployment is scheduled for standby.
The deployment must be ready, not already shutting down, belong to the
production environment, and its app must already have a current deployment.
Promoting the deployment that is already current fails, unless the app is in
a rolled-back state, in which case promoting the current deployment
confirms the rollback and re-enables automatic promotion of future
deployments.
Promotion runs as a durable workflow: this endpoint returns once the
promotion is accepted. Poll `getDeployment` or `listDeployments` to observe
the result.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.promote_deployment` (to promote deployments in any environment)
- `environment.<environment_id>.promote_deployment` (to promote deployments in a specific environment)
▾
Promote a deployment to become the current deployment for its environment.
All sticky domains are reassigned from the current deployment to the
promoted one, and the previous deployment is scheduled for standby.
The deployment must be ready, not already shutting down, belong to the
production environment, and its app must already have a current deployment.
Promoting the deployment that is already current fails, unless the app is in
a rolled-back state, in which case promoting the current deployment
confirms the rollback and re-enables automatic promotion of future
deployments.
Promotion runs as a durable workflow: this endpoint returns once the
promotion is accepted. Poll `getDeployment` or `listDeployments` to observe
the result.
**Required Permissions**
Your root key must have one of the following permissions:
- `environment.*.promote_deployment` (to promote deployments in any environment)
- `environment.<environment_id>.promote_deployment` (to promote deployments in a specific environment)
Open-world
unkey_v2_deployments_list_deployments
Retrieve a paginated list of deployments within a workspace, newest first.
Filter by project, app, environment, lifecycle status, git branch, and
creation time. All filters are optional; with none set, every deployment in
the workspace is returned. Filters nest: `app` requires `project`, and
`environment` and `branch` require both `project` and `app`. Results are
paginated; when `hasMore` is true, pass the returned `cursor` to fetch the
next page.
**Required Permissions**
Your root key must have this permission:
- `unkey:v1:<workspace_id>:projects/<project_id>/apps/<app_id>/environments/<environment_id>/deployments/*#read`
(use `*` for every level you do not filter by)
The permission must cover every deployment the filters select: a grant on
one environment is not sufficient for a request that spans more than that
environment.
▾
Retrieve a paginated list of deployments within a workspace, newest first.
Filter by project, app, environment, lifecycle status, git branch, and
creation time. All filters are optional; with none set, every deployment in
the workspace is returned. Filters nest: `app` requires `project`, and
`environment` and `branch` require both `project` and `app`. Results are
paginated; when `hasMore` is true, pass the returned `cursor` to fetch the
next page.
**Required Permissions**
Your root key must have this permission:
- `unkey:v1:<workspace_id>:projects/<project_id>/apps/<app_id>/environments/<environment_id>/deployments/*#read`
(use `*` for every level you do not filter by)
The permission must cover every deployment the filters select: a grant on
one environment is not sufficient for a request that spans more than that
environment.
Open-world
unkey_v2_deployments_list_build_logs
Retrieve the build output of a deployment as a list of log entries, in the
order the build printed them. A log entry is one chunk of build output,
and can contain several lines or part of a line.
Poll this endpoint to follow a running build:
- Send the `pagination.cursor` of the last response as `cursor`. The
response contains only the entries after it.
- When `hasMore` is true, request again now.
- When `hasMore` is false, you have all entries so far. Wait,
then request again with the same cursor.
- The cursor is absent only when the request had no cursor and the build
has no entries yet.
- A response can contain fewer than `limit` entries and still have
`hasMore: true` when the entries are large.
New entries become visible up to a few seconds after the build prints
them. To know that a build is done, check the deployment status with
`getDeployment`. After the status is no longer `building`, request until
you get an empty response at least 5 seconds later.
When a build attempt is retried, an entry from the earlier attempt can
arrive after the cursor has moved past it, and a poll does not return it.
A request without a cursor returns it. A deployment from a prebuilt image
has no build and returns no entries. Build logs are kept for 3 months.
**Required Permissions**
Your root key must have the following permission:
- `unkey:v1:<workspace_id>:projects/<project_id>/apps/<app_id>/environments/<environment_id>/deployments/<deployment_id>/buildLogs#read`
▾
Retrieve the build output of a deployment as a list of log entries, in the
order the build printed them. A log entry is one chunk of build output,
and can contain several lines or part of a line.
Poll this endpoint to follow a running build:
- Send the `pagination.cursor` of the last response as `cursor`. The
response contains only the entries after it.
- When `hasMore` is true, request again now.
- When `hasMore` is false, you have all entries so far. Wait,
then request again with the same cursor.
- The cursor is absent only when the request had no cursor and the build
has no entries yet.
- A response can contain fewer than `limit` entries and still have
`hasMore: true` when the entries are large.
New entries become visible up to a few seconds after the build prints
them. To know that a build is done, check the deployment status with
`getDeployment`. After the status is no longer `building`, request until
you get an empty response at least 5 seconds later.
When a build attempt is retried, an entry from the earlier attempt can
arrive after the cursor has moved past it, and a poll does not return it.
A request without a cursor returns it. A deployment from a prebuilt image
has no build and returns no entries. Build logs are kept for 3 months.
**Required Permissions**
Your root key must have the following permission:
- `unkey:v1:<workspace_id>:projects/<project_id>/apps/<app_id>/environments/<environment_id>/deployments/<deployment_id>/buildLogs#read`
Open-world
unkey_v2_deployments_get_deployment
Retrieve a single deployment by its id.
Use this to check a deployment's status after creating it, or to inspect the
runtime configuration of an existing deployment.
**Required Permissions**
Your root key must have this permission:
- `unkey:v1:<workspace_id>:projects/<project_id>/apps/<app_id>/environments/<environment_id>/deployments/<deployment_id>#read`
(use `*` for any level)
▾
Retrieve a single deployment by its id.
Use this to check a deployment's status after creating it, or to inspect the
runtime configuration of an existing deployment.
**Required Permissions**
Your root key must have this permission:
- `unkey:v1:<workspace_id>:projects/<project_id>/apps/<app_id>/environments/<environment_id>/deployments/<deployment_id>#read`
(use `*` for any level)
Open-world
unkey_v2_apps_update_app
Update an existing app, identified by its id.
The app name, slug, default branch, and delete protection setting can be changed. Omitted fields are left unchanged. Changing the slug affects the deployment domains generated for this app.
**Important**: The slug cannot collide with an existing app in the same project. A duplicate slug returns a 409 conflict.
**Required Permissions**
Your root key must have one of the following permissions:
- `app.*.update_app` (to update any app)
- `app.<app_id>.update_app` (to update a specific app)
▾
Update an existing app, identified by its id.
The app name, slug, default branch, and delete protection setting can be changed. Omitted fields are left unchanged. Changing the slug affects the deployment domains generated for this app.
**Important**: The slug cannot collide with an existing app in the same project. A duplicate slug returns a 409 conflict.
**Required Permissions**
Your root key must have one of the following permissions:
- `app.*.update_app` (to update any app)
- `app.<app_id>.update_app` (to update a specific app)
Open-world
unkey_v2_apps_list_apps
Retrieve a paginated list of apps within a project.
Use this to enumerate every app in a project. Results are ordered by app id and paginated; when `hasMore` is true, pass the returned `cursor` to fetch the next page.
**Required Permissions**
Your root key must have the following permission:
- `app.*.read_app` (to read apps in any project)
▾
Retrieve a paginated list of apps within a project.
Use this to enumerate every app in a project. Results are ordered by app id and paginated; when `hasMore` is true, pass the returned `cursor` to fetch the next page.
**Required Permissions**
Your root key must have the following permission:
- `app.*.read_app` (to read apps in any project)
Open-world
unkey_v2_apps_get_app
Retrieve a single app by its id or slug within a project.
Use this to fetch app details after creation or to verify an app exists before performing operations.
**Required Permissions**
Your root key must have one of the following permissions:
- `app.*.read_app` (to read any app)
- `app.<app_id>.read_app` (to read a specific app)
▾
Retrieve a single app by its id or slug within a project.
Use this to fetch app details after creation or to verify an app exists before performing operations.
**Required Permissions**
Your root key must have one of the following permissions:
- `app.*.read_app` (to read any app)
- `app.<app_id>.read_app` (to read a specific app)
Open-world
unkey_v2_apps_delete_app
Delete an existing app, identified by its id.
Deletion is asynchronous and eventually consistent. The app and all of its associated resources (environments, deployments, custom domains) are torn down by a background workflow. A successful response indicates the deletion was enqueued, not that every resource has already been removed.
Apps with delete protection enabled cannot be deleted until protection is disabled.
**Required Permissions**
Your root key must have one of the following permissions:
- `app.*.delete_app` (to delete any app)
- `app.<app_id>.delete_app` (to delete a specific app)
▾
Delete an existing app, identified by its id.
Deletion is asynchronous and eventually consistent. The app and all of its associated resources (environments, deployments, custom domains) are torn down by a background workflow. A successful response indicates the deletion was enqueued, not that every resource has already been removed.
Apps with delete protection enabled cannot be deleted until protection is disabled.
**Required Permissions**
Your root key must have one of the following permissions:
- `app.*.delete_app` (to delete any app)
- `app.<app_id>.delete_app` (to delete a specific app)
Open-world
unkey_v2_apps_create_app
Create an app within a project. The app is created with default `production` and `preview` environments.
Set exactly one source. Use `git` to create a GitHub-sourced app and connect its repository. Use `oci` to create an app from a prebuilt OCI image.
The slug you provide is the stable, caller-defined handle used to reference this app. It must be unique within the project.
**Important**: The slug cannot collide with an existing app in the same project. A duplicate slug returns a 409 conflict.
**Required Permissions**
Your root key must have one of the following permissions:
- `project.*.create_app` (to create apps in any project)
- `project.<project_id>.create_app` (to create apps in a specific project)
▾
Create an app within a project. The app is created with default `production` and `preview` environments.
Set exactly one source. Use `git` to create a GitHub-sourced app and connect its repository. Use `oci` to create an app from a prebuilt OCI image.
The slug you provide is the stable, caller-defined handle used to reference this app. It must be unique within the project.
**Important**: The slug cannot collide with an existing app in the same project. A duplicate slug returns a 409 conflict.
**Required Permissions**
Your root key must have one of the following permissions:
- `project.*.create_app` (to create apps in any project)
- `project.<project_id>.create_app` (to create apps in a specific project)
Open-world
unkey_v2_analytics_get_runtime_logs
A query can use only the public alias `runtime_logs_v1`. CTEs, subqueries, UNION, and EXCEPT are permitted.
The root key must have the `project.*.read_runtime_logs` permission.
Unkey limits each query to the workspace of the root key. To get the logs of one project, app, environment, or deployment, add a filter on `project_id`, `app_id`, `environment_id`, or `deployment_id`.
The workspace retention period and the workspace query limits apply.
For the table, the columns, and more query examples, see [Query runtime logs](/platform/analytics/get-runtime-logs).
▾
A query can use only the public alias `runtime_logs_v1`. CTEs, subqueries, UNION, and EXCEPT are permitted.
The root key must have the `project.*.read_runtime_logs` permission.
Unkey limits each query to the workspace of the root key. To get the logs of one project, app, environment, or deployment, add a filter on `project_id`, `app_id`, `environment_id`, or `deployment_id`.
The workspace retention period and the workspace query limits apply.
For the table, the columns, and more query examples, see [Query runtime logs](/platform/analytics/get-runtime-logs).
Open-world
unkey_v2_analytics_get_gateway_requests
A query can use only the public alias `gateway_requests_v1`. CTEs, subqueries, UNION, and EXCEPT are permitted.
The root key must have the `project.*.read_gateway_requests` permission.
Unkey limits each query to the workspace of the root key. To get the data for one project, app, or environment, add a filter on `project_id`, `app_id`, or `environment_id`.
The workspace retention period and the workspace query limits apply.
For the columns and more query examples, see the gateway request analytics documentation.
▾
A query can use only the public alias `gateway_requests_v1`. CTEs, subqueries, UNION, and EXCEPT are permitted.
The root key must have the `project.*.read_gateway_requests` permission.
Unkey limits each query to the workspace of the root key. To get the data for one project, app, or environment, add a filter on `project_id`, `app_id`, or `environment_id`.
The workspace retention period and the workspace query limits apply.
For the columns and more query examples, see the gateway request analytics documentation.
Open-world
No tools match your search.
These instructions are provided to LLMs when they connect to help them understand how to use the server effectively.
# Unkey Deploy Manage projects, apps, environments, deployments, domains, and edge gateway policies. ## Resource hierarchy `workspace → project → app → environment → deployment` Most calls need the parent identifiers. Projects and apps are addressable by id or slug; slugs are caller-defined and must be unique within their parent. Creating an app provisions `production` and `preview` environments automatically. ## Typical setup flow 1. `projects.createProject` → `apps.createApp` (set exactly one source: `git` or `oci`). 2. For `git` apps: `github.installApp` first, open the returned URL in a browser, then connect the repo via the app's `git` field. 3. `environments.setEnvironmentVariables`, `environments.updateSettings` (build/runtime/regions). 4. `deployments.createDeployment` → poll `deployments.getDeployment`. 5. Optional: `domains.createDomain`, `gateway.setPolicies`. ## Asynchronous operations Create, promote, rollback, start, stop, verify, and delete all return on acceptance, not completion. Always poll: - deployments → `deployments.getDeployment` (status) and `deployments.listBuildLogs` (output, cursor-based; empty response ≠ build finished — check status first) - domains → `domains.getDomain` - deletions of projects/apps → eventually consistent; resources tear down in the background ## Traffic control - Production only: `promoteDeployment`, `rollbackDeployment`. Target must be `ready`. - Non-production only: `stopDeployment` / `startDeployment` (config preserved, nothing rebuilt). - After a rollback the app is flagged rolled-back and new deployments stop auto-promoting. Promote any ready deployment (including the current one) to clear it. ## Replace vs. merge semantics - `gateway.setPolicies`: full atomic replace, order = evaluation order, ids regenerated. Use `gateway.listPolicies` to get fresh ids before `gateway.updatePolicy`. - `environments.setEnvironmentVariables`: upsert by default; `prune: true` makes it a full replace. Each variable is written whole — omitted optional fields reset to defaults. - `environments.updateSettings`: per-field merge, but `regions` replaces the whole set; send `null` to clear nullable fields. ## Constraints - Delete protection must be disabled before deleting a project or app. - Duplicate slugs and duplicate domain names → 409. - `writeonly` env vars can never be read back; use `kind: recoverable` if you need reads. - Domain verification expires 24h after `createdAt`; re-arm with `domains.verifyDomain`. Create every returned DNS record. - Check `workspace.getLimits` before adding domains, drains, or reserving CPU/memory/disk. `workspace.getUsage` lags up to 15 min and can change for 7 days. - Log/metrics windows are capped (≤100 days) and bounded by workspace retention; build logs kept 3 months. - Analytics tools accept SQL against only `runtime_logs_v1` / `gateway_requests_v1`, scoped to your workspace — filter by `project_id`/`app_id`/`environment_id`/`deployment_id` to narrow.
https://mcp.unkey.com/mcp/compute
If you have a client that's not listed above, access the raw MCP
configuration below. Check out
the troubleshooting documentation
for more help.
{
"command": "npx",
"args": [
"mcp-remote@0.1.25",
"https://mcp.unkey.com/mcp/compute",
"--header",
"Mcp-Unkey-V2-Bearer:${UNKEY_ROOT_KEY}"
],
"env": {
"UNKEY_ROOT_KEY": "<your-value-here>"
}
}