Skip to content

API endpoints

This page lists every route that DXPR Builder registers in dxpr_builder.routing.yml, with the HTTP methods, access requirements, request parameters and response shapes as implemented in the controllers. The editor's JavaScript is the intended client for the AJAX endpoints; nothing on this page is a stable public API, and parameter names can change between releases.

Access requirements

Routes use three kinds of requirement. A route can combine them.

Requirement Meaning
_permission The user needs the named Drupal permission. DXPR Builder defines administer dxpr builder configuration, edit with dxpr builder and administer dxpr_builder_profile in dxpr_builder.permissions.yml; view media and administer site configuration come from core.
_csrf_token The request must carry a valid CSRF token in the token query parameter. For the main AJAX handler, the editor fetches a URL with the token from /dxpr_builder/csrf (or from the dxpr_builder_csrf operation). For the other routes, the field formatter puts URLs with a token in drupalSettings.dxprBuilder, for example fileUploadUrl, entityLinkSuggestionsUrl, userSettingsUrl and aiAgent.endpointUrl.
_dxpr_builder_billable_user The user must be a billable user, as defined below.

What "billable user" means

DxprBuilderBillableUserAccessCheck allows access when DxprBuilderLicenseService::isBillableUser() returns true for the current account. That method returns false for blocked accounts and for accounts whose dxpr_user_is_disavowed field is set (an administrator excludes a user from editing on the User Licenses page). Otherwise it returns true for user 1 and for any account that holds the edit with dxpr builder permission. In short: a billable user is an active, non-excluded account that is allowed to edit with DXPR Builder, and the licence service counts these accounts against your product key.

HTTP methods

