---
title: Update an agent
url: https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/
image: https://developers.wpengine.com/og/docs/ai/api/reference/operations/updateagent.png
---

# Update an agent

PATCH

/v1/agents/{agent_id}

Select code sample

```php
<?php


$client = new \GuzzleHttp\Client();


$response = $client->request('PATCH', 'https://api.ai.wpengine.com/v1/agents/example', [
  'body' => '{ "name": "Site Concierge", "model": "anthropic/claude-sonnet-4-6", "profile": "example", "guardrails": { "moderation": "disabled" }, "description": "example", "system_prompt": "example", "project_id": "example", "temperature": 1, "max_tokens": 1, "reasoning_effort": "example", "scopes": [ "example" ], "settings": {}, "mcp_servers": [ {} ], "tools": [ { "type": "custom", "name": "example", "description": "example", "input_schema": {}, "label": "example", "defer_loading": false } ], "skills": [ {} ], "metadata": { "additionalProperty": "example" } }',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);


echo $response->getBody();
```

- Current environment

Partially updates an existing agent. Fields omitted from the request body are left unchanged. When updating the model, the new model must support the `tools` capability; models without this capability return HTTP 400. Accepts a service-token bearer authenticating a site or an API key, either of which must be authorized for the agent’s project. An agent stays in the project it was created in.

## Authorizations

