---
title: Authentication
description: Authenticate AI API requests with a WP Engine AI-issued API key, and pick the right key type and scopes.
url: https://developers.wpengine.com/docs/ai/api/authentication/
image: https://developers.wpengine.com/og/docs/ai/api/authentication.png
---

# Authentication

Every request to the AI API except the model catalog must include a bearer token in the `Authorization` header:

```http
Authorization: Bearer <token>
```

The model catalog (`GET /v1/models` and `GET /v1/models/{owner}/{model}/schema`) is public and requires no authentication.

API keys are the credential for developer integrations with the HTTP API. MCP clients authenticate with [OAuth](https://developers.wpengine.com/docs/ai/api/authentication/#mcp-clients-authenticate-with-oauth). You create and revoke keys in the [WP Engine User Portal](https://my.wpengine.com/ai/gateways-and-api/api-keys).

## Key types

There are two types of key, and the difference is whether the key carries a person:

| Type        | Prefix     | Acts as                   | Use for                                        |
| ----------- | ---------- | ------------------------- | ---------------------------------------------- |
| **User**    | `wpe_pat_` | The person who created it | Anything acting for a person over the HTTP API |
| **Account** | `wpe_`     | Nobody                    | Service-to-service calls and automation        |

The prefix is the quickest way to tell which kind you pasted into a client.

> **Tip**
>
> The API and its error messages call these `personal` and `project` keys.

A user key is visible only to the person who created it. Nobody else on the account can see it, edit it, or revoke it — to them it does not exist. Take that into account before a user key becomes load-bearing in shared infrastructure.

## Creating a key

1. In the WP Engine User Portal, go to **AI** → **Gateways & API** → **API Keys**.

2. Select **Create API Key**.

3. Enter a **Name** that tells you where the key is used, such as `My Company Production`.

4. Choose the **Key Type** — **Account** or **User**.

5. Choose the **Permissions**:

   - **Full access** — write on every scope.
   - **Read only** — read on every scope.
   - **Restricted** — set **Chat**, **Image**, **Speech**, **Transcribe**, and **MCP** individually to **Write**, **Read**, or **None**.

6. Select **Create Key**, then copy the secret. It is displayed **once**.

![Screenshot: Creating a User API key in the WP Engine User Portal](https://developers.wpengine.com/_astro/create-user-key.COcZrl4a_LKIHd.webp)

> **Keep it secret, keep it safe!**
>
> Keys are only displayed once, save it somewhere safe before closing the dialog.
>
> This key is sensitive, keep it out of source control, client-side code, logs, and screenshots. If one does leak, you suspect it could have leaked, or you simply lose it, [replace it](https://developers.wpengine.com/docs/ai/api/authentication/#rotating-a-key).

## Scopes

Every endpoint requires a scope at a level — `read` or `write`, where `write` also grants `read`. A key that does not hold the level its endpoint requires returns `403`.

A key’s scopes come from the permissions you picked when you created it. **Full access** and **Read only** cover every scope in the table below. **Restricted** lets you set `chat`, `image`, `speech`, `transcribe`, and `mcp` individually; the remaining scopes are `none` on a restricted key, so pick **Full access** or **Read only** if you need the knowledge base, agents, or sessions endpoints.

The `mcp` scope is deprecated. It lets a key call MCP tools only while the server still accepts API keys, and it needs `write`. There is no read tier: a key holding `mcp: read` authenticates and then fails every tool call with a `403`. Connect MCP clients with [OAuth](https://developers.wpengine.com/docs/ai/api/authentication/#mcp-clients-authenticate-with-oauth) instead.

| Scope            | Covers                                                                                                                                                                   |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `chat`           | `POST /v1/chat/completions`, `POST /v1/messages`, `POST /v1/messages/count_tokens`, `POST /v1/content/summarize`, `POST /v1/content/suggest-taxonomy`. All need `write`. |
| `image`          | `POST /v1/images/generations` and `POST /v1/images/alt-text`. Both need `write`.                                                                                         |
| `speech`         | `POST /v1/audio/speech`. Needs `write`.                                                                                                                                  |
| `transcribe`     | `POST /v1/audio/transcriptions`. Needs `write`.                                                                                                                          |
| `collections`    | Knowledge base collections under `/v1/kb/collections`, and `/v1/sites/{site_identifier}`. `read` to get or list, `write` to create, update, or delete.                   |
| `documents`      | Documents under `/v1/kb/collections/{id}/documents`. `read` to fetch one, `write` to index or delete.                                                                    |
| `search`         | `POST /v1/kb/collections/{id}/search`. Needs `read`.                                                                                                                     |
| `agents`         | `/v1/agents` and `/v1/sessions`. `read` to get or list, `write` to create, update, archive, or delete.                                                                   |
| `session_events` | Session events and response feedback under `/v1/sessions/{session_id}`. Accepted in place of `agents` on those routes only.                                              |
| `mcp`            | Deprecated. `/v1/mcp`, only while the server accepts API keys. Needs `write`.                                                                                            |

> **Tip**
>
> Most endpoints require a single scope. The session event and response feedback routes are the exception — they accept either `agents` or `session_events`.

## MCP clients authenticate with OAuth

An MCP client authenticates a user with OAuth, so each call runs as that user.

Why: an OAuth session belongs to one user, so the server attributes every call to that user and checks that user’s access on every call.

Running a WordPress ability needs the user who authenticated with OAuth to connect their WordPress account to the target site. The server checks it on every call:

- `run_site_ability` checks that this user has connected their WordPress account to the target site
- `wp_connection_status` in `list_account_sites` reports whether this user is connected, site by site
- Audit logs name this user as the acting user for every ability run

To set a client up, see [Connect Claude Code](https://developers.wpengine.com/docs/ai/api/mcp/how-to/configure-claude-code/) or [Connect Claude Desktop](https://developers.wpengine.com/docs/ai/api/mcp/how-to/configure-claude-desktop/). To try the server directly, run [MCP Inspector](https://github.com/modelcontextprotocol/inspector) and use its **OAuth** sign-in:

Terminal window

```sh
npx @modelcontextprotocol/inspector https://api.ai.wpengine.com/v1/mcp
```

## When a key is rejected

A rejected key fails at the HTTP layer, before the request reaches the endpoint it was aimed at. Both responses below use the gateway’s standard error envelope — [Errors](https://developers.wpengine.com/docs/ai/api/errors/) documents its fields. What follows is what each one means for a key.

### 401: the key was not accepted

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="ai-services"


{
  "error": {
    "message": "invalid or revoked API key",
    "type": "authentication_error",
    "code": 401,
    "request_id": "77e3a50c925779840eb98bb29d2a6c0d"
  }
}
```

> **Tip**
>
> A 401 does not tell you which thing went wrong, and that is deliberate: a mistyped key, a key from another account, and a key you revoked last week all answer identically, so probing the endpoint reveals nothing about which keys exist. Check the key’s prefix under **API Keys** in the User Portal, and that it hasn’t been revoked; if you can’t account for it, [rotate it](https://developers.wpengine.com/docs/ai/api/authentication/#rotating-a-key).

### 403: the key is missing a scope

```http
HTTP/1.1 403 Forbidden


{
  "error": {
    "message": "API key does not have 'write' permission for scope 'mcp' (granted: 'none').",
    "type": "permission_error",
    "code": 403,
    "request_id": "3c1f9a7e05b24d6c8e2a41f0b9d7e615"
  }
}
```

Unlike a 401, this one names the scope and the level you were granted. Edit the key’s permissions under **API Keys** in the User Portal to grant the scope at the level the table above lists (`write` for `mcp`), or use **Full access** while you’re testing.

## Rotating a key

Keys do not expire on their own, and there is no rotation endpoint. Rotating is creating a replacement and revoking the original:

1. [Create a new key](https://developers.wpengine.com/docs/ai/api/authentication/#creating-a-key) with the same type and permissions.
2. Deploy it to your application.
3. Confirm the new key works.
4. [Revoke the old key](https://developers.wpengine.com/docs/ai/api/authentication/#revoking-a-key).

The two keys work side by side for as long as you need, so there is no window where neither authenticates. Nothing forces a rotation, which is why it’s worth putting on a schedule rather than doing it only after something goes wrong.

## Revoking a key

1. In the WP Engine User Portal, go to **AI** → **Gateways & API** → **API Keys**.
2. Find the key in the list and select **Delete** (Trash Can).
3. Confirm with **Revoke Key**.

A revoked key stops authenticating and returns `401` from then on. Revocation cannot be undone — there is no way to reactivate a revoked key, only to create a new one. A user key can be revoked only by the person who created it.

---

> #### Using your key
>
> - [Errors — the full response envelope and every status code](https://developers.wpengine.com/docs/ai/api/errors/)
> - [Site and WordPress account connections — the second gate a key does not open](https://developers.wpengine.com/docs/ai/api/site-and-account-connections/)
> - [MCP server — point an AI agent at your sites, authenticated with OAuth](https://developers.wpengine.com/docs/ai/api/mcp/)

## Was this helpful?

Thanks for the feedback!

```json
{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://developers.wpengine.com/#website","name":"WP Engine Product Documentation","url":"https://developers.wpengine.com/","description":"Resources for developing, deploying, and scaling on WP Engine.","inLanguage":"en-US","keywords":["API documentation","product documentation","headless WordPress","managed WordPress hosting"],"publisher":{"@id":"https://wpengine.com/#organization"}}]}
```
