Versiones y compatibilidad
Matriz de versiones de la API externa, los SDK de JavaScript y Python y el widget, con lo que aporta cada versión y sus cambios incompatibles.
Actualizado el . 15 min de lectura
Incluido en todos los planes. Ver precios
Esta página es la referencia única de versiones del ecosistema de integración de UTILIA OS: la API externa, los dos SDK oficiales y el widget. Úsala para fijar las dependencias de tu proyecto y para saber qué aporta cada versión antes de actualizar.
Matriz de versiones
| Componente | Paquete | Versión en el árbol | Última versión publicada |
|---|---|---|---|
| API externa | /external/v1 | v1 | v1 |
| SDK JavaScript | @utilia-os/sdk-js | 4.1.0 | 4.1.0 |
| SDK Python | utilia-sdk | 4.1.0 | 4.1.0 |
| Widget | @utilia-os/widget | 1.1.0 | 1.1.0 |
La 4.1.0 es a la vez la versión del repositorio y la última publicada, en los dos lenguajes: npm install @utilia-os/sdk-js y pip install utilia-sdk instalan esa versión. Los dos SDK comparten numeración y se publican a la vez, para que la paridad entre lenguajes se mantenga versión a versión.
Antes de dar por hecho que un método existe, comprueba qué versión tienes con npm ls @utilia-os/sdk-js o pip show utilia-sdk: si vienes de la 3.x, la 4.0.0 retiró tres métodos y tu código puede depender de ellos.
Novedades de la versión 4.1.0
La 4.1.0 (2026-09-12) añade el calendario laboral de la empresa por MCP, sin
cambios incompatibles. sdk.mcp.attendance.holidays envuelve la parte de
festivos de la herramienta attendance del servidor de recursos humanos
(POST /api/mcp/rrhh):
getScope()(get_scope()en Python) devuelve el ámbito de la empresa (comunidad autónoma, isla y municipio) y el vocabulario cerrado para elegirlo.setScope()(set_scope()) lo fija. No borra ningún festivo: los del ámbito anterior dejan de contar y quedan visibles como «de otros ámbitos».import(year)(import_year(year), porqueimportes palabra reservada en Python) carga el calendario oficial de ese año. Es idempotente.list()lista los festivos;applicablefiltra los que cuentan para la empresa o los de otros ámbitos.
Los festivos municipales no se cargan: los publica cada ayuntamiento y la
respuesta lo avisa en notice. Consultar y listar exige hr:attendance:view;
elegir el ámbito y cargar el año, hr:attendance:manage.
Si ya estás en la 4.0.1, subir a la 4.1.0 no te obliga a tocar nada.
Novedades de la versión 4.0.1
La 4.0.1 (2026-09-09) es una versión solo de documentación interna del paquete: no cambia ningún comportamiento ni ninguna firma. Además alinea el número de versión del paquete de Python, que arrastraba un 2.23.0 en su package.json que no correspondía con lo que de verdad se publica.
Si ya estás en la 4.0.0, subir a la 4.0.1 no te obliga a tocar nada.
Novedades de la versión 4.0.0
La 4.0.0 (2026-09-07) añade sdk.paymentMethods.getReadiness()
(payment_methods.get_readiness() en Python, en las variantes asíncrona y
síncrona), que responde si la organización puede cobrar con tarjeta ahora mismo
y por qué no. Es el mismo criterio que usa la interfaz de UTILIA OS para
decidir si enseña el botón de cobrar. Tipos nuevos: ChargingReadiness y
ChargingReadinessReason. El detalle está en
Comprobar si se puede cobrar.
Es una versión mayor porque retira tres métodos: getEmailRecipients, sendEmail y replyEmail de sdk.mcp.erp.suppliers.
Novedades de la versión 3.0.0
La 3.0.0 (2026-09-05) hace que la facturación y el cobro de una aplicación externa funcionen de verdad. Es una versión mayor, y la razón principal no es el volumen de cambios: es que cinco servicios que existían y devolvían 401 siempre pasan a funcionar contra otra ruta, y uno desaparece.
Lo que gana:
sdk.subscriptionsfunciona, sobre/external/v1/subscriptions, con trece métodos: alta, listado, detalle, cambios, pausa, reanudación, baja, reactivación, generación adelantada, próximo cobro, facturas generadas, historial de ejecuciones y reintento del cobro.sdk.paymentAuthorizationses nuevo (sdk.payment_authorizationsen Python), con el texto de consentimiento, el alta de la autorización firmada, el listado, el detalle y la retirada.sdk.invoicesgana cinco acciones:send,charge,markPaid,getPublicLinkyregeneratePublicLink.sdk.invoices.scheduledChargesfunciona, con programar, listar, cancelar y adelantar el reintento.sdk.invoices.refunds.createemite el reembolso por la API externa.sdk.webhooks.verifyysdk.webhooks.parseverifican la firma de cualquier familia de avisos, con tipos por evento para facturación, suscripciones y cobros.sdk.users.identifyaceptaclientIdpara vincular el usuario a una ficha de cliente que la aplicación creó antes.- Los enumerados se derivan del esquema real:
InvoiceStatuspasa de 7 a 12 valores yTaxSystemsumaIPSIeINTERNATIONAL. En Python, un enumerado incompleto reventaba con un error de validación en la primera factura reembolsada. - El catálogo de permisos de los dos SDK pasa a 56, con la categoría nueva de críticos financieros.
Tabla de rupturas
| Antes | Después | Qué hay que cambiar |
|---|---|---|
sdk.subscriptions.* sobre /finance/recurring-invoices (401 siempre) | sobre /external/v1/subscriptions | clientId desaparece y userId pasa a obligatorio en todos los métodos |
sdk.subscriptions.create({ clientId, ... }) | create({ userId, ... }) | Cambiar el identificador |
sdk.subscriptions.remove(id) | retirado | La baja es cancel(id, { userId }), que conserva el historial |
sdk.subscriptions.stats() | retirado | Era una métrica del tenant, no de la aplicación |
sdk.subscriptions.pause(id) | pause(id, { userId }) | Añadir el usuario |
sdk.mandates.* | sdk.paymentAuthorizations.* | Renombre visible. El alias antiguo sigue funcionando y avisa |
sdk.mandates.listForClient(clientId) | retirado | Una aplicación externa no conoce clientes del CRM |
sdk.mandates.revoke(id) | revoke(id, { userId }) | Añadir el usuario |
sdk.invoices.scheduledCharges.schedule(invoiceId, { stripePaymentMethodId, mandateConsent }) | .schedule(invoiceId, { userId, scheduledAt, paymentAuthorizationId }) | Cuerpo distinto. El consentimiento se firma antes, en su propio endpoint |
sdk.invoices.scheduledCharges.update(...) | retirado | Cambiar la fecha es cancelar y volver a programar |
sdk.invoices.refunds.cancelPreview y .cancel | sdk.invoices.refunds.create(...) | Deshacer un reembolso es del equipo; lo que la aplicación puede hacer es emitirlo |
sdk.invoices.rectifications.updateLegalMetadata | retirado con error claro | Reservado al equipo; usar la herramienta MCP crm_invoices_rectifications |
sdk.invoices.getPdfUrl(id, userId) | retirado | Sustituto: regeneratePublicLink. Si lo usaste, regenera la clave de API |
sdk.chat.webhooks.verify(...) | sdk.webhooks.verify(rawBody, headers, secret) | Sale de chat. El alias antiguo conserva su firma |
sdk.scheduled_charges (Python, en la raíz) | sdk.invoices.scheduled_charges | Reubicación. El alias antiguo sigue funcionando y avisa |
sdk.scheduled_charges.retrieve(id) (Python) | retirado | La ruta no existía |
InvoiceStatus con 7 valores (Python) | 12 valores | El enumerado reventaba en la primera factura reembolsada |
Antes de actualizar, revisa tus permisos
La 3.0.0 estrena once permisos y endurece uno existente: POST /external/v1/users/identify pasa a exigir crm:users:write. Si tu aplicación ya usaba identify, concédele ese permiso antes de desplegar, o la llamada empezará a responder 403.
Novedades de la versión 2.27.0
La 2.27.0 (2026-09-04) completa la paridad del CRM en los dos SDK oficiales.
sdk.mcp.crmes nuevo, con clientes, contactos y leads: altas y ediciones unitarias o por lotes, duplicados, fusiones y transiciones.- Las operaciones destructivas o con efecto externo mandan confirmación explícita desde sus métodos de alto nivel.
- Los errores MCP conservan
errorCodeydetails, de modo que una integración puede distinguir permisos, campos inválidos y reglas de negocio.
Novedades de la versión 2.26.0
La 2.26.0 (2026-09-02) recoge el lote MCP del 2 de septiembre: dos herramientas transversales nuevas y varios cambios de contrato del servidor. Los detalles y las fechas de caducidad de las redes de compatibilidad están en la sección de cambios de contrato.
sdk.mcp.searchysdk.mcp.notifications, nuevos. El buscador global del ecosistema y los avisos de la persona que autorizó el token. Tienen página propia.- El cliente MCP deja de tragarse el mensaje de los errores de una herramienta. Ahora lee las tres formas que conviven, añade la pista al mensaje y conserva el código original en
errorCode.
Novedades de la versión 2.23.0
La 2.23.0 (2026-08-05) cierra el lote de medición y atribución de Marketing: sdk.mcp.marketing pasa de 20 a 87 métodos por lenguaje y cubre enteras marketing_campaigns (35 operaciones), marketing_lists (17) y marketing_deliverability (10).
- Comportamiento de la audiencia y segundos intentos:
engagementBreakdown(siete grupos, dos niveles, y el recuento es gratuito),resendPreview,createResendylistResends. - Interés de los suscriptores:
listSubscribers—que no existía en MCP—,engagementSummary,setAsideInactiveyreactivateSubscriber. Apartar no es dar de baja y el consentimiento no se toca. - Quejas por correo no deseado:
reports.complaints,deliverability.getComplaintPolicyysetComplaintPolicy. La tasa esnullcuando no hay forma de medirla, nunca0 %. - Medición del correo:
reports.linkHeatmapyreports.audienceTech. El país es aproximado y sale de una base local.
Novedades de la versión 2.22.0
La 2.22.0 (2026-08-03) completa las imágenes de presupuesto en sdk.budgets:
uploadImageToSection(budgetId, sectionId, file, placement?)/upload_image_to_section(...): atajo para colocar una imagen dentro de un apartado. El apartado lo fija la dirección, así que el cuerpo no puede apuntar a otro.scanLegacyImages(budgetId)/scan_legacy_images(...): detecta las imágenes heredadas incrustadas en el HTML de los apartados, que se ven en el editor y no salen en el PDF.migrateLegacyImages(budgetId)/migrate_legacy_images(...): las convierte en colocaciones reales. Es idempotente y tolera fallos parciales: cada imagen vuelve comoMIGRATEDoFAILEDcon su motivo.- Quedan obsoletos
textWrap(el generador del PDF nunca lo aplicó: la imagen siempre ocupa su propia línea) y la opcióndeleteFileal borrar una imagen (el borrado del binario pasó a ser automático por recuento de referencias). Los dos se siguen aceptando y el servidor los ignora.
Novedades de la versión 2.21.0
La 2.21.0 (2026-07-28) hace que sdk.oauth.getAuthorizedApps() / get_authorized_apps() devuelva los permisos ya traducidos y recortados por el plan de la organización: permissions, permissionCount, unavailablePermissionCount y unavailableModules, todos opcionales para no romper contra un backend anterior.
AuthorizedApp.scope cambió de significado en la 2.21.0. El campo queda obsoleto (retirada prevista el 2027-02-01) y, sobre todo, ya no es el universo de scopes concedidos a la aplicación, sino ese universo recortado por el plan. Un scope que sigue vivo en el token puede no aparecer en el campo si su aplicativo no está contratado, así que quien lo use para decidir qué puede hacer la aplicación verá menos de lo que hay. Sustitúyelo por permissions (lo ejercible) y unavailablePermissionCount (lo que quedó fuera).
Novedades de la versión 2.18.0
La 2.18.0 (2026-07-05) incorpora los grupos de empresas del CRM (matriz y filiales) a la API externa de clientes:
- El tipo
ExternalClientincluyeparentClientId(escalar, presente en todas las respuestas) yparent { id, name, slug }(solo en el detalle). - Nuevo método
sdk.externalClients.getGroup(id)/sdk.external_clients.get_group(client_id): rol del cliente en su grupo (PARENT/SUBSIDIARY/STANDALONE), referencia a la matriz y lista de filiales. Requiere el scopecrm:clients:read. updateaceptaparentClientIdpara vincular una filial a su matriz o desvincularla (nullen JavaScript;Noneexplícito en Python). Requiere el sub-scope nuevocrm:clients:write:hierarchyademás decrm:clients:write.- Webhooks nuevos
CLIENT_LINKED_TO_GROUPyCLIENT_UNLINKED_FROM_GROUP(payload de solo identificadores). - El espejo del catálogo de scopes pasa a 36 entradas con
crm:clients:write:hierarchy.
La 2.17.0 (2026-07-02) añadió sdk.mcp.opportunities.listStages() / list_stages() para las etapas de oportunidad configurables por organización.
Cambios aditivos, sin breaking changes. Detalle completo en Endpoints de clientes del CRM.
Novedades de la versión 2.16.0, y por qué quedó rota
La 2.16.0 (5 de junio de 2026) añadió sdk.subscriptions y sdk.mandates
envolviendo rutas internas de /finance/*, no la API externa.
Esas rutas exigen la sesión de un usuario del panel, que el SDK no sabe obtener: con clave de API devolvían 401 y con OAuth también, porque el token OAuth es opaco y solo se resuelve en el carril MCP. Hasta el 4 de agosto de 2026 esta página y los comentarios del SDK decían que bastaba con OAuth, y era falso.
Se arregló en la 3.0.0, que reescribe esos servicios sobre /external/v1/*
con la clave de API. Si tu código quedó escrito contra la 2.16.0, revisa la
tabla de rupturas de arriba: las firmas cambian.
Hitos por versión
Resumen de las versiones más relevantes de ambos SDK, de la rama 1.x a la actual. La numeración es compartida entre JavaScript y Python.
| Versión | Fecha | Aportación principal |
|---|---|---|
| 4.1.0 | 2026-09-12 | Calendario laboral por MCP: sdk.mcp.attendance.holidays consulta y fija el ámbito de festivos de la empresa, carga el calendario oficial de un año y lista los festivos que cuentan. Sin cambios incompatibles. |
| 4.0.1 | 2026-09-09 | Solo documentación interna del paquete y número de versión del paquete de Python alineado. Sin cambios de comportamiento ni de firma. |
| 4.0.0 | 2026-09-07 | Disposición de cobro con tarjeta: sdk.paymentMethods.getReadiness() (payment_methods.get_readiness() en Python) responde si la organización puede cobrar ahora mismo y por qué no. Versión mayor por una retirada en un servicio no disponible para las organizaciones cliente. |
| 3.1.0 | 2026-09-05 | Honestidad de la medición y fiabilidad del envío en Marketing por correo: 39 métodos nuevos y dos sub-espacios nuevos, sin cambios incompatibles. Aviso: marketing:write deja de enviar por sí solo. |
| 3.0.0 | 2026-09-05 | Facturación y cobro de aplicaciones externas: sdk.subscriptions y sdk.invoices.scheduledCharges funcionan de verdad sobre /external/v1/*, sdk.paymentAuthorizations es nuevo, sdk.invoices gana send, charge, markPaid y el enlace público, y sdk.webhooks verifica cualquier familia de avisos. Versión MAYOR: ver la tabla de rupturas. Catálogo de permisos: 56. |
| 2.27.0 | 2026-09-04 | CRM completo por MCP: servicio sdk.mcp.crm, con lotes y fusión de duplicados. |
| 2.26.0 | 2026-09-02 | Buscador global y avisos por MCP (sdk.mcp.search, sdk.mcp.notifications). |
| 2.23.0 | 2026-08-05 | Medición y atribución de Marketing: marketing_campaigns, marketing_lists y marketing_deliverability completas; comportamiento de la audiencia, segundos intentos, interés de suscriptores, quejas por correo no deseado, mapa de calor por enlace y desglose por aparato, programa y país. |
| 2.22.0 | 2026-08-03 | Imágenes de presupuesto completas: uploadImageToSection, scanLegacyImages y migrateLegacyImages. Quedan obsoletos textWrap y la opción deleteFile. |
| 2.21.0 | 2026-07-28 | Permisos recortados por el plan en getAuthorizedApps(): permissions, permissionCount, unavailablePermissionCount y unavailableModules. AuthorizedApp.scope queda obsoleto y cambia de significado. |
| 2.20.0 | 2026-07-12 | Plataforma de chat extensible (sdk.chat): publicar (sendMessage, v1) y leer canales, miembros e historial visible (listChannels/getChannel/listMembers/listMessages/getMessage, v2), más sdk.chat.webhooks.verify() para validar localmente la firma HMAC de los webhooks de chat. Catálogo de scopes: 40 (Chat pasa de 1 a 4 con chat:channels:view, chat:messages:view y chat:events:subscribe). |
| 2.18.0 | 2026-07-05 | Grupos de empresas: parentClientId/parent en ExternalClient, getGroup, vínculo vía update con el sub-scope crm:clients:write:hierarchy y webhooks CLIENT_LINKED_TO_GROUP / CLIENT_UNLINKED_FROM_GROUP. Catálogo de scopes: 36. |
| 2.17.0 | 2026-07-02 | Etapas de oportunidad configurables: sdk.mcp.opportunities.listStages(). |
| 2.16.0 | 2026-06-05 | Paridad de suscripciones (sdk.subscriptions) y mandatos (sdk.mandates). |
| 2.15.1 | 2026-05-25 | Ajuste del catálogo de scopes externos: se retira fm:files:delete y se añaden 7 scopes (presupuestos, analítica de IA, telemetría de errores). Catálogo resultante en esa versión: 35 scopes. |
| 2.15.0 | 2026-05-25 | Catálogo público de scopes de la API externa como tipos TypeScript / modelos, espejo 1:1 del backend. |
| 2.13.0 | 2026-05-24 | Servicios sdk.externalLeads y sdk.externalClients (/external/v1/leads y /external/v1/clients). |
| 2.12.1 | 2026-05-21 | Servicio sdk.externalContacts (/external/v1/contacts), pensado para aplicaciones de envío de correo. |
| 2.10.0 | 2026-05-14 | Servicio MCP tipado sdk.mcp.opportunities (refleja la tool crm_opportunities_stats). |
| 2.9.0 | 2026-05-12 | Tool MCP de tickets y ampliaciones del árbol sdk.mcp.*. |
| 2.8.0 | 2026-05-12 | Módulo sdk.mcp.*: integraciones, credenciales de API, ajustes de integraciones de la organización y vista de resumen. |
| 1.8.0 | 2026-04-08 | Parámetro theme ('light' / 'dark') en la pantalla de consentimiento OAuth (en Python, 0.7.0). |
Los dos SDK admiten OAuth 2.1 con PKCE como alternativa a la clave de la aplicación. El parámetro theme para elegir tema claro u oscuro en la pantalla de consentimiento llegó en las versiones 1.8.0 (JavaScript) y 0.7.0 (Python). Ver OAuth con el SDK.
Catálogo de scopes de la API externa
El catálogo de scopes que una ExternalApp puede tener concedidos se expone en el endpoint:
/api/integrations/apps/scopes/catalogLa fuente de verdad es la lista EXTERNAL_API_SCOPES_LIST del backend. A día de hoy contiene 56 permisos. Las cifras que aparecen en la tabla de hitos (35, 36, 40, 45) son el tamaño del catálogo en aquella versión, no el de hoy. El conteo canónico y su desglose viven en Catálogo de scopes: los 56 de la API externa:
| Dominio | Permisos |
|---|---|
| Contactos | 6 |
| Leads | 5 |
| Clientes | 5 |
| Usuarios externos | 2 |
| Facturación | 5 |
| Cobros con tarjeta | 4 |
| Suscripciones | 3 |
| Autorizaciones de cobro | 3 |
| Cobros programados | 2 |
| Soporte | 3 |
| Ficheros | 2 |
| Presupuestos | 4 |
| Analítica y telemetría | 3 |
| Chat | 9 |
| Total | 56 |
El cuarto scope del dominio Clientes es crm:clients:write:hierarchy (2.18.0): gestiona el vínculo matriz-filial de los grupos de empresas y se concede por separado del write genérico. El dominio Chat aporta nueve scopes con la plataforma de chat extensible: chat:messages:send (v1, publicar); chat:channels:view, chat:messages:view y chat:events:subscribe (v2: leer canales y mensajes, y recibir webhooks); chat:channels:create, chat:channels:manage y chat:members:manage (v3: crear, editar y archivar canales y gestionar sus miembros); y chat:agents:view y chat:agents:manage:external (v4: gestión de agentes de IA por apps). De todos ellos, solo chat:agents:manage:external exige SUPER_ADMIN y queda fuera de todo paquete.
Los scopes de gobierno del canal (v3) tienen ya sus métodos en sdk.chat: createChannel, updateChannel, archiveChannel, addMember y removeMember (en Python, en snake_case). La gestión de agentes de IA de la v4 (sdk.chat.agents) se documenta en Gestionar agentes de IA.
De esos 56 permisos, 14 solo puede concederlos un Super Administrador, con un motivo razonado de al menos veinte caracteres. Ocho lo son por datos personales críticos (contactos en derecho de oposición, notas internas de contactos, leads y clientes, conversión de leads, datos fiscales, envío de datos de tickets a proveedores de IA y verificación de firmas), uno por permitir que una aplicación gestione agentes de IA (chat:agents:manage:external) y cinco por ser críticos financieros: billing:charge, billing:refund, billing:subscriptions:cancel, billing:payment-authorizations:write y crm:invoices:cancel.
La categoría de críticos financieros es nueva en la 3.0.0. Existe porque quien revisa la solicitud de una aplicación necesita saber por qué un permiso está blindado: no es lo mismo «leerá notas sobre personas» que «podrá cobrar y devolver dinero de tus clientes».
Cambio de catálogo en la 2.15.1. El scope fm:files:delete se retiró del catálogo porque ningún endpoint de la API externa lo aplicaba (no existe DELETE /external/v1/files/:id), de modo que concederlo generaba una falsa sensación de seguridad. Las aplicaciones que ya lo tuvieran concedido seguirán mostrándolo hasta que el operador lo retire desde el panel, pero nunca habilitó ninguna operación real. Volverá al catálogo cuando se exponga el endpoint correspondiente.
Política de compatibilidad
La API externa es estable en v1
Todos los endpoints de la API externa viven bajo
/external/v1. Mientras tu integración consuma esa versión, los contratos publicados se mantienen. Las novedades se añaden de forma aditiva.Los SDK siguen versionado semántico
La rama actual de ambos SDK es la 4.x. Los cambios menores (segundo número) añaden funcionalidad de forma compatible; los de parche (tercer número) corrigen o ajustan sin romper. Fija una versión mínima conocida y revisa el changelog antes de subir de versión menor.
Las retiradas se anuncian con antelación
Los métodos que se van a eliminar se marcan primero como
@deprecatedy se mantienen durante una ventana de coexistencia antes de desaparecer en una versión mayor. Por ejemplo,generateSigningLinkquedó obsoleto en favor deforceSendSignature: hoy lanza siempre un error que remite al método nuevo y se conserva solo para que el código antiguo compile.Mantén SDK y backend alineados
Algunas funcionalidades nuevas del SDK dependen de endpoints que deben existir en tu instancia de UTILIA OS. Si llamas a un método nuevo contra un backend más antiguo, recibirás un error de endpoint no encontrado. Actualiza ambos lados de forma coordinada.