---
url: 'https://dxpr.com/es/hc/documentacion/aprender-dxpr-builder/referencia/endpoints-api'
title: 'Endpoints de API | DXPR'
author:
  name: Jurriaan
  url: 'https://dxpr.com/users/jurriaan'
date: '2026-10-24T00:59:57+00:00'
updated: '2026-10-24T17:19:22+00:00'
copyright: 'Copyright DXPR. All rights reserved.'
type: article
summary: |-
  Esta página lista cada ruta que registra DXPR Builder en
  dxpr_builder.routing.yml, con los métodos HTTP, los requisitos de
  acceso, los parámetros de petición y las formas de respuesta
  implementados en los controladores. El JavaScript del editor es el
  cliente previsto de los endpoints AJAX; nada de esta página es una
  API pública estable, y los nombres de parámetro pueden cambiar entre
  versiones.
  Requisitos de acceso
  Las rutas usan tres tipos de requisito. Una ruta puede combinarlos.
tags:
  - 'Configuration and API'
image: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
published: true
og:
  site_name: DXPR
  updated_time: '2026-10-24T17:19:22+0000'
  'image:alt': 'DXPR, powered by Drupal: AI-powered Drupal for marketers.'
schema:
  '@context': 'https://schema.org'
  '@graph':
    -
      mainEntity: {  }
    -
      '@type': TechArticle
      headline: 'Endpoints de API'
      description: |-
        Esta página lista cada ruta que registra DXPR Builder en
        dxpr_builder.routing.yml, con los métodos HTTP, los requisitos de
        acceso, los parámetros de petición y las formas de respuesta
        implementados en los controladores. El JavaScript del editor es el
        cliente previsto de los endpoints AJAX; nada de esta página es una
        API pública estable, y los nombres de parámetro pueden cambiar entre
        versiones.
        Requisitos de acceso
        Las rutas usan tres tipos de requisito. Una ruta puede combinarlos.
      image:
        '@type': ImageObject
        url: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
        width: '1200'
        height: '630'
      datePublished: '2026-10-24T00:59:57+0000'
      dateModified: '2026-10-24T17:19:22+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/es/hc/documentacion/aprender-dxpr-builder/referencia/endpoints-api'
      articleSection: 'Configuración y API'
    -
      '@type': WebPage
      '@id': 'https://dxpr.com/es/hc/documentacion/aprender-dxpr-builder/referencia/endpoints-api'
      description: |-
        Esta página lista cada ruta que registra DXPR Builder en
        dxpr_builder.routing.yml, con los métodos HTTP, los requisitos de
        acceso, los parámetros de petición y las formas de respuesta
        implementados en los controladores. El JavaScript del editor es el
        cliente previsto de los endpoints AJAX; nada de esta página es una
        API pública estable, y los nombres de parámetro pueden cambiar entre
        versiones.
        Requisitos de acceso
        Las rutas usan tres tipos de requisito. Una ruta puede combinarlos.
      breadcrumb:
        '@type': BreadcrumbList
        itemListElement:
          -
            '@type': ListItem
            position: 1
            name: Inicio
            item: 'https://dxpr.com/es'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
      inLanguage: es
---
[Centro de ayuda](/es/hc)/[Documentación](/es/hc/documentacion) /[Aprende DXPR Builder](/es/hc/documentation/learn-dxpr-builder) /[Referencia](/es/hc/documentation/learn-dxpr-builder/reference) /[Configuración y API](/es/hc/documentation/learn-dxpr-builder/reference/config-and-api) # Endpoints de API.

 Aprende DXPR BuilderReferenciaConfiguración y API

   ## En esta guía

 Guías relacionadas

- [Referencia de configuración](/es/hc/documentacion/aprender-dxpr-builder/referencia/referencia-configuracion)
- [Referencia de la API](/es/hc/documentation/learn-dxpr-builder/development/api)
- [Referencia de la API de hooks](/es/hc/documentacion/aprender-dxpr-builder/desarrollo/api-hooks)

Esta página lista cada ruta que registra DXPR Builder en `dxpr_builder.routing.yml`, con los métodos HTTP, los requisitos de acceso, los parámetros de petición y las formas de respuesta implementados en los controladores. El JavaScript del editor es el cliente previsto de los endpoints AJAX; nada de esta página es una API pública estable, y los nombres de parámetro pueden cambiar entre versiones.

## Requisitos de acceso

Las rutas usan tres tipos de requisito. Una ruta puede combinarlos.

| Requisito | Significado |
|---|---|
| `_permission` | La cuenta necesita el permiso de Drupal nombrado. DXPR Builder define `administer dxpr builder configuration`, `edit with dxpr builder` y `administer dxpr_builder_profile` en `dxpr_builder.permissions.yml`; `view media` y `administer site configuration` vienen del núcleo. |
| `_csrf_token` | La petición debe llevar un token CSRF válido en el parámetro de consulta `token`. Para el manejador AJAX principal, el editor obtiene una URL con el token desde `/dxpr_builder/csrf` (o desde la operación `dxpr_builder_csrf`). Para las demás rutas, el formateador de campo pone URL con token en `drupalSettings.dxprBuilder`, por ejemplo `fileUploadUrl`, `entityLinkSuggestionsUrl`, `userSettingsUrl` y `aiAgent.endpointUrl`. |
| `_dxpr_builder_billable_user` | La cuenta debe ser una cuenta facturable, como se define abajo. |

