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

# API keys

> Choose, use, rotate, and revoke personal and service-account credentials for Horizon.

API keys are bearer credentials for non-interactive access to Horizon. Use them
when a script, CI job, Terraform run, service account, or MCP client needs to
authenticate without completing an interactive sign-in flow.

An API key proves the identity of the actor that owns it. That owner can be a
user or a service account. The key does not carry a separate permission scope:
Horizon evaluates the owner's current organization role, server access, and
capability access on each request.

<Info>
  Horizon API keys start with `fmcp_`. The full key is shown only once, when you
  create it. Store it before closing the creation dialog.
</Info>

## Key types

Choose the owner based on who should appear as the actor and how long the
workflow should outlive a person.

| Key type            | Identity scope                                                          | Best for                                                                                              |
| ------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Personal API key    | Acts as one user across every organization where that user is a member. | Personal scripts, local testing, and MCP clients that cannot open an interactive sign-in flow.        |
| Service-account key | Acts as one service account in the organization that owns it.           | CI/CD, Terraform, scheduled jobs, and production integrations that must survive employee offboarding. |

<Tip>
  For production automation, prefer service accounts. A service account makes
  ownership explicit and avoids depending on a person's membership or personal
  key lifecycle.
</Tip>

## Permissions

A key can perform only the actions its owner can perform. For the REST API,
organization and server permissions control which resources the actor can read
or change. For an MCP endpoint, organization membership, server access, and
capability policies control which tools, resources, and prompts the actor can
use.

Keys do not elevate access or preserve permissions that their owner has lost.
See [Roles](/roles) for the organization and server role contracts, and
[Authorization](/platform/authorization) for how Horizon resolves them on each
request.

## Supported surfaces

Both key types use the same header on the two customer-facing surfaces that
accept Horizon API keys:

```http theme={null}
Authorization: Bearer fmcp_...
```

The target URL decides whether Horizon applies management permissions or MCP
server access.

### REST API

