---
title: Bulk-index knowledge base documents
url: https://developers.wpengine.com/docs/ai/api/reference/operations/bulkindexdocuments/
image: https://developers.wpengine.com/og/docs/ai/api/reference/operations/bulkindexdocuments.png
---

# Bulk-index knowledge base documents

POST

/v1/kb/collections/{id}/documents/bulk

Select code sample

```php
<?php


$client = new \GuzzleHttp\Client();


$response = $client->request('POST', 'https://api.ai.wpengine.com/v1/kb/collections/example/documents/bulk', [
  'body' => '{ "documents": [ { "id": "example", "content": "example", "title": "example", "type": "example", "uri": "example", "language": "example", "created_at": "2026-04-15T12:00:00Z", "modified_at": "2026-04-15T12:00:00Z", "metadata": { "status": "publish", "category": "news", "tags": [ "guide", "billing" ] }, "elements": [ { "tag": "a", "count": 2, "href": "https://example.org/page", "domain": "example.org", "scheme": "https", "has_query": true, "internal": false, "target": "_blank", "rel": [ "nofollow", "noopener" ] } ], "elements_truncated": true } ] }',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);


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

- Current environment

Indexes multiple documents in one request. Each item is reported independently, so one invalid document does not fail the batch. A request may contain at most 100 documents. Requires a valid WP Engine bearer token.

## Authorizations

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

## Parameters

### Path Parameters

**id**

required

string

The collection ID.

## Request Bodyrequired

Media typeapplication/json

object

**documents**

required

Array\<object>

\>= 1 items <= 100 items

object

**id**

Stable document id. Supply it to make index idempotent (re-indexing the same id replaces the document); generated when omitted.

string

**content**

required

The document text indexed for search.

string

**title**

string

**type**

Document type (e.g. the WordPress post type).

string

**uri**

Canonical URL for the document.

string

**language**

ISO 639-1 language code.

string

**created_at**

string format: date-time

**modified_at**

string format: date-time

**metadata**

Free-form metadata; values are stored as keywords for exact-match filtering.

object

**_key_**

additional properties

any

### Example

```json
{
  "status": "publish",
  "category": "news",
  "tags": [
    "guide",
    "billing"
  ]
}
```

**elements**

The document’s HTML elements (links, images, embeds), one entry per distinct element with its occurrence count, at most 256 KiB encoded. Send the whole list with every write, or an empty list when the document has none: a write without the field stores the document without elements, removing any stored before. Elements are used by document listing and element aggregations and are not returned when a document is fetched.

Array\<object>

<= 1000 items

One distinct HTML element of a document. `href` or `src` is the element’s main URL, without its fragment or query string (the WordPress content parameters `p`, `page_id`, `attachment_id`, `cat`, `tag` and `author` are kept, sorted by name); `domain`, `scheme`, `has_query` and `internal` describe it. A link with a non-http scheme carries only `scheme`.

object

**tag**

required

Lowercase tag name, such as `a`, `img`, `iframe` or `embed`.

string

/^\[a-z]\[a-z0-9-]{0,31}$/

**count**

required

How many times the element occurs in the document.

integer

\>= 1 <= 1000000

**href**

Link URL.

string

<= 2048 characters

**src**

Source URL.

string

<= 2048 characters

**domain**

Lowercase host of the URL.

string

<= 253 characters

**scheme**

Lowercase URL scheme, such as `https` or `mailto`.

string

/^\[a-z]\[a-z0-9+.-]{0,31}$/

**has_query**

Whether the URL had a query string.

boolean

**internal**

Whether the URL points at the site itself.

boolean

**target**

Link target, such as `_blank`.

string

<= 64 characters

**rel**

Link rel tokens, lowercase.

Array\<string>

<= 16 items

**alt**

Image alt text. An empty string means the attribute is present without text; omitted means the attribute is missing.

string

<= 1024 characters

**ext**

Custom element attributes, grouped by type. Names are lowercase letters, digits, `-` and `_`, starting with a letter, at most 64 characters; an element has at most 16 and a request at most 64 distinct names.

object

**keyword**

Exact-match text values, each a string or a list of up to 16 strings of at most 1024 bytes. Values of an attribute the site declares as an enum are matched in lowercase, so send them lowercase.

object

**_key_**

additional properties

One of:

- [string](https://developers.wpengine.com/docs/ai/api/reference/operations/bulkindexdocuments/#tab-panel-0-0)
- [Array\<string>](https://developers.wpengine.com/docs/ai/api/reference/operations/bulkindexdocuments/#tab-panel-0-1)

string

<= 1024 characters

**url**

URL values, at most 2048 bytes. An absolute http or https URL is stored as filters compare it: scheme and host lowercased, fragment and query string dropped except WordPress content parameters.

object

**_key_**

additional properties

string

<= 2048 characters

**boolean**

object

**_key_**

additional properties

boolean

**long**

Whole numbers between -2^53 and 2^53.

object

**_key_**

additional properties

integer format: int64

### Example

```json
{
  "tag": "a",
  "count": 2,
  "href": "https://example.org/page",
  "domain": "example.org",
  "scheme": "https",
  "has_query": true,
  "internal": false,
  "target": "_blank",
  "rel": [
    "nofollow",
    "noopener"
  ]
}
```

**elements_truncated**

True when the client dropped elements to stay within its limits, so the list is incomplete.

boolean

## Responses

### 200

Per-document results, including any per-item failures

Media typeapplication/json

object

**items**

required

Array\<object>

object

**id**

required

string

**result**

string

Allowed values: created updated unchanged

**status**

required

HTTP-style status for this item (e.g. 201, 200, 400).

integer

**error**

Failure reason, present only when the item failed.

string

#### Example

```json
{
  "items": [
    {
      "result": "created"
    }
  ]
}
```

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

### 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

### 503

The knowledge base is not currently available. Retry after a short delay.

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