### Qué significa «cuenta facturable»

`DxprBuilderBillableUserAccessCheck` permite el acceso cuando `DxprBuilderLicenseService::isBillableUser()` devuelve verdadero para la cuenta actual. Ese método devuelve falso para cuentas bloqueadas y para cuentas cuyo campo `dxpr_user_is_disavowed` tiene valor (una persona administradora excluye a una cuenta de la edición en la página Licencias de usuario). Si no, devuelve verdadero para la cuenta 1 y para cualquier cuenta que tiene el permiso `edit with dxpr builder`. En resumen: una cuenta facturable es una cuenta activa y no excluida que puede editar con DXPR Builder, y el servicio de licencias cuenta estas cuentas en tu clave de producto.

### Métodos HTTP

Donde una ruta declara `methods`, solo esos métodos se enrutan. Donde no, la ruta acepta cualquier método (el `MethodFilter` de Drupal solo filtra rutas que declaran métodos). Las tablas de abajo indican el método que usa en realidad el JavaScript del editor cuando se ve en el código.

## Endpoints AJAX del editor

### URL de token CSRF

|  |  |
|---|---|
| Ruta | `/dxpr_builder/csrf` |
| Nombre de ruta | `dxpr_builder.csrf_refresh` |
| Métodos | No declarado (cualquier método). El editor envía GET (`backend-connect.js`, `fetchCsrfTokenUrl()`). |
| Requisitos | Cuenta facturable |
| Controlador | `AjaxController::ajaxRefresh()` |

La petición debe llevar la cabecera `X-Requested-With: XMLHttpRequest`; sin ella el controlador devuelve HTTP 403 con el cuerpo JSON `{"error": "Invalid request"}`.

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `enterprise` | Query string | Opcional | Cuando vale `true` y el módulo `dxpr_builder_e` está instalado, el token se genera para la ruta `dxpr_builder_e.ajax_callback`. Cuando vale `true` sin ese módulo, el controlador lanza una excepción. |

Respuesta: una cadena JSON con la URL del manejador AJAX principal y un parámetro de consulta `token`. La URL es una ruta desde la raíz del sitio (ruta base incluida, sin host). El JavaScript envía cada operación del constructor a esta URL.

### Manejador AJAX principal

|  |  |
|---|---|
| Ruta | `/dxpr_builder/ajax` |
| Nombre de ruta | `dxpr_builder.ajax_callback` |
| Métodos | No declarado (cualquier método). El controlador lee cada parámetro del cuerpo POST, y el editor envía POST. |
| Requisitos | Cuenta facturable, token CSRF |
| Controlador | `AjaxController::ajaxCallback()` |