Where a route declares methods, only those methods are routed. Where it does not, the route accepts any method (Drupal's MethodFilter only filters routes that declare methods). The tables below state the method the editor's JavaScript actually uses when that is visible in the source.

Editor AJAX endpoints

CSRF token URL

Path /dxpr_builder/csrf
Route dxpr_builder.csrf_refresh
Methods Not declared (any method). The editor sends GET (backend-connect.js, fetchCsrfTokenUrl()).
Requirements Billable user
Controller AjaxController::ajaxRefresh()

The request must carry the header X-Requested-With: XMLHttpRequest; without it the controller returns HTTP 403 with the JSON body {"error": "Invalid request"}.

Parameter Source Required Notes
enterprise Query string Optional When set to true and the dxpr_builder_e module is installed, the token is generated for the dxpr_builder_e.ajax_callback route instead. When set to true without that module the controller throws an exception.

Response: a JSON string with the URL of the main AJAX handler and a token query parameter. The URL is a path from the site root (base path included, no host). The JavaScript posts every builder operation to this URL.

Main AJAX handler

Path /dxpr_builder/ajax
Route dxpr_builder.ajax_callback
Methods Not declared (any method). The controller reads every parameter from the POST body, and the editor sends POST.
Requirements Billable user, CSRF token
Controller AjaxController::ajaxCallback()

The POST body field action selects the operation. Every operation and its parameters are listed under Main AJAX handler operations. When action is missing or unknown, the controller returns an empty Drupal AjaxResponse with no commands. Most operations that re-check the billable user status return the same empty response when that check fails; the tables note the two exceptions.

AI chat

Path /dxpr_builder/ajax/ai/chat
Route dxpr_builder.ai_chat
Methods POST
Requirements edit with dxpr builder, billable user, CSRF token
Controller AiChatController::chat()

The request body is JSON. The controller proxies the request to the dxpr provider of the Drupal ai module, so no API key reaches the browser. Before the call it merges the domains from the ai_output_allowed_domains setting into the ai module's hostname filter, when that service exists. A value of * sets the filter to full trust instead. The filter is restored afterwards.

Parameter Source Required Notes
messages JSON body Required Array of objects with role and content.
stream JSON body Optional Boolean, default true.
model JSON body Optional Default kavya-m1.
prediction JSON body Optional Passed to the provider configuration as an array.
providers JSON body Optional Passed through to the provider configuration.
allowed_html_tags JSON body Optional Passed through to the provider configuration.
allowed_html_classes JSON body Optional Passed through to the provider configuration.
web_search JSON body Optional Only the value false is forwarded; any other value is ignored.
response_format JSON body Optional Passed to the provider configuration as an array.

Responses:

Case Status Body
Streamed (stream true and the provider streams) 200, Content-Type: text/event-stream Server-sent events. Each event is data: <JSON> where the JSON has choices[0].delta.content and, when the provider supplies them, id, object, created, model, original_model and usage. The stream ends with data: [DONE].
Non-streamed 200, application/json {"choices": [{"message": {"role": "assistant", "content": "<text>"}}]}
Body is not JSON, or messages is missing or empty 400, plain text Invalid request: messages required
model not in the allowed_models list of ai_provider_dxpr.settings (only checked when the ai_provider_dxpr module is installed and the list is set) 403, application/json {"error": {"code": "model_not_allowed", "message": "The selected model is not allowed. Please refresh the page to update your model options."}}
Provider exception 500, application/json {"error": {"message": "The request could not be completed."}}

AI image generation

Path /dxpr_builder/ajax/ai/image
Route dxpr_builder.ai_image
Methods POST
Requirements edit with dxpr builder, billable user, CSRF token
Controller AiImageController::generate()
Parameter Source Required Notes
prompt JSON body Required Text prompt.
model JSON body Optional Default kavya-image.
size JSON body Optional Forwarded to the provider configuration when non-empty.
quality JSON body Optional Forwarded to the provider configuration when non-empty.
background JSON body Optional Forwarded to the provider configuration when non-empty.

Responses:

Case Status Body
Success 200 {"data": [{"b64_json": "<base64 image>"}]} (only the first generated image is returned)
Body is not JSON, or prompt is missing 400 {"error": {"message": "Invalid request: prompt required"}}
Provider returned no image 500 {"error": {"message": "No image was generated"}}
Provider exception 500 {"error": {"message": "Image generation failed. Please try again."}}

AI image editing

Path /dxpr_builder/ajax/ai/image/edit
Route dxpr_builder.ai_image_edit
Methods POST
Requirements edit with dxpr builder, billable user, CSRF token
Controller AiImageController::edit()
Parameter Source Required Notes
prompt JSON body Required Editing instruction.
image JSON body Required Base64-encoded source image (strict decoding).
mimeType JSON body Optional Default image/png; the subtype becomes the file extension passed to the provider.
model JSON body Optional Default kavya-image.
size, quality, background JSON body Optional Forwarded to the provider configuration when non-empty.

Responses:

Case Status Body
Success 200 {"data": [{"b64_json": "<base64 image>"}]}
Body is not JSON, or prompt or image is missing 400 {"error": {"message": "Invalid request: prompt and image required"}}
image is not valid base64 400 {"error": {"message": "Invalid image data: base64 decode failed"}}
Provider returned no image 500 {"error": {"message": "No image was generated"}}
Provider exception 500 {"error": {"message": "Image editing failed. Please try again."}}

File upload

Path /dxpr_builder/ajax/file_upload
Route dxpr_builder.ajax_file_upload_callback
Methods POST, DELETE (declared in routing; the controller has a single upload handler and no separate delete branch)
Requirements Billable user, CSRF token
Controller UploadFileController::fileUpload()
Parameter Source Required Notes
upload Multipart form files, sent as upload[] Required One or more uploaded files.

The controller sorts each file by the first part of its client MIME type into <default scheme>://dxpr_builder_images, dxpr_builder_videos or dxpr_builder_files. An image needs an extension of the MIME types image/gif, jpg, jpeg, png, webp, avif or svg. A video needs one of video/webm, ogv, ogg, mp4 or quicktime (for example .mov). The size limit is PHP's upload maximum. A file with the same name and identical SHA-256 content as an existing managed file that the user can view is reused instead of saved again. When the media module is installed and a media type named image, media_image, video or media_video exists, a published media entity is created (or reused) for the file. File usage is recorded under the dxpr_builder module.

Responses:

Case Status Body
Success 201 JSON array, one object per file: url (absolute file URL), uuid and id (of the media entity when one exists, otherwise of the file), fid (file ID), entity_type (media or file).
No upload files 400 {"message": "No files were uploaded."}
Invalid upload, unwritable destination or save failure 500 {"message": "<reason>"}
Validation failure (extension or size) 422 {"message": "<violation messages>"}
Filename already locked by another request 503 {"message": "File \"<name>\" is already locked for writing."}

Media library dialog

Path /dxpr_builder/media-library
Route dxpr_builder.media_library
Methods Not declared (any method). Parameters are read from the query string.
Requirements view media; admin route
Controller AjaxController::openImageMediaLibrary()
Parameter Source Required Notes
media_type Query string Optional image (default) or video.
remaining_slots Query string Optional Number of items the opener accepts; defaults to 1.
uuid Query string Optional Passed to the opener as opener_parameters.uuid.

The media type offered depends on the media_browser setting: media_library uses the image or video media type directly; media_library_acquia_dam uses acquia_dam_image_asset or acquia_dam_video_asset when that media type exists.

Responses:

Case Result
Success A render array built by MediaLibraryUiBuilder::buildUi() with the opener media_library.opener.dxpr_builder. Drupal renders it as an HTML page intended for an iframe.
media_library module not installed 403, plain text Media Library is not enabled. Please enable it to access this feature.
Unsupported media_type 400, plain text Unsupported media type "<value>".
media_browser setting has no usable media type 400, plain text The "<setting>" settings is not supported.
Path /dxpr_builder/ajax/help_link_validator
Route dxpr_builder.ajax_help_link_validator
Methods Not declared (any method). The dev script dxpr_builder_dev.js sends POST with a form-encoded body.
Requirements Billable user
Controller AjaxController::validateHelpLink()
Parameter Source Required Notes
help_link POST body Required for a meaningful answer Only http or https URLs on host dxpr.com with a path starting /documentation/ are checked.

Response: a JSON array. [true] when a HEAD request to the link (without following redirects) returns 200; [false] when the HTTP client throws; [] in every other case, including a missing parameter, a non-matching URL or a non-200 status.

Path /dxpr_builder/entity-link-suggestions
Route dxpr_builder.entity_link_suggestions
Methods GET
Requirements edit with dxpr builder, CSRF token; no_cache route option
Controller EntityLinkSuggestionsController::suggestions()
Parameter Source Required Notes
q Query string Required for results Search text, lower-cased. A value like /node/123 loads that entity directly.
langcode Query string Optional Language of the host entity; defaults to the current language. Only entities available in this language are returned.

Bundles are those with ckeditor5_link_suggestions enabled in their bundle info; when none are configured, all node bundles are searched. Up to 100 entities per entity type are matched with a CONTAINS search through core's entity reference selection plugins.

Response: {"suggestions": [...]} with private cacheability and a max age of 300 seconds. Each suggestion has description, entity_type_id, entity_uuid, group, label and path. When q matches nothing, the array holds a single manual-link suggestion with description, label (the lower-cased input) and path (the input when it is a valid URL, otherwise an empty string). When q is empty, suggestions is an empty array.

User editor settings

Path /dxpr_builder/user-settings
Route dxpr_builder.user_settings
Methods POST
Requirements edit with dxpr builder, CSRF token; no_cache route option
Controller UserSettingsController::save()

The editor sends this request when a user changes their own editor settings, for example under Editor settings. The values are stored with the user account in user.data, module dxpr_builder.

Parameter Source Required Notes
controls_layout JSON body Required (the only setting) element, breadcrumb or default. default removes the user's choice, so the profile or site setting applies.

Responses:

Case Status Body
Saved 200 {"settings": {"controls_layout": "<value>"}}: every setting after saving, default where the user has no choice stored.
Body is not a non-empty JSON object, or a name or value is invalid 400 {"error": "Invalid setting or value."}. Nothing is stored.

Main AJAX handler operations

All operations go to /dxpr_builder/ajax with the token query parameter obtained from /dxpr_builder/csrf. The operation name is sent in the POST body field action; all other parameters are POST body fields unless stated otherwise. The "Re-checks billable" column marks operations that call isBillableUser() again inside the switch. When that check fails they return the empty AjaxResponse described above, unless the row says otherwise.

Session and access

Operation Parameters Re-checks billable Returns
dxpr_login None No JSON boolean: whether the current user is billable.
dxpr_builder_csrf None Yes JSON string: the handler URL with a token query parameter (same as /dxpr_builder/csrf without the enterprise option).

Containers (fields rendered with the DXPR Builder formatter)

Operation Parameters Re-checks billable Returns
dxpr_get_container_types None Yes JSON object keyed entity_type\|bundle with value entity_type - bundle, one entry per bundle whose default view display uses the dxpr_builder_text formatter on at least one field.
dxpr_get_container_names container_type (required, entity_type\|bundle) Yes (returns an empty JSON string instead of the empty response) JSON object keyed entity_id\|field_name (or entity_id\|field_name\|langcode for translatable entities) with value entity label\|field label. When container_type is missing, or the billable check fails, the response is an empty JSON string.
dxpr_save_container type (required, entity_type\|bundle); name (required, entity_id\|field_name or entity_id\|revision_id\|field_name); htmlContent (required, encoded markup); lang (optional, defaults to the site default language) Yes JSON empty string on success. HTTP 400 with a JSON message when htmlContent is not a string or the language does not apply to a non-translatable entity; 404 when the requested translation does not exist; 500 when the entity cannot be loaded.

dxpr_save_container does the following:

  1. Decodes htmlContent: XOR every byte with 7, then URL-decode.
  2. Writes the result to the first delta of the named field.
  3. Creates a new default revision with the log message Saved with DXPR builder when the entity type is revisionable.
  4. Removes any content lock for the entity.
  5. Updates block_revision_id in Layout Builder sections that reference the saved inline block.
  6. Increments the dxpr_builder.saves_count state value.

The save only happens when the user has update access to the entity. Without it, the operation still returns the empty-string success response.

CMS elements (blocks and views)

Operation Parameters Re-checks billable Returns
dxpr_builder_get_cms_element_names None Yes JSON object from DxprBuilderService::getCmsElementNames() with keys list, disallowed and blockCategories.
dxpr_get_cms_element_settings name (required): view-<view_id>-<display_id> or block-<plugin_id>; ajax_page_state[libraries] (optional, comma-separated libraries already loaded) Yes JSON object with css, js, settings and data. For a view, data is the rendered exposed filter widgets; for a block, data is the block's configuration form wrapped in <form> tags, with the provider, admin_label, label, label_display and context_mapping elements removed and all details elements opened.
dxpr_builder_load_cms_element name (required, parsed by parseStringForCmsElementInfo()); settings (required); data (required, array); ajax_page_state[libraries] (optional) No JSON object with css, js, settings and data, where data is the rendered block or view display.

In both settings-returning operations, css and js are rendered asset tags not already present in the page, and settings is the decoded drupalSettings object, or an empty string when there are none.

Page templates

Operation Parameters Re-checks billable Returns
dxpr_get_page_templates None Yes JSON array of enabled page templates, each with title, uuid, module (always null: the entity does not store it), category, date, weight (integer) and image (a data: URL, or the module's not-found.png URL).
dxpr_load_page_template uuid (required) Yes HTML response containing the template markup with base tokens replaced; empty when no enabled template matches.

User templates

Operation Parameters Re-checks billable Returns
dxpr_get_templates None Yes JSON array of templates owned by the current user or marked global; templates whose author account no longer exists are left out. Each entry has id, uuid, name, global, current_user_is_author, author_id, author_name, type and, when stored, image (a data: URL).
dxpr_load_template uuid (required) Yes HTML response containing the template markup with base tokens replaced; empty when no enabled template matches.
dxpr_save_template name (required); template (required, markup); type (optional, defaults to custom); global (optional, cast to boolean); image (optional: a base64 string or data:image URL in the POST body, or a multipart file field named image) Yes JSON object with message and code. code 200 on success; code 409 (HTTP status 200) when a template with the same machine name exists; code 400 with HTTP 400 when the image is not valid image data.
dxpr_delete_template name (required) Yes JSON empty string.

The machine name is derived from name by lower-casing it and replacing every run of characters outside a-z0-9_ with an underscore. type falls back to the data-azb attribute in the markup when a stored template has no type.

Images

Operation Parameters Re-checks billable Returns
dxpr_builder_get_image_urls entityIDs (required, array); imageStyle (required; original for the unstyled file); entityType (required; media resolves media items, any other value is used as the entity type of the IDs) Yes Text body: comma-separated image URLs. Files give a root-relative URL with a fid query parameter. Media items of the image or video type resolve to their source file. acquia_dam_image_asset items give the DAM URL with mid, acquiaDamAsset and imageStyle added. Other media items are skipped. HTTP 204 with no body when entityIDs is empty, or when no media item can be resolved.
dxpr_builder_get_image_style_url imageStyle (required); entityId (required); entityTypeId (required, file or media) Yes Text body. For a file: its root-relative URL through the image style (SVG files and original skip the style), with a fid query parameter. For an acquia_dam_image_asset media item: the DAM URL. HTTP 204 with no body for any other entity, or when the entity is not found.
dxpr_builder_get_image_metadata entityId (required); entityType (required, file or media) Yes (returns 403 JSON instead of the empty response) {"data": {"alt": "...", "title": "..."}} from the media item's image source field (an Acquia DAM asset gives its DAM alt text and an empty title). For a file, the values come from the first media item whose field_media_image references it. data is an empty array when the entity is neither a file nor a media item, or when no media references the file. Errors: 400 {"error": "Missing required parameters"}, 404 {"error": "Entity not found"}, 500 {"error": "Failed to load entity"}, 403 {"error": "Access denied"}.

Content locks

Operation Parameters Re-checks billable Returns
dxpr_content_lock_status entity_id, revision_id, entity_type, langcode (all required) No JSON object with status (boolean) and label (entity label); when locked, also entity_lock_author_id and entity_lock_author_name.
dxpr_toggle_content_lock entity_id, revision_id, entity_type, langcode, toggle_action (all required; lock creates the lock, any other value removes it) No JSON object with label and status (true after locking, false after unlocking). An empty JSON array ([]) when the entity cannot be loaded or the user lacks update access.

Admin pages

All of these routes accept any method (no methods key). Paths containing {...} take the config entity ID, or the migration ID for {migration_id}.

Path Route Permission Purpose
/admin/dxpr_studio dxpr_builder.admin.studio administer dxpr builder configuration DXPR Studio overview; core's admin menu block page listing child pages.
/admin/dxpr_studio/dxpr_builder dxpr_builder.admin.studio.builder administer dxpr builder configuration DXPR Builder overview; core's admin menu block page.
/admin/dxpr_studio/dxpr_builder/settings dxpr_builder.settings administer dxpr builder configuration DxprBuilderSettingsForm: the module settings form.
/admin/dxpr_studio/dxpr_builder/ai_settings dxpr_builder.ai_settings administer dxpr builder configuration DxprBuilderAiSettingsForm: the AI settings form.
/admin/dxpr_studio/dxpr_builder/user_templates entity.dxpr_builder_user_template.collection administer site configuration List of dxpr_builder_user_template config entities.
/admin/dxpr_studio/dxpr_builder/user_templates/add entity.dxpr_builder_user_template.add_form administer site configuration Add a user template.
/admin/dxpr_studio/dxpr_builder/user_templates/{dxpr_builder_user_template} entity.dxpr_builder_user_template.edit_form administer site configuration Edit a user template.
/admin/dxpr_studio/dxpr_builder/user_templates/{dxpr_builder_user_template}/delete entity.dxpr_builder_user_template.delete_form administer site configuration Delete a user template (confirm form).
/admin/dxpr_studio/dxpr_builder/page_template entity.dxpr_builder_page_template.collection administer site configuration List of dxpr_builder_page_template config entities.
/admin/dxpr_studio/dxpr_builder/page_template/add entity.dxpr_builder_page_template.add_form administer site configuration Add a page template.
/admin/dxpr_studio/dxpr_builder/page_template/create dxpr_builder.create_page_template administer dxpr builder configuration PageController::createPageTemplate(): copies the enabled user template identified by the uuid query parameter into a new page template with the same ID and category DXPR. It sets a status or error message and redirects to the user template list.
/admin/dxpr_studio/dxpr_builder/page_template/{dxpr_builder_page_template} entity.dxpr_builder_page_template.edit_form administer site configuration Edit a page template.
/admin/dxpr_studio/dxpr_builder/page_template/{dxpr_builder_page_template}/delete entity.dxpr_builder_page_template.delete_form administer site configuration Delete a page template (confirm form).
/admin/dxpr_studio/dxpr_builder/profile entity.dxpr_builder_profile.collection administer dxpr_builder_profile List of dxpr_builder_profile config entities.
/admin/dxpr_studio/dxpr_builder/profile/add entity.dxpr_builder_profile.add_form administer dxpr_builder_profile Add a profile.
/admin/dxpr_studio/dxpr_builder/profile/{dxpr_builder_profile} entity.dxpr_builder_profile.edit_form administer dxpr_builder_profile Edit a profile.
/admin/dxpr_studio/dxpr_builder/profile/{dxpr_builder_profile}/delete entity.dxpr_builder_profile.delete_form administer dxpr_builder_profile Delete a profile (confirm form).
/admin/dxpr_studio/dxpr_builder/user_licenses dxpr_builder.user_licenses administer dxpr builder configuration PageController::userLicensesPage(): uncached table of licensed users (columns User, Roles, Sites, Assigned and Operations). Above it, the page renders its own licence summary card (dxpr-license-info) when licence information is available, and, while a freed licence waits out its 30 days, a "Next license available on" notice. On this route the License info block renders nothing, so the summary never shows twice.
/admin/dxpr_studio/dxpr_builder/user_licenses/sites dxpr_builder.user_licenses.sites administer dxpr builder configuration PageController::userLicensesSitesPage(): item list of the domains recorded for the user given in the mail request parameter; opened in a modal from the licences table.
/admin/dxpr_studio/dxpr_builder/content dxpr_builder.licensed_content administer dxpr builder configuration PageController::licensedContentPage(): paged table (20 per page) of content items edited with DXPR Builder, with the content items licence summary. The query parameter needs_migration=1 shows only items that need a content migration. Empty when no licence information is available.
/admin/dxpr_studio/dxpr_builder/migration-status dxpr_builder.migration_status administer dxpr builder configuration MigrationStatusController::statusPage(): uncached table of registered content migrations with their pending items. Each pending migration has a Run now link, and a Run all pending migrations button appears when any are pending.
/admin/dxpr_studio/dxpr_builder/migration-run/{migration_id} dxpr_builder.migration_run_confirm administer dxpr builder configuration MigrationRunConfirmForm: confirms, then runs one migration as a batch and returns to the status page.
/admin/dxpr_studio/dxpr_builder/migration-run-all dxpr_builder.migration_run_all_confirm administer dxpr builder configuration MigrationRunAllConfirmForm: confirms, then runs every registered migration as one batch and returns to the status page.
/dxpr-builder/disavow-user dxpr_builder.disavow_user_confirm administer dxpr builder configuration DisavowUserConfirmForm: confirms excluding the user given in the uid query parameter from DXPR Builder editing.
/dxpr-builder/delete-stale-user dxpr_builder.delete_stale_user_confirm administer dxpr builder configuration DeleteStaleUserConfirmForm: confirms removing licence data for the email address given in the email query parameter.

What's next?

  • Configuration reference for the settings that control the media browser and AI behaviour used by these endpoints.
  • PHP API for the services the controllers call.
  • Hooks API for the hooks that let other modules alter builder behaviour.
Something wrong or missing on this page? Report it or edit the page.