---
url: 'https://dxpr.com/hc/documentation/learn-dxpr-builder/ai/api-reference'
title: 'AI API reference | DXPR'
author:
  name: docs-sync
  url: 'https://dxpr.com/users/docs-sync'
date: '2026-10-23T14:31:17+00:00'
copyright: 'Copyright DXPR. All rights reserved.'
type: article
summary: 'The AI routes, their request fields and responses'
tags:
  - 'Architecture and APIs'
image: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
published: true
og:
  site_name: DXPR
  updated_time: '2026-10-23T14:31:17+0000'
  'image:alt': 'DXPR, powered by Drupal: AI-powered Drupal for marketers.'
schema:
  '@context': 'https://schema.org'
  '@graph':
    -
      mainEntity: {  }
    -
      '@type': TechArticle
      headline: 'AI API reference'
      description: 'The AI routes, their request fields and responses'
      image:
        '@type': ImageObject
        url: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
        width: '1200'
        height: '630'
      datePublished: '2026-10-23T14:31:17+0000'
      dateModified: '2026-10-23T14:31:17+0000'
      author:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
        url: 'https://dxpr.com/'
        logo:
          '@type': ImageObject
          url: 'https://dxpr.com/themes/custom/dxpr_com/dxpr-logo-dark.svg'
          width: '1348'
          height: '501'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
        url: 'https://dxpr.com/'
        logo:
          '@type': ImageObject
          url: 'https://dxpr.com/themes/custom/dxpr_com/dxpr-logo-dark.svg'
          width: '1348'
          height: '501'
      mainEntityOfPage: 'https://dxpr.com/hc/documentation/learn-dxpr-builder/ai/api-reference'
      articleSection: 'Architecture and APIs'
    -
      '@type': WebPage
      '@id': 'https://dxpr.com/hc/documentation/learn-dxpr-builder/ai/api-reference'
      description: 'The AI routes, their request fields and responses'
      breadcrumb:
        '@type': BreadcrumbList
        itemListElement:
          -
            '@type': ListItem
            position: 1
            name: Home
            item: 'https://dxpr.com/'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
      inLanguage: en
---
[Help Center](/hc)/[Documentation](/hc/documentation) /[Learn DXPR Builder](/hc/documentation/learn-dxpr-builder) /[Extend](/hc/documentation/learn-dxpr-builder/extend) /[Architecture and APIs](/hc/documentation/learn-dxpr-builder/extend/architecture) # AI API reference.

The AI routes, their request fields and responses

 Learn DXPR BuilderExtendArchitecture and APIs

   ## In this guide

 Related guides

- [Models and providers](/hc/documentation/learn-dxpr-builder/ai/models-and-providers)
- [Configuration](/hc/documentation/learn-dxpr-builder/ai/configuration)
- [AI troubleshooting](/hc/documentation/learn-dxpr-builder/ai/troubleshooting)

DXPR Builder exposes three AI routes. The browser calls them, and the controllers proxy the request through the Drupal AI module to the DXPR provider (`ai_provider_dxpr`), so the API key never reaches the browser. Routes are defined in `dxpr_builder.routing.yml`; behaviour below comes from `src/Controller/AiChatController.php` and `src/Controller/AiImageController.php`.

## Access requirements (all three routes)

| Requirement | Source |
|---|---|
| HTTP method `POST` | `methods: [POST]` in the route |
| Permission `edit with dxpr builder` | `_permission` |
| Billable user (valid licence seat) | `_dxpr_builder_billable_user`, checked by `DxprBuilderBillableUserAccessCheck` |
| CSRF token in the `token` query parameter | `_csrf_token: 'TRUE'` |
| Logged-in Drupal session cookie | Drupal access checks run per user |

The token is Drupal's route CSRF token for the route path. DXPR Builder generates it server side and embeds it in `drupalSettings.dxprBuilder.aiAgent`as `endpointUrl`, `imageEndpointUrl` and `imageEditEndpointUrl` (see `DxprBuilderFormatter`). Read one of those values from a page where the editor is loaded to obtain a working URL. A failed access check returns Drupal's standard `403` response.

The controllers always instantiate the `dxpr`provider; the provider set at `/admin/config/ai/settings` is not used.

## Chat

`POST /dxpr_builder/ajax/ai/chat?token=...`

Used by text commands, page creation and prompt suggestions. The controller reads a JSON body and calls `$provider->chat()`.

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `messages` | array of `{role, content}` | yes | `role` is `system`, `user` or `assistant` |
| `model` | string | no | Defaults to `kavya-m1`. Must be on the provider's Allowed models list |
| `stream` | boolean | no | Defaults to `true` |
| `prediction` | object | no | Passed through, for example `{"type":"content","content":"<p>...</p>"}` |
| `providers` | string | no | Comma-separated provider IDs, for example `openai,mistral` |
| `allowed_html_tags` | string | no | Passed through; the builder sends `Bootstrap 5 HTML` |
| `allowed_html_classes` | string | no | Passed through; the builder sends `Bootstrap 5 Classes` |
| `web_search` | boolean | no | Only `false` is forwarded |
| `response_format` | object | no | Passed through, for example a `json_schema` object |