The Horizon REST API accepts personal and service-account keys. Each operation
checks whether the owning actor has the required access. Use the interactive
[API reference](https://horizon.prefect.io/api/v0/docs) for the current routes,
request schemas, and response schemas.

This request lists the organizations available to the key owner. For a one-off
test, read the key without saving it in shell history. In automation, load the
same environment variable from your secret manager.

```bash theme={null}
read -rsp "Horizon API key: " HORIZON_API_KEY
echo

curl --fail-with-body \
  https://horizon.prefect.io/api/v0/me/organizations \
  --header "Authorization: Bearer ${HORIZON_API_KEY}"

unset HORIZON_API_KEY
```

### MCP endpoints

A protected hosted, external, or remix server accepts a Horizon API key at its
serving URL. The gateway resolves the key owner, checks organization and server
access, applies capability permissions, and then forwards an accepted MCP
request.

Use the stable `/mcp` URL from the server's **Connect** page. This example sends
an MCP `initialize` request directly. Most users configure the same URL and
header in an [MCP client](/connect-a-client) instead.

```bash theme={null}
read -rsp "Horizon API key: " HORIZON_API_KEY
echo
HORIZON_MCP_URL="https://weather-mcp.fastmcp.app/mcp"

curl --fail-with-body "${HORIZON_MCP_URL}" \
  --header "Authorization: Bearer ${HORIZON_API_KEY}" \
  --header "Content-Type: application/json" \
  --header "Accept: application/json, text/event-stream" \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "capabilities": {},
      "clientInfo": {"name": "curl", "version": "1.0"}
    }
  }'

unset HORIZON_API_KEY
```

## Credential boundaries

A Horizon API key authenticates only at a Horizon API or gateway boundary.
Adjacent surfaces use different credentials.

| Surface                                             | Authentication behavior                                                                                                                                                                                                                                                       |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Dashboard and browser authorization flows           | Dashboard sign-in and consent pages require an interactive user session. An API key cannot create a browser session.                                                                                                                                                          |
| Downstream services                                 | A Horizon key identifies the caller to Horizon. A remote MCP server or an API called by hosted server code uses the OAuth token or API key configured for that service. See [External authentication](/platform/external-authentication) for this second credential boundary. |
| Hosted servers with Horizon authentication disabled | Horizon does not validate an `fmcp_` key for these endpoints. The hosted server decides which credentials, if any, it accepts.                                                                                                                                                |

<Warning>
  A service-account key can authenticate to a protected hosted server, but
  per-actor delegated authorization is not supported for service accounts.
  Browser authorization saves the downstream credential for the signed-in user,
  not the service account. Automation must provide its upstream credential
  through the hosted server, such as with an
  [environment variable](/environment-variables), until service-account
  delegated authorization is supported.
</Warning>

## Personal keys

Create a personal API key for work that should act as your user identity.

<Steps>
  <Step title="Open API Keys">
    In Horizon, open the user menu and select <b>API Keys</b>.
  </Step>

  <Step title="Create the key">
    Select <b>Create API Key</b>. Add a descriptor that identifies where the key
    will be used, such as `local-client` or `staging-ci`.
  </Step>

  <Step title="Store the secret">
    Copy the `fmcp_` value from the reveal dialog and store it in the client,
    CI secret store, or secret manager that will send requests.
  </Step>

  <Step title="Grant server access">
    Confirm the user has access to every organization and server the key needs.
    The key cannot exceed the user's current access.
  </Step>
</Steps>

## Create a service-account API key

Create service-account keys from an organization's service account settings.
Service accounts are designed for automation, so their keys can be rotated
without involving a human user's account.

<Steps>
  <Step title="Open Service Accounts">
    Go to organization settings and select <b>Service Accounts</b>.
  </Step>

  <Step title="Create or select a service account">
    Create a new service account for the automation, or open an existing
    service account that already owns the right access.
  </Step>

  <Step title="Copy the generated key">
    New service accounts receive an API key when created. Existing service
    accounts can have additional keys added from the service account details
    panel.
  </Step>

  <Step title="Assign access">
    Give the service account the organization role, explicit server grants, and
    capability access it needs.
  </Step>
</Steps>

Service accounts can have up to two active API keys at a time. This supports
zero-downtime rotation: add a replacement key, move traffic, then revoke the
old key.

## Rotation workflow

Rotate keys by introducing a replacement before revoking the old key.

<Steps>
  <Step title="Create a replacement key">
    Create a new key for the same user or service account. For service
    accounts, keep the two-key limit in mind.
  </Step>

  <Step title="Update the client">
    Change the secret value used by the MCP client, CI job, Terraform run, or
    integration.
  </Step>

  <Step title="Verify new traffic">
    Confirm the client succeeds with the new key. Check request logs or the
    client response before removing the old key.
  </Step>

  <Step title="Revoke the old key">
    Delete or revoke the old key. Revocation stops that key from
    authenticating immediately.
  </Step>
</Steps>

## Lifecycle and access

API key behavior follows the owner and the active key record.

<AccordionGroup>
  <Accordion title="A user leaves an organization">
    Removing the member deletes their membership and explicit server grants in
    that organization. Their personal API key remains active, but it loses
    access to the organization they left. The same key can still access other
    organizations where the user remains a member.

    Move shared automation to a service account before offboarding the user.
    Reinviting the user later does not restore their previous explicit server
    grants.
  </Accordion>

  <Accordion title="The key is revoked">
    Horizon stops accepting the key immediately. Existing clients must be
    updated to use another key or sign-in method.
  </Accordion>

  <Accordion title="The full secret is lost">
    Horizon cannot show the full key again. Create a new key, update the
    client, and revoke the old key if it might still be in use.
  </Accordion>

  <Accordion title="A service account is suspended or deleted">
    Requests made with that service account's keys can no longer use the
    suspended or deleted identity. Replace the key with one owned by an active
    service account that has the required access.
  </Accordion>
</AccordionGroup>

## Security

Store keys in a secret manager or the encrypted secret store provided by your CI
system. Keep them out of source control, client-side application code, shell
history, issue text, screenshots, logs, and traces. Treat an exposed key as
compromised and rotate it.

Give each key a descriptor that identifies its integration, and use a separate
key per integration so each credential can be rotated without disrupting
unrelated clients. Keys owned by the same actor still share one identity and
permission set. For least privilege and clearer audit attribution, create a
separate service account for each production workflow and grant only the access
it needs.

[Request logs and usage views](/observability) attribute protected MCP traffic
to the user or service account that owns the key. They do not distinguish
between multiple keys owned by that same actor, and they never display the raw
key. Use separate service accounts when audit records must distinguish one
automation from another.

## Common failures

<AccordionGroup>
  <Accordion title="A request returns 401">
    Horizon did not accept the credential. Check that the request uses
    `Authorization: Bearer`, that the key starts with `fmcp_`, that the full
    value was copied, and that the key has not been revoked.
  </Accordion>

  <Accordion title="A request returns 403">
    The key authenticated, but the owning actor does not have permission for
    the organization, server, or action. Check the owner's organization role,
    server grants, default server role, and capability policy.
  </Accordion>

  <Accordion title="A protected server returns 404">
    The deployment URL may not map to a live server, or Horizon may be
    concealing a server from an authenticated actor that lacks discovery
    access. Confirm the URL and the owner's server access.
  </Accordion>

  <Accordion title="A service account cannot add another key">
    Revoke an unused service-account key first. Service accounts support up to
    two active keys at a time.
  </Accordion>
</AccordionGroup>

## Related docs

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/platform/authentication">
    Learn how API keys, user tokens, and browser sessions authenticate.
  </Card>

  <Card title="Authorization" icon="shield" href="/platform/authorization">
    Learn how Horizon decides what an authenticated actor can do.
  </Card>
</CardGroup>