- **[bearerAuth](https://developers.wpengine.com/docs/ai/api/reference/#bearerauth)**

## Parameters

### Path Parameters

**agent_id**

required

string

The unique identifier of the agent to update.

## Request Bodyrequired

Media typeapplication/json

Partial update request for an agent. All fields are optional; omit a field to preserve its current value.

object

**name**

Human-readable agent name. Cannot be cleared (must be non-empty if provided).

string

\>= 1 characters <= 255 characters

### Example

```
Site Concierge
```

**model**

Identifier of the model that powers the agent (e.g. `anthropic/claude-sonnet-4-6`). Can only be cleared on an agent with a `profile`, where null means “use the profile’s default”.

string

nullable >= 1 characters <= 255 characters

### Example

```
anthropic/claude-sonnet-4-6
```

**profile**

See `CreateAgentRequest.profile`. Adopting a profile without `model` in the same request keeps the stored model if the profile allows it, and otherwise uses the profile’s default. Once set, a profile can be replaced by another but not removed.

string

<= 64 characters

**guardrails**

Partial update. Omit this property to preserve guardrails; an empty object also preserves the current moderation setting. Set `moderation` to `disabled` or `enabled` to replace it. Explicit null — at the `guardrails` level or its nested `moderation` key — is invalid, and profiled agents reject a `moderation` write because their profile owns it.

object

**moderation**

Best-effort custom-agent moderation setting. Product profiles own this value: writes are rejected and the field is omitted from responses for profiled agents.

string

default: disabled

Allowed values: disabled enabled

**description**

Free-form description of what the agent does. Send empty string or null to clear.

string

nullable <= 4096 characters

**system_prompt**

User prompt template (site prompt) prepended to every conversation powered by this agent. Send empty string or null to clear.

string

nullable <= 32768 characters

**project_id**

The agent’s current project. An agent stays in the project it was created in, so this must match the agent’s `project_id`; any other value, or null, returns HTTP 400.

string

**temperature**

Sampling temperature applied to chat completions. Send null to clear.

number format: float

nullable <= 2

**max_tokens**

Hard upper bound on output tokens per agent turn (see CreateAgentRequest.max_tokens for semantics). Send null to clear and fall back to provider-specific defaults on subsequent turns.

integer

nullable >= 1 <= 200000

**reasoning_effort**

Catalog-native reasoning effort for this agent’s model. Allowed values are the model’s `parameters.reasoning_effort` on GET /v1/models. Send null to clear (provider default). Omit the field to preserve the stored value. Changing `model` clears a stored value the new model does not accept.

string

nullable

**scopes**

Permission scopes the agent operates under. Must be drawn from the site’s existing scopes (e.g. `chat`, `search`). Send null or empty array to clear.

Array\<string>

nullable

**settings**

Feature toggles for the agent (e.g. `disable_kb_rag: true` to skip knowledge-base retrieval). Capped at 32 keys and 4 KiB serialized. Send null or empty object to clear.

object

<= 32 properties

**_key_**

additional properties

any

**mcp_servers**

MCP server definitions the agent may connect to. Full replacement; send empty array or null to clear.

Array\<object>

nullable <= 20 items

object

**_key_**

additional properties

any

**tools**

Tool declarations available to the agent. Full replacement; send an empty array or null to clear all of them. See `AgentTool` for the per-entry contract.

Array

nullable <= 128 items

One of: discriminator: type

- [object](https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/#tab-panel-0-0)
- [object](https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/#tab-panel-0-1)
- [object](https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/#tab-panel-0-2)
- [object](https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/#tab-panel-0-3)

object

**type**

Discriminator for the tools\[] union. Omit for a plain client tool (the default); `custom` is the only value this schema accepts.

string

Allowed values: custom

**name**

required

Unique tool name. Must be unique within the agent’s `tools` array (across every entry, regardless of type).

string

<= 64 characters /^\[a-zA-Z0-9\_-]{1,64}$/

**description**

Human-readable description of what the tool does.

string

**input_schema**

JSON Schema defining the tool’s input parameters.

object

**label**

Optional short human-readable name for the tool, used alongside `name` and `description` when the gateway matches a search query against deferred tools. Supply it when the tool’s `name` is a slug whose wording a natural-language query would not contain.

string

<= 64 characters

**defer_loading**

When true, the tool is declared but kept out of the model’s tool list until it is needed, so a large catalogue costs no context up front. The gateway offers the agent a search over the deferred tools and loads the matches, and a deferred tool the model names directly is loaded on demand. Once loaded, its input is enforced strictly against its schema — unlike a non-deferred tool, which keeps today’s lenient handling — so a malformed call is rejected with a model-readable error instead of failing downstream. Leave false (the default) for tools that must be callable from the first turn.

boolean

**skills**

Skills enabled for the agent. Full replacement; send empty array or null to clear.

Array\<object>

nullable <= 64 items

object

**_key_**

additional properties

any

**metadata**

Arbitrary string key-value metadata. Per-key patch: set a key to a string to add/update it, or to null to delete that key; omitted keys are preserved. Maximum 16 keys, keys up to 64 characters, values up to 512 characters. The keys “scopes” and “settings” are reserved.

object

<= 16 properties

**_key_**

additional properties

string

nullable <= 512 characters

## Responses

### 200

The updated agent

Media typeapplication/json

object

**id**

required

Unique identifier for the agent.

string

**type**

required

string

Allowed values: agent

**project_id**

required

The project the agent belongs to.

string

**name**

required

string

**model**

required

string

**description**

Free-form description of what the agent does. On an agent with a `profile` this is the profile’s current description.

string

**system_prompt**

User prompt template (site prompt). On an agent with a `profile` this is the profile’s current prompt.

string

**profile**

Server-owned profile the agent follows (see `CreateAgentRequest.profile`). Omitted when the client owns every field.

string

**guardrails**

object

**moderation**

Best-effort custom-agent moderation setting. Product profiles own this value: writes are rejected and the field is omitted from responses for profiled agents.

string

default: disabled

Allowed values: disabled enabled

**managed_fields**

Fields owned by the agent’s profile, which the client cannot write. Omitted when the agent has no profile.

Array\<string>

**allowed_models**

Models the agent’s profile allows as a `model` choice. Omitted when the agent has no profile.

Array\<string>

**temperature**

number format: float

**max_tokens**

Output-token limit per turn (see CreateAgentRequest.max_tokens). Omitted when unset on the agent.

integer

**reasoning_effort**

Catalog-native reasoning effort stored on the agent. Omitted when unset. Allowed values follow the agent’s current model on GET /v1/models.

string

**scopes**

Permission scopes the agent operates under (round-trips the request value).

Array\<string>

**settings**

Feature toggles for the agent (round-trips the request value).

object

**_key_**

additional properties

any

**mcp_servers**

Array\<object>

object

**_key_**

additional properties

any

**tools**

Tool declarations (client tools, knowledge_base grounding entries, and echo/random_number evaluation tool opt-ins) round-tripped from the request.

Array

One of: discriminator: type

- [object](https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/#tab-panel-1-0)
- [object](https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/#tab-panel-1-1)
- [object](https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/#tab-panel-1-2)
- [object](https://developers.wpengine.com/docs/ai/api/reference/operations/updateagent/#tab-panel-1-3)

object

**type**

Discriminator for the tools\[] union. Omit for a plain client tool (the default); `custom` is the only value this schema accepts.

string

Allowed values: custom

**name**

Unique tool name. Must be unique within the agent’s `tools` array (across every entry, regardless of type). Always present for tools created since name validation was added; may be absent on an agent whose tools were stored before that validation existed.

string

<= 64 characters /^\[a-zA-Z0-9\_-]{1,64}$/

**description**

Human-readable description of what the tool does.

string

**input_schema**

JSON Schema defining the tool’s input parameters.

object

**label**

Optional short human-readable name for the tool, used alongside `name` and `description` when the gateway matches a search query against deferred tools. Supply it when the tool’s `name` is a slug whose wording a natural-language query would not contain.

string

<= 64 characters

**defer_loading**

When true, the tool is declared but kept out of the model’s tool list until it is needed, so a large catalogue costs no context up front. The gateway offers the agent a search over the deferred tools and loads the matches, and a deferred tool the model names directly is loaded on demand. Once loaded, its input is enforced strictly against its schema — unlike a non-deferred tool, which keeps today’s lenient handling — so a malformed call is rejected with a model-readable error instead of failing downstream. Leave false (the default) for tools that must be callable from the first turn.

boolean

**skills**

Array\<object>

object

**_key_**

additional properties

any

**metadata**

User-supplied string metadata. Reserved keys (“scopes”, “settings”) are surfaced on their own top-level fields rather than appearing here.

object

**_key_**

additional properties

string

<= 512 characters

**created_at**

required

string format: date-time

**updated_at**

string format: date-time

nullable

#### Example

```json
{
  "type": "agent",
  "guardrails": {
    "moderation": "disabled"
  },
  "managed_fields": [
    "model",
    "system_prompt",
    "description"
  ],
  "tools": [
    {
      "type": "custom",
      "defer_loading": false
    }
  ]
}
```

### 400

Invalid request body or parameters. On agent create and update, error type “profile_unavailable” means the requested profile is not available to the caller.

Media typeapplication/json

object

**error**

required

object

**message**

required

string

**type**

required

string

**error_code**

Stable, machine-readable cause, set by routes that document their codes (the AI readiness and account AI routes, and an entitlement_required refusal, where it is one of not_eligible, terms_required, not_enabled or suspended); absent elsewhere and on errors from shared layers such as authentication. Clients must allow new codes.

string

**portal_url**

Where the customer can resolve the error, set on an entitlement_required refusal that has an error_code when one is configured.

string

**code**

required

integer

**request_id**

required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string

#### Example

```json
{
  "error": {
    "type": "invalid_request_error",
    "request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
  }
}
```

### 401

Missing or invalid bearer token

Media typeapplication/json

object

**error**

required

object

**message**

required

string

**type**

required

string

**error_code**

Stable, machine-readable cause, set by routes that document their codes (the AI readiness and account AI routes, and an entitlement_required refusal, where it is one of not_eligible, terms_required, not_enabled or suspended); absent elsewhere and on errors from shared layers such as authentication. Clients must allow new codes.

string

**portal_url**

Where the customer can resolve the error, set on an entitlement_required refusal that has an error_code when one is configured.

string

**code**

required

integer

**request_id**

required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string

#### Example

```json
{
  "error": {
    "type": "invalid_request_error",
    "request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
  }
}
```

#### Headers

**WWW-Authenticate**

string

##### Example

```
Bearer realm="ai-services"
```

### 403

The token is valid, but the request is forbidden. Error type “permission_error” means the token’s scope/permission is insufficient or the authenticated user is not authorized for the target account; “entitlement_required” means the account may not use WP Engine AI, with error_code giving why when known (not_eligible, terms_required, not_enabled or suspended) and portal_url where to fix it; “account_required” means no billing account could be resolved; and “billing_account_pending” means billing isn’t set up for the account yet, usually because its setup after AI was turned on hasn’t finished. Retry shortly. On /v1/chat/completions when content moderation is enabled, and on /v1/sessions/{session_id}/events, error type “content_policy_violation” instead means the request content was blocked by content moderation policy; that response never identifies which filter or category matched.

Media typeapplication/json

object

**error**

required

object

**message**

required

string

**type**

required

string

**error_code**

Stable, machine-readable cause, set by routes that document their codes (the AI readiness and account AI routes, and an entitlement_required refusal, where it is one of not_eligible, terms_required, not_enabled or suspended); absent elsewhere and on errors from shared layers such as authentication. Clients must allow new codes.

string

**portal_url**

Where the customer can resolve the error, set on an entitlement_required refusal that has an error_code when one is configured.

string

**code**

required

integer

**request_id**

required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string

#### Example

```json
{
  "error": {
    "type": "invalid_request_error",
    "request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
  }
}
```

### 404

The requested resource was not found

Media typeapplication/json

object

**error**

required

object

**message**

required

string

**type**

required

string

**error_code**

Stable, machine-readable cause, set by routes that document their codes (the AI readiness and account AI routes, and an entitlement_required refusal, where it is one of not_eligible, terms_required, not_enabled or suspended); absent elsewhere and on errors from shared layers such as authentication. Clients must allow new codes.

string

**portal_url**

Where the customer can resolve the error, set on an entitlement_required refusal that has an error_code when one is configured.

string

**code**

required

integer

**request_id**

required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string

#### Example

```json
{
  "error": {
    "type": "invalid_request_error",
    "request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
  }
}
```

### 409

The request conflicts with an existing resource

Media typeapplication/json

object

**error**

required

object

**message**

required

string

**type**

required

string

**error_code**

Stable, machine-readable cause, set by routes that document their codes (the AI readiness and account AI routes, and an entitlement_required refusal, where it is one of not_eligible, terms_required, not_enabled or suspended); absent elsewhere and on errors from shared layers such as authentication. Clients must allow new codes.

string

**portal_url**

Where the customer can resolve the error, set on an entitlement_required refusal that has an error_code when one is configured.

string

**code**

required

integer

**request_id**

required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string

#### Example

```json
{
  "error": {
    "type": "invalid_request_error",
    "request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
  }
}
```

### 413

Request body exceeds the 64 KiB limit

Media typeapplication/json

object

**error**

required

object

**message**

required

string

**type**

required

string

**error_code**

Stable, machine-readable cause, set by routes that document their codes (the AI readiness and account AI routes, and an entitlement_required refusal, where it is one of not_eligible, terms_required, not_enabled or suspended); absent elsewhere and on errors from shared layers such as authentication. Clients must allow new codes.

string

**portal_url**

Where the customer can resolve the error, set on an entitlement_required refusal that has an error_code when one is configured.

string

**code**

required

integer

**request_id**

required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string

#### Example

```json
{
  "error": {
    "type": "invalid_request_error",
    "request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
  }
}
```

### 429

Rate limit exceeded. The request was throttled at the edge; wait and retry later. The response body is a short HTML page generated by the load balancer, not a structured JSON error — clients should rely on the 429 status code rather than parsing the body.

Media typetext/html

string

### 500

The server encountered an unexpected error while handling the request. Safe to retry once; if it persists, the cause is server-side and the request payload was not the problem.

Media typeapplication/json

object

**error**

required

object

**message**

required

string

**type**

required

string

**error_code**

Stable, machine-readable cause, set by routes that document their codes (the AI readiness and account AI routes, and an entitlement_required refusal, where it is one of not_eligible, terms_required, not_enabled or suspended); absent elsewhere and on errors from shared layers such as authentication. Clients must allow new codes.

string

**portal_url**

Where the customer can resolve the error, set on an entitlement_required refusal that has an error_code when one is configured.

string

**code**

required

integer

**request_id**

required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string

#### Example

```json
{
  "error": {
    "type": "invalid_request_error",
    "request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
  }
}
```

### 503

A required dependency is temporarily unavailable. Retry after a short delay with exponential back-off. An entitlement lookup failure uses error type “entitlement_unavailable”. A model without complete rate coverage uses error type “model_unpriced”. A credit balance that can’t be read uses error type “balance_unavailable”.

Media typeapplication/json

object

**error**

required

object

**message**

required

string

**type**

required

string

**error_code**

Stable, machine-readable cause, set by routes that document their codes (the AI readiness and account AI routes, and an entitlement_required refusal, where it is one of not_eligible, terms_required, not_enabled or suspended); absent elsewhere and on errors from shared layers such as authentication. Clients must allow new codes.

string

**portal_url**

Where the customer can resolve the error, set on an entitlement_required refusal that has an error_code when one is configured.

string

**code**

required

integer

**request_id**

required

Correlation ID for this request, matching the X-Request-ID response header — a 32-character trace ID behind the load balancer, otherwise a UUID. Quote it in support reports.

string

#### Example

```json
{
  "error": {
    "type": "invalid_request_error",
    "request_id": "80f1e2c3a4b5c6d7e8f9a0b1c2d3e4f5"
  }
}
```

## 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"}}]}
```