The controller always adds `jsonrpc: false` to the provider configuration. Before the call it merges the domains from **AI Output Filtering &gt; Allowed domains** into the AI module's hostname filter for the duration of the request (`*` switches the filter to full trust).

### Response

Streamed (`stream` true, the default): `200`, `Content-Type: text/event-stream`. Each event is `data: {json}` followed by a blank line, and the stream ends with `data: [DONE]`.

```text
data: {"choices":[{"delta":{"content":"Hello"}}],"id":"...","model":"kavya-m1","usage":{...}}

data: [DONE]

```

`id`, `object`, `created`, `model`, `original_model` and `usage` are copied from the provider's raw chunk when present.

Non-streamed (`stream` false): `200`, `application/json`:

```json
{"choices":[{"message":{"role":"assistant","content":"..."}}]}

```

### Errors

| Status | Body |
|---|---|
| `400` | Plain text `Invalid request: messages required` |
| `403` | `{"error":{"code":"model_not_allowed","message":"The selected model is not allowed. Please refresh the page to update your model options."}}` when `ai_provider_dxpr` is installed and `model` is not on its Allowed models list |
| `500` | `{"error":{"message":"The request could not be completed."}}` (details in the `dxpr_builder` log channel) |

### Example

```js
const url = drupalSettings.dxprBuilder.aiAgent.endpointUrl;
const res = await fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "kavya-m1",
    stream: false,
    messages: [
      { role: "system", content: "You are a copywriter." },
      { role: "user", content: "Shorten: <p>Our team ...</p>" }
    ]
  })
});
const data = await res.json();
console.log(data.choices[0].message.content);

```

## Image generation

`POST /dxpr_builder/ajax/ai/image?token=...`

Calls `$provider->textToImage()`.

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `prompt` | string | yes | Text description of the image |
| `model` | string | no | Defaults to `kavya-image` |
| `size` | string | no | The builder sends `1024x1024`, `1536x1024` or `1024x1536`; omitted for Auto |
| `quality` | string | no | Passed to the provider unchanged |
| `background` | string | no | Passed to the provider unchanged |

### Response

`200`, `application/json`. Only the first image is returned, base64 encoded. The DXPR provider requests `webp` output.

```json
{"data":[{"b64_json":"UklGRi..."}]}

```

### Errors

| Status | Body |
|---|---|
| `400` | `{"error":{"message":"Invalid request: prompt required"}}` |
| `500` | `{"error":{"message":"No image was generated"}}` |
| `500` | `{"error":{"message":"Image generation failed. Please try again."}}` |

### Example

```bash
curl -X POST "https://example.com/dxpr_builder/ajax/ai/image?token=TOKEN" \
  -H "Content-Type: application/json" \
  -H "Cookie: SESSxxx=..." \
  -d '{"prompt":"Flat illustration of a rocket","size":"1536x1024"}'

```

## Image editing

`POST /dxpr_builder/ajax/ai/image/edit?token=...`

Calls `$provider->imageToImage()` with the uploaded image and the prompt.

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `prompt` | string | yes | Editing instruction |
| `image` | string | yes | Base64 image data without a `data:` prefix; strict decoding |
| `mimeType` | string | no | Defaults to `image/png`; the subtype becomes the file extension |
| `model` | string | no | Defaults to `kavya-image` |
| `size`, `quality`, `background` | string | no | As for image generation |

### Response

Same shape as image generation: `{"data":[{"b64_json":"..."}]}`.

### Errors

| Status | Body |
|---|---|
| `400` | `{"error":{"message":"Invalid request: prompt and image required"}}` |
| `400` | `{"error":{"message":"Invalid image data: base64 decode failed"}}` |
| `500` | `{"error":{"message":"No image was generated"}}` |
| `500` | `{"error":{"message":"Image editing failed. Please try again."}}` |

### Example

```js
const url = drupalSettings.dxprBuilder.aiAgent.imageEditEndpointUrl;
const res = await fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    prompt: "Remove the background",
    image: base64String,
    mimeType: "image/jpeg"
  })
});
const { data } = await res.json();

```

## Storing a generated image

The routes return image bytes only. The builder converts `b64_json` to a `webp` file and uploads it to `POST /dxpr_builder/ajax/file_upload`(`drupalSettings.dxprBuilder.fileUploadUrl`, form field `upload[]`), which responds with the file `url` and `fid`. The prompt becomes the file name (first 80 characters) and the alt attribute.

## What's next?

- [Models and providers](/hc/documentation/learn-dxpr-builder/ai/models-and-providers)
- [AI configuration](/hc/documentation/learn-dxpr-builder/ai/configuration)
- [AI troubleshooting](/hc/documentation/learn-dxpr-builder/ai/troubleshooting)