El campo `action` del cuerpo POST elige la operación. Cada operación y sus parámetros se listan en [Operaciones del manejador AJAX principal](#main-ajax-handler-operations). Cuando falta `action` o es desconocido, el controlador devuelve un `AjaxResponse` de Drupal vacío sin comandos. La mayoría de operaciones que reverifican el estado facturable de la cuenta devuelven la misma respuesta vacía cuando falla esa revisión; las tablas indican las dos excepciones.

### Chat de IA

|  |  |
|---|---|
| Ruta | `/dxpr_builder/ajax/ai/chat` |
| Nombre de ruta | `dxpr_builder.ai_chat` |
| Métodos | POST |
| Requisitos | `edit with dxpr builder`, cuenta facturable, token CSRF |
| Controlador | `AiChatController::chat()` |

El cuerpo de la petición es JSON. El controlador pasa la petición al proveedor `dxpr` del módulo `ai` de Drupal, así que ninguna clave de API llega al navegador. Antes de la llamada combina los dominios del ajuste `ai_output_allowed_domains` en el filtro de nombres de host del módulo `ai`, cuando ese servicio existe. Un valor de `*` pone el filtro en confianza plena. El filtro se restaura después.

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `messages` | Cuerpo JSON | Obligatorio | Array de objetos con `role` y `content`. |
| `stream` | Cuerpo JSON | Opcional | Booleano, por defecto `true`. |
| `model` | Cuerpo JSON | Opcional | Por defecto `kavya-m1`. |
| `prediction` | Cuerpo JSON | Opcional | Se pasa a la configuración del proveedor como array. |
| `providers` | Cuerpo JSON | Opcional | Se pasa tal cual a la configuración del proveedor. |
| `allowed_html_tags` | Cuerpo JSON | Opcional | Se pasa tal cual a la configuración del proveedor. |
| `allowed_html_classes` | Cuerpo JSON | Opcional | Se pasa tal cual a la configuración del proveedor. |
| `web_search` | Cuerpo JSON | Opcional | Solo el valor `false` se reenvía; cualquier otro valor se ignora. |
| `response_format` | Cuerpo JSON | Opcional | Se pasa a la configuración del proveedor como array. |

Respuestas:

| Caso | Estado | Cuerpo |
|---|---|---|
| Retransmitido (`stream` verdadero y el proveedor retransmite) | 200, `Content-Type: text/event-stream` | Eventos enviados por el servidor. Cada evento es `data: <JSON>` donde el JSON tiene `choices[0].delta.content` y, cuando el proveedor los da, `id`, `object`, `created`, `model`, `original_model` y `usage`. La retransmisión termina con `data: [DONE]`. |
| No retransmitido | 200, `application/json` | `{"choices": [{"message": {"role": "assistant", "content": "<text>"}}]}` |
| El cuerpo no es JSON, o falta `messages` o está vacío | 400, texto sin formato | `Invalid request: messages required` |
| `model` no está en la lista `allowed_models` de `ai_provider_dxpr.settings` (solo se revisa cuando el módulo `ai_provider_dxpr` está instalado y la lista tiene valor) | 403, `application/json` | `{"error": {"code": "model_not_allowed", "message": "The selected model is not allowed. Please refresh the page to update your model options."}}` |
| Excepción del proveedor | 500, `application/json` | `{"error": {"message": "The request could not be completed."}}` |

### Generación de imágenes con IA

|  |  |
|---|---|
| Ruta | `/dxpr_builder/ajax/ai/image` |
| Nombre de ruta | `dxpr_builder.ai_image` |
| Métodos | POST |
| Requisitos | `edit with dxpr builder`, cuenta facturable, token CSRF |
| Controlador | `AiImageController::generate()` |

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `prompt` | Cuerpo JSON | Obligatorio | Prompt de texto. |
| `model` | Cuerpo JSON | Opcional | Por defecto `kavya-image`. |
| `size` | Cuerpo JSON | Opcional | Se reenvía a la configuración del proveedor cuando no está vacío. |
| `quality` | Cuerpo JSON | Opcional | Se reenvía a la configuración del proveedor cuando no está vacío. |
| `background` | Cuerpo JSON | Opcional | Se reenvía a la configuración del proveedor cuando no está vacío. |

Respuestas:

| Caso | Estado | Cuerpo |
|---|---|---|
| Éxito | 200 | `{"data": [{"b64_json": "<base64 image>"}]}` (solo se devuelve la primera imagen generada) |
| El cuerpo no es JSON, o `prompt` falta | 400 | `{"error": {"message": "Invalid request: prompt required"}}` |
| El proveedor no devolvió imagen | 500 | `{"error": {"message": "No image was generated"}}` |
| Excepción del proveedor | 500 | `{"error": {"message": "Image generation failed. Please try again."}}` |

### Edición de imágenes con IA

|  |  |
|---|---|
| Ruta | `/dxpr_builder/ajax/ai/image/edit` |
| Nombre de ruta | `dxpr_builder.ai_image_edit` |
| Métodos | POST |
| Requisitos | `edit with dxpr builder`, cuenta facturable, token CSRF |
| Controlador | `AiImageController::edit()` |

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `prompt` | Cuerpo JSON | Obligatorio | Instrucción de edición. |
| `image` | Cuerpo JSON | Obligatorio | Imagen de origen codificada en Base64 (decodificación estricta). |
| `mimeType` | Cuerpo JSON | Opcional | Por defecto `image/png`; el subtipo se vuelve la extensión de archivo pasada al proveedor. |
| `model` | Cuerpo JSON | Opcional | Por defecto `kavya-image`. |
| `size`, `quality`, `background` | Cuerpo JSON | Opcional | Se reenvían a la configuración del proveedor cuando no están vacíos. |

Respuestas:

| Caso | Estado | Cuerpo |
|---|---|---|
| Éxito | 200 | `{"data": [{"b64_json": "<base64 image>"}]}` |
| El cuerpo no es JSON, o `prompt` o `image` faltan | 400 | `{"error": {"message": "Invalid request: prompt and image required"}}` |
| `image` no es base64 válido | 400 | `{"error": {"message": "Invalid image data: base64 decode failed"}}` |
| El proveedor no devolvió imagen | 500 | `{"error": {"message": "No image was generated"}}` |
| Excepción del proveedor | 500 | `{"error": {"message": "Image editing failed. Please try again."}}` |

### Subida de archivos

|  |  |
|---|---|
| Ruta | `/dxpr_builder/ajax/file_upload` |
| Nombre de ruta | `dxpr_builder.ajax_file_upload_callback` |
| Métodos | POST, DELETE (declarados en el enrutado; el controlador tiene un solo manejador de subida y ninguna rama separada de borrado) |
| Requisitos | Cuenta facturable, token CSRF |
| Controlador | `UploadFileController::fileUpload()` |

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `upload` | Archivos de formulario multiparte, enviados como `upload[]` | Obligatorio | Uno o más archivos subidos. |

El controlador clasifica cada archivo por la primera parte de su MIME de cliente en `<default scheme>://dxpr_builder_images`, `dxpr_builder_videos` o `dxpr_builder_files`. Una imagen necesita una extensión de los tipos MIME `image/gif`, `jpg`, `jpeg`, `png`, `webp`, `avif` o `svg`. Un vídeo necesita uno de `video/webm`, `ogv`, `ogg`, `mp4` o `quicktime` (por ejemplo `.mov`). El límite de tamaño es el máximo de subida de PHP. Un archivo con el mismo nombre e idéntico contenido SHA-256 que un archivo gestionado existente que la cuenta puede ver se reutiliza en lugar de guardarse de nuevo. Cuando el módulo `media` está instalado y existe un tipo de medio llamado `image`, `media_image`, `video` o `media_video`, se crea una entidad de medio publicada (o se reutiliza) para el archivo. El uso del archivo se registra en el módulo `dxpr_builder`.

Respuestas:

| Caso | Estado | Cuerpo |
|---|---|---|
| Éxito | 201 | Array JSON, un objeto por archivo: `url` (URL absoluta del archivo), `uuid` e `id` (de la entidad de medio cuando existe, si no del archivo), `fid` (ID del archivo), `entity_type` (`media` o `file`). |
| Sin archivos `upload` subidos | 400 | `{"message": "No files were uploaded."}` |
| Subida no válida, destino sin escritura o fallo al guardar | 500 | `{"message": "<reason>"}` |
| Fallo de validación (extensión o tamaño) | 422 | `{"message": "<violation messages>"}` |
| Nombre de archivo ya bloqueado por otra petición | 503 | `{"message": "File \"<name>\" is already locked for writing."}` |

### Diálogo de biblioteca de medios

|  |  |
|---|---|
| Ruta | `/dxpr_builder/media-library` |
| Nombre de ruta | `dxpr_builder.media_library` |
| Métodos | No declarado (cualquier método). Los parámetros se leen de la query string. |
| Requisitos | `view media`; ruta de administración |
| Controlador | `AjaxController::openImageMediaLibrary()` |

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `media_type` | Query string | Opcional | `image` (por defecto) o `video`. |
| `remaining_slots` | Query string | Opcional | Número de elementos que acepta quien abre; por defecto 1. |
| `uuid` | Query string | Opcional | Se pasa a quien abre como `opener_parameters.uuid`. |

El tipo de medio ofrecido depende del ajuste `media_browser`: `media_library` usa el tipo de medio `image` o `video` directamente; `media_library_acquia_dam` usa `acquia_dam_image_asset` o `acquia_dam_video_asset` cuando ese tipo de medio existe.

Respuestas:

| Caso | Resultado |
|---|---|
| Éxito | Un array de render creado por `MediaLibraryUiBuilder::buildUi()` con el abridor `media_library.opener.dxpr_builder`. Drupal lo muestra como página HTML pensada para un iframe. |
| `media_library`: módulo no instalado | 403, texto sin formato `Media Library is not enabled. Please enable it to access this feature.` |
| Tipo no admitido de `media_type` | 400, texto sin formato `Unsupported media type "<value>".` |
| `media_browser` no tiene tipo de medio usable | 400, texto sin formato `The "<setting>" settings is not supported.` |

### Validador de enlaces de ayuda

|  |  |
|---|---|
| Ruta | `/dxpr_builder/ajax/help_link_validator` |
| Nombre de ruta | `dxpr_builder.ajax_help_link_validator` |
| Métodos | No declarado (cualquier método). El script de desarrollo `dxpr_builder_dev.js` envía POST con cuerpo de formulario. |
| Requisitos | Cuenta facturable |
| Controlador | `AjaxController::validateHelpLink()` |

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `help_link` | Cuerpo POST | Obligatorio para una respuesta con sentido | Solo se revisan URL `http` o `https` en el host `dxpr.com` con ruta que empieza por `/documentation/`. |

Respuesta: un array JSON. `[true]` cuando una petición HEAD al enlace (sin seguir redirecciones) devuelve 200; `[false]` cuando el cliente HTTP lanza una excepción; `[]` en cualquier otro caso, incluido un parámetro ausente, una URL no coincidente o un estado distinto de 200.

### Sugerencias de enlaces de entidad

|  |  |
|---|---|
| Ruta | `/dxpr_builder/entity-link-suggestions` |
| Nombre de ruta | `dxpr_builder.entity_link_suggestions` |
| Métodos | GET |
| Requisitos | `edit with dxpr builder`, token CSRF; opción `no_cache` de ruta |
| Controlador | `EntityLinkSuggestionsController::suggestions()` |

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `q` | Query string | Obligatorio para resultados | Texto de búsqueda, en minúsculas. Un valor como `/node/123` carga esa entidad directamente. |
| `langcode` | Query string | Opcional | Idioma de la entidad anfitriona; por defecto el idioma actual. Solo se devuelven entidades disponibles en este idioma. |

Los bundles son los que tienen `ckeditor5_link_suggestions` activado en su info de bundle; cuando no hay ninguno configurado, se buscan todos los bundles de nodo. Hasta 100 entidades por tipo de entidad coinciden con una búsqueda `CONTAINS` en los plugins de selección de referencia de entidad del núcleo.

Respuesta: `{"suggestions": [...]}` con caché privada y una edad máxima de 300 segundos. Cada sugerencia tiene `description`, `entity_type_id`, `entity_uuid`, `group`, `label` y `path`. Cuando `q` no coincide con nada, el array guarda una sola sugerencia de enlace manual con `description`, `label` (la entrada en minúsculas) y `path` (la entrada cuando es una URL válida; si no, una cadena vacía). Cuando `q` está vacío, `suggestions` es un array vacío.

### Ajustes de editor de la cuenta

|  |  |
|---|---|
| Ruta | `/dxpr_builder/user-settings` |
| Nombre de ruta | `dxpr_builder.user_settings` |
| Métodos | POST |
| Requisitos | `edit with dxpr builder`, token CSRF; opción `no_cache` de ruta |
| Controlador | `UserSettingsController::save()` |

El editor envía esta petición cuando una cuenta cambia sus propios ajustes de editor, por ejemplo en **Ajustes del editor**. Los valores se guardan con la cuenta de usuario en `user.data`, módulo `dxpr_builder`.

| Parámetro | Origen | Obligatorio | Notas |
|---|---|---|---|
| `controls_layout` | Cuerpo JSON | Obligatorio (el único ajuste) | `element`, `breadcrumb` o `default`. `default` quita la elección de la cuenta, así que vale el ajuste del perfil o del sitio. |

Respuestas:

| Caso | Estado | Cuerpo |
|---|---|---|
| Guardado | 200 | `{"settings": {"controls_layout": "<value>"}}`: cada ajuste tras guardar, `default` donde la cuenta no tiene elección guardada. |
| El cuerpo no es un objeto JSON no vacío, o un nombre o valor no es válido | 400 | `{"error": "Invalid setting or value."}`. No se guarda nada. |

## Operaciones del manejador AJAX principal

Todas las operaciones van a `/dxpr_builder/ajax` con el parámetro de consulta de token obtenido de `/dxpr_builder/csrf`. El nombre de la operación se envía en el campo `action` del cuerpo POST; todos los demás parámetros son campos del cuerpo POST salvo que se indique lo contrario. La columna «Reverifica facturable» marca las operaciones que llaman a `isBillableUser()` de nuevo dentro del switch. Cuando falla esa revisión devuelven el `AjaxResponse` vacío descrito arriba, salvo que la fila diga lo contrario.

### Sesión y acceso

| Operación | Parámetros | Reverifica facturable | Devuelve |
|---|---|---|---|
| `dxpr_login` | Ninguno | No | Booleano JSON: si la cuenta actual es facturable. |
| `dxpr_builder_csrf` | Ninguno | Sí | Cadena JSON: la URL del manejador con un parámetro de consulta `token` (igual que `/dxpr_builder/csrf` sin la opción `enterprise`). |

### Contenedores (campos mostrados con el formateador de DXPR Builder)

| Operación | Parámetros | Reverifica facturable | Devuelve |
|---|---|---|---|
| `dxpr_get_container_types` | Ninguno | Sí | Objeto JSON con claves `entity_type\|bundle` y valor `entity_type - bundle`, una entrada por bundle cuya visualización de vista por defecto usa el formateador `dxpr_builder_text` en al menos un campo. |
| `dxpr_get_container_names` | `container_type` (obligatorio, `entity_type\|bundle`) | Sí (devuelve una cadena JSON vacía en lugar de la respuesta vacía) | Objeto JSON con claves `entity_id\|field_name` (o `entity_id\|field_name\|langcode` para entidades traducibles) y valor `entity label\|field label`. Cuando falta `container_type`, o falla la revisión facturable, la respuesta es una cadena JSON vacía. |
| `dxpr_save_container` | `type` (obligatorio, `entity_type\|bundle`); `name` (obligatorio, `entity_id\|field_name` o `entity_id\|revision_id\|field_name`); `htmlContent` (obligatorio, marcado codificado); `lang` (opcional, por defecto el idioma por defecto del sitio) | Sí | Cadena JSON vacía si todo va bien. HTTP 400 con mensaje JSON cuando `htmlContent` no es una cadena o el idioma no vale para una entidad no traducible; 404 cuando la traducción pedida no existe; 500 cuando la entidad no se puede cargar. |

`dxpr_save_container` hace lo siguiente:

1. Decodifica `htmlContent`: XOR de cada byte con 7, luego decodificación URL.
2. Escribe el resultado en el primer delta del campo nombrado.
3. Crea una revisión por defecto nueva con el mensaje de registro `Saved with DXPR builder` cuando el tipo de entidad admite revisiones.
4. Quita cualquier bloqueo de contenido de la entidad.
5. Actualiza `block_revision_id` en las secciones de Layout Builder que referencian el bloque en línea guardado.
6. Incrementa el valor de estado `dxpr_builder.saves_count`.

El guardado solo ocurre cuando la cuenta tiene acceso `update` a la entidad. Sin él, la operación aún devuelve la respuesta de éxito de cadena vacía.

### Elementos CMS (bloques y vistas)

| Operación | Parámetros | Reverifica facturable | Devuelve |
|---|---|---|---|
| `dxpr_builder_get_cms_element_names` | Ninguno | Sí | Objeto JSON de `DxprBuilderService::getCmsElementNames()` con claves `list`, `disallowed` y `blockCategories`. |
| `dxpr_get_cms_element_settings` | `name` (obligatorio): `view-<view_id>-<display_id>` o `block-<plugin_id>`; `ajax_page_state[libraries]` (opcional, bibliotecas ya cargadas separadas por comas) | Sí | Objeto JSON con `css`, `js`, `settings` y `data`. Para una vista, `data` son los widgets de filtros expuestos mostrados; para un bloque, `data` es el formulario de configuración del bloque envuelto en etiquetas `<form>`, sin los elementos `provider`, `admin_label`, `label`, `label_display` ni `context_mapping`, y con todos los elementos details abiertos. |
| `dxpr_builder_load_cms_element` | `name` (obligatorio, analizado por `parseStringForCmsElementInfo()`); `settings` (obligatorio); `data` (obligatorio, array); `ajax_page_state[libraries]` (opcional) | No | Objeto JSON con `css`, `js`, `settings` y `data`, donde `data` es la vista o el bloque mostrado. |

En ambas operaciones que devuelven `settings`, `css` y `js` son etiquetas de recursos mostradas que aún no están en la página, y `settings` es el objeto `drupalSettings` decodificado, o una cadena vacía cuando no hay ninguno.

### Plantillas de página

| Operación | Parámetros | Reverifica facturable | Devuelve |
|---|---|---|---|
| `dxpr_get_page_templates` | Ninguno | Sí | Array JSON de plantillas de página activadas, cada una con `title`, `uuid`, `module` (siempre `null`: la entidad no lo guarda), `category`, `date`, `weight` (entero) e `image` (una URL `data:`, o la URL de `not-found.png` del módulo). |
| `dxpr_load_page_template` | `uuid` (obligatorio) | Sí | Respuesta HTML con el marcado de la plantilla y los tokens base cambiados; vacía cuando ninguna plantilla activada coincide. |

### Plantillas de usuario

| Operación | Parámetros | Reverifica facturable | Devuelve |
|---|---|---|---|
| `dxpr_get_templates` | Ninguno | Sí | Array JSON de plantillas de la cuenta actual o marcadas como globales; las plantillas cuya cuenta propietaria ya no existe quedan fuera. Cada entrada tiene `id`, `uuid`, `name`, `global`, `current_user_is_author`, `author_id`, `author_name`, `type` y, cuando se guarda, `image` (una URL `data:`). |
| `dxpr_load_template` | `uuid` (obligatorio) | Sí | Respuesta HTML con el marcado de la plantilla y los tokens base cambiados; vacía cuando ninguna plantilla activada coincide. |
| `dxpr_save_template` | `name` (obligatorio); `template` (obligatorio, marcado); `type` (opcional, por defecto `custom`); `global` (opcional, convertido a booleano); `image` (opcional: una cadena base64 o URL `data:image` en el cuerpo POST, o un campo de archivo multiparte llamado `image`) | Sí | Objeto JSON con `message` y `code`. `code` 200 si todo va bien; `code` 409 (estado HTTP 200) cuando existe una plantilla con el mismo nombre de sistema; `code` 400 con HTTP 400 cuando la imagen no son datos de imagen válidos. |
| `dxpr_delete_template` | `name` (obligatorio) | Sí | Cadena JSON vacía. |

El nombre de sistema deriva de `name` pasándolo a minúsculas y cambiando cada grupo de caracteres fuera de `a-z0-9_` por un guion bajo. `type` recurre al atributo `data-azb` del marcado cuando una plantilla guardada no tiene tipo.

### Imágenes

| Operación | Parámetros | Reverifica facturable | Devuelve |
|---|---|---|---|
| `dxpr_builder_get_image_urls` | `entityIDs` (obligatorio, array); `imageStyle` (obligatorio; `original` para el archivo sin estilo); `entityType` (obligatorio; `media` resuelve elementos de medio, cualquier otro valor se usa como tipo de entidad de los ID) | Sí | Cuerpo de texto: URL de imágenes separadas por comas. Los archivos dan una URL relativa a la raíz con parámetro de consulta `fid`. Los elementos de medio de tipo `image` o `video` resuelven a su archivo de origen. Los elementos `acquia_dam_image_asset` dan la URL de DAM con `mid`, `acquiaDamAsset` e `imageStyle` añadidos. Los demás elementos de medio se saltan. HTTP 204 sin cuerpo cuando `entityIDs` está vacío, o cuando ningún elemento de medio se puede resolver. |
| `dxpr_builder_get_image_style_url` | `imageStyle` (obligatorio); `entityId` (obligatorio); `entityTypeId` (obligatorio, `file` o `media`) | Sí | Cuerpo de texto. Para un archivo: su URL relativa a la raíz con el estilo de imagen (los archivos SVG y `original` saltan el estilo), con parámetro de consulta `fid`. Para un elemento de medio `acquia_dam_image_asset`: la URL de DAM. HTTP 204 sin cuerpo para cualquier otra entidad, o cuando la entidad no se encuentra. |
| `dxpr_builder_get_image_metadata` | `entityId` (obligatorio); `entityType` (obligatorio, `file` o `media`) | Sí (devuelve 403 JSON en lugar de la respuesta vacía) | `{"data": {"alt": "...", "title": "..."}}` del campo de origen de imagen del elemento de medio (un recurso de Acquia DAM da su texto Alt de DAM y un título vacío). Para un archivo, los valores vienen del primer elemento de medio cuyo `field_media_image` lo referencia. `data` es un array vacío cuando la entidad no es ni archivo ni elemento de medio, o cuando ningún medio referencia al archivo. Errores: 400 `{"error": "Missing required parameters"}`, 404 `{"error": "Entity not found"}`, 500 `{"error": "Failed to load entity"}`, 403 `{"error": "Access denied"}`. |

### Bloqueos de contenido

| Operación | Parámetros | Reverifica facturable | Devuelve |
|---|---|---|---|
| `dxpr_content_lock_status` | `entity_id`, `revision_id`, `entity_type`, `langcode` (todos obligatorios) | No | Objeto JSON con `status` (booleano) y `label` (etiqueta de la entidad); cuando está bloqueada, también `entity_lock_author_id` y `entity_lock_author_name`. |
| `dxpr_toggle_content_lock` | `entity_id`, `revision_id`, `entity_type`, `langcode`, `toggle_action` (todos obligatorios; `lock` crea el bloqueo, cualquier otro valor lo quita) | No | Objeto JSON con `label` y `status` (`true` tras bloquear, `false` tras desbloquear). Un array JSON vacío (`[]`) cuando la entidad no se puede cargar o la cuenta no tiene acceso `update`. |

## Páginas de administración

Todas estas rutas aceptan cualquier método (sin clave `methods`). Las rutas que llevan `{...}` toman el ID de entidad de configuración, o el ID de migración para `{migration_id}`.

| Ruta | Nombre de ruta | Permiso | Propósito |
|---|---|---|---|
| `/admin/dxpr_studio` | `dxpr_builder.admin.studio` | `administer dxpr builder configuration` | Resumen de DXPR Studio; página de bloque del menú de administración del núcleo con las páginas hijas. |
| `/admin/dxpr_studio/dxpr_builder` | `dxpr_builder.admin.studio.builder` | `administer dxpr builder configuration` | Resumen de DXPR Builder; página de bloque del menú de administración del núcleo. |
| `/admin/dxpr_studio/dxpr_builder/settings` | `dxpr_builder.settings` | `administer dxpr builder configuration` | `DxprBuilderSettingsForm`: el formulario de ajustes del módulo. |
| `/admin/dxpr_studio/dxpr_builder/ai_settings` | `dxpr_builder.ai_settings` | `administer dxpr builder configuration` | `DxprBuilderAiSettingsForm`: el formulario de ajustes de IA. |
| `/admin/dxpr_studio/dxpr_builder/user_templates` | `entity.dxpr_builder_user_template.collection` | `administer site configuration` | Lista de entidades de configuración `dxpr_builder_user_template`. |
| `/admin/dxpr_studio/dxpr_builder/user_templates/add` | `entity.dxpr_builder_user_template.add_form` | `administer site configuration` | Añade una plantilla de usuario. |
| `/admin/dxpr_studio/dxpr_builder/user_templates/{dxpr_builder_user_template}` | `entity.dxpr_builder_user_template.edit_form` | `administer site configuration` | Edita una plantilla de usuario. |
| `/admin/dxpr_studio/dxpr_builder/user_templates/{dxpr_builder_user_template}/delete` | `entity.dxpr_builder_user_template.delete_form` | `administer site configuration` | Borra una plantilla de usuario (formulario de confirmación). |
| `/admin/dxpr_studio/dxpr_builder/page_template` | `entity.dxpr_builder_page_template.collection` | `administer site configuration` | Lista de entidades de configuración `dxpr_builder_page_template`. |
| `/admin/dxpr_studio/dxpr_builder/page_template/add` | `entity.dxpr_builder_page_template.add_form` | `administer site configuration` | Añade una plantilla de página. |
| `/admin/dxpr_studio/dxpr_builder/page_template/create` | `dxpr_builder.create_page_template` | `administer dxpr builder configuration` | `PageController::createPageTemplate()`: copia la plantilla de usuario activada identificada por el parámetro de consulta `uuid` en una plantilla de página nueva con el mismo ID y la categoría `DXPR`. Fija un mensaje de estado o de error y redirige a la lista de plantillas de usuario. |
| `/admin/dxpr_studio/dxpr_builder/page_template/{dxpr_builder_page_template}` | `entity.dxpr_builder_page_template.edit_form` | `administer site configuration` | Edita una plantilla de página. |
| `/admin/dxpr_studio/dxpr_builder/page_template/{dxpr_builder_page_template}/delete` | `entity.dxpr_builder_page_template.delete_form` | `administer site configuration` | Borra una plantilla de página (formulario de confirmación). |
| `/admin/dxpr_studio/dxpr_builder/profile` | `entity.dxpr_builder_profile.collection` | `administer dxpr_builder_profile` | Lista de entidades de configuración `dxpr_builder_profile`. |
| `/admin/dxpr_studio/dxpr_builder/profile/add` | `entity.dxpr_builder_profile.add_form` | `administer dxpr_builder_profile` | Añade un perfil. |
| `/admin/dxpr_studio/dxpr_builder/profile/{dxpr_builder_profile}` | `entity.dxpr_builder_profile.edit_form` | `administer dxpr_builder_profile` | Edita un perfil. |
| `/admin/dxpr_studio/dxpr_builder/profile/{dxpr_builder_profile}/delete` | `entity.dxpr_builder_profile.delete_form` | `administer dxpr_builder_profile` | Borra un perfil (formulario de confirmación). |
| `/admin/dxpr_studio/dxpr_builder/user_licenses` | `dxpr_builder.user_licenses` | `administer dxpr builder configuration` | `PageController::userLicensesPage()`: tabla sin caché de cuentas con licencia (columnas Cuenta, Roles, Sitios, Asignada y Operaciones). Encima, la página muestra su propia tarjeta de resumen de licencia (`dxpr-license-info`) cuando hay información de licencia, y, mientras una licencia liberada espera sus 30 días, un aviso «Próxima licencia disponible el». En esta ruta el bloque **License info** no muestra nada, así que el resumen nunca sale dos veces. |
| `/admin/dxpr_studio/dxpr_builder/user_licenses/sites` | `dxpr_builder.user_licenses.sites` | `administer dxpr builder configuration` | `PageController::userLicensesSitesPage()`: lista de los dominios registrados para la cuenta indicada en el parámetro de petición `mail`; se abre en una ventana modal desde la tabla de licencias. |
| `/admin/dxpr_studio/dxpr_builder/content` | `dxpr_builder.licensed_content` | `administer dxpr builder configuration` | `PageController::licensedContentPage()`: tabla paginada (20 por página) de elementos de contenido editados con DXPR Builder, con el resumen de licencia de elementos de contenido. El parámetro de consulta `needs_migration=1` muestra solo elementos que necesitan una migración de contenido. Vacía cuando no hay información de licencia. |
| `/admin/dxpr_studio/dxpr_builder/migration-status` | `dxpr_builder.migration_status` | `administer dxpr builder configuration` | `MigrationStatusController::statusPage()`: tabla sin caché de migraciones de contenido registradas con sus elementos pendientes. Cada migración pendiente tiene un enlace **Ejecutar ahora**, y un botón **Ejecutar todas las migraciones pendientes** aparece cuando hay alguna pendiente. |
| `/admin/dxpr_studio/dxpr_builder/migration-run/{migration_id}` | `dxpr_builder.migration_run_confirm` | `administer dxpr builder configuration` | `MigrationRunConfirmForm`: confirma y luego ejecuta una migración como lote, y vuelve a la página de estado. |
| `/admin/dxpr_studio/dxpr_builder/migration-run-all` | `dxpr_builder.migration_run_all_confirm` | `administer dxpr builder configuration` | `MigrationRunAllConfirmForm`: confirma y luego ejecuta cada migración registrada como un lote, y vuelve a la página de estado. |
| `/dxpr-builder/disavow-user` | `dxpr_builder.disavow_user_confirm` | `administer dxpr builder configuration` | `DisavowUserConfirmForm`: confirma excluir de la edición con DXPR Builder a la cuenta indicada en el parámetro de consulta `uid`. |
| `/dxpr-builder/delete-stale-user` | `dxpr_builder.delete_stale_user_confirm` | `administer dxpr builder configuration` | `DeleteStaleUserConfirmForm`: confirma quitar los datos de licencia de la dirección de correo indicada en el parámetro de consulta `email`. |

## ¿Qué sigue?

- [Referencia de configuración](/es/hc/documentacion/aprender-dxpr-builder/referencia/referencia-configuracion) para los ajustes que controlan el navegador de medios y el comportamiento de IA usados por estos endpoints.
- [API de PHP](/es/hc/documentation/learn-dxpr-builder/development/api) para los servicios que llaman los controladores.
- [API de hooks](/es/hc/documentacion/aprender-dxpr-builder/desarrollo/api-hooks) para los hooks que dejan que otros módulos cambien el comportamiento del constructor.