Skip to content

AI API reference

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.

Generate content panel with the prompt Add a paragraph with 3 feature boxes, Enhance prompt and Chat mode links, a Generate content button and Choose a template and Add Elements buttons

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 > 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].

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:

{"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

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.

{"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

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

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?

Something wrong or missing on this page? Report it or edit the page.