Soluciones en la API de Codenica

Empiece a trabajar con las soluciones mediante la API de Codenica creando una clave en los ajustes de Codenica. Si todavía no tiene una clave, abra en una pestaña nueva el artículo API de Codenica - introducción. Allí se explican las reglas comunes para emitir claves, guardar el secreto y autenticar las solicitudes.

El nombre técnico del módulo es solutions y el tipo de cada objeto es solution. Una solución es una entrada de la base de conocimientos. Puede contener instrucciones, una descripción del procedimiento, referencias y archivos de apoyo. No es un objeto de flujo de trabajo como una Incidencia, un Cambio, un Problema o una Versión. Por eso, no copie en una solución sus campos de estado, prioridad o escalado.

En las secciones siguientes encontrará la dirección, los scopes, el contexto, el esquema, los campos, las listas, los filtros, la creación, la idempotencia, el ETag, la edición, las operaciones por lotes, las relaciones con Problemas, los datos del autor y del editor, los archivos, las valoraciones y la eliminación.

Los ejemplos utilizan el prefijo PUBLIC-API-SOLUTION-20260905134845. Sustitúyalo en su integración por un identificador propio y adapte las direcciones de correo, los identificadores y los valores de los campos a los datos de su base de datos.


Soluciones - dirección de la API y tipo de instalación

Todas las rutas de Soluciones comienzan por:

{BASE_URL}/api/v1/solutions

BASE_URL es la dirección del servidor Codenica sin el tramo final /api/v1. En Codenica Cloud, utilice el dominio público asignado a la empresa correspondiente:

export BASE_URL="https://su-empresa.codenica.com"

En una instalación On-Premise predeterminada, Codenica Discovery registra localmente esta dirección:

export BASE_URL="http://codenica.local:5150"

Si el administrador ha publicado la instalación bajo un dominio de la empresa, mediante un proxy inverso, con HTTPS o en otro puerto, utilice exactamente la dirección que le haya proporcionado:

export BASE_URL="https://api.su-empresa.example"

No utilice localhost si el programa que integra la API se ejecuta en un equipo distinto. La base de datos correcta se selecciona a partir de la dirección utilizada por la integración. No envíe tenantId en el body ni en la cadena de consulta.


Soluciones - clave de API y límites de licencia

Cree una clave de API en Codenica desde Ajustes - API - API Keys. El secreto se muestra una sola vez, inmediatamente después de crear o rotar la clave. En ese momento, guarde Client ID y Client Secret en el almacenamiento seguro que utilice la integración.

La API de Codenica está disponible con las licencias Plus y Enterprise. Plus permite hasta 50 claves activas y Enterprise hasta 100. Starter no incluye la API de Codenica. Cree una clave independiente para cada aplicación y entorno, de modo que pueda administrar sus scopes, rotar el secreto o retirar el acceso sin afectar a las demás integraciones.

Licencia
Acceso a la API
Máximo de claves activas
Starter
No disponible
0
Plus
Disponible
50
Enterprise
Disponible
100

Al eliminar una clave, se borra su registro y se libera un lugar dentro del límite. Cuando pasa la fecha de caducidad, la clave deja de autenticar solicitudes, pero permanece en la lista hasta que se elimina. Si no establece una fecha final al crearla, la validez predeterminada es de 90 días. La validez máxima de una clave es de 5 años.


Soluciones - autenticación y solicitudes seguras

Autentique cada solicitud de la API de Codenica con las dos cabeceras de la clave:

export CLIENT_ID="cna_su_client_id"
export CLIENT_SECRET="cns_su_client_secret"

curl --request GET --url "$BASE_URL/api/v1/solutions?page=1&pageSize=25" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Una integración externa no necesita el JWT del administrador ni las cookies del panel de Codenica. No incluya la clave en un repositorio, en código enviado al navegador, en una URL, en el historial del shell ni en los registros. Fuera de las pruebas locales, utilice HTTPS.

Conserve meta.requestId de la respuesta. Sirve para localizar una solicitud concreta durante el diagnóstico, pero no sustituye al identificador de la solución y no debe tratarse como un secreto.


Soluciones - comprobación del contexto de conexión

Antes de realizar la primera escritura, lea el contexto. Así podrá comprobar que la dirección apunta a la base de datos correcta y que la clave elegida tiene los scopes necesarios:

curl --request GET --url "$BASE_URL/api/v1/context" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Compruebe en la respuesta:

  • data.apiVersion y data.contractVersion;
  • data.tenant.id, data.tenant.name y data.tenant.resolvedDomain;
  • data.caller.authentication con el valor api_key;
  • la presencia de solutions en data.capabilities.resources;
  • los scopes asignados a la clave;
  • los límites de páginas, operaciones por lotes, archivos y solicitudes.

Si el contexto apunta a otra base de datos o no incluye un scope necesario, detenga la integración y corrija la dirección o la clave. Los scopes no se pueden añadir a una solicitud individual.


Soluciones - scopes y permisos

La gestión completa de Soluciones requiere scopes que correspondan a las operaciones que utilizará la integración:

solutions:read
solutions:write
solutions:delete
solutions:schema
solutions:stats
solutions:relationships:read
solutions:relationships:write
solutions:users:read
solutions:files:read
solutions:files:write
solutions:technical:read
solutions:technical:write
solutions:rating:write
problems:read
users:read

Para las lecturas habituales basta con solutions:read. El esquema y las estadísticas requieren los scopes independientes solutions:schema y solutions:stats. Para leer relaciones, autores, editores y archivos se necesitan los scopes de lectura correspondientes. Las operaciones de escritura utilizan los scopes equivalentes con :write.

  • solutions:relationships:read y solutions:relationships:write cubren las relaciones de objetos con Problemas;
  • solutions:users:read y users:read cubren los datos de autores y editores, según la configuración;
  • solutions:files:read y solutions:files:write cubren la consulta, la subida, la asociación y la eliminación de archivos;
  • solutions:rating:write es necesario para enviar o retirar su propia valoración;
  • utilice los scopes técnicos únicamente cuando la integración necesite campos marcados como técnicos en el esquema.

El scope problems:read es necesario cuando la integración busca un Problema que utilizará como objetivo de una relación. El módulo de Soluciones no crea ni elimina ese Problema. Conceda únicamente los scopes que la integración necesite.


Soluciones - esquema y campos

El esquema muestra qué campos se pueden leer y escribir en la base de datos seleccionada. Consúltelo antes de crear un formulario o un mapeo de campos:

curl --request GET --url "$BASE_URL/api/v1/solutions/schema" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

La respuesta incluye, entre otros datos, data.itemType, data.fields y data.relationshipTargets. El itemType fijo de este módulo es solution. Para cada campo, compruebe readable, writable, required, technical, unique y maxLength. No construya el mapeo únicamente a partir de los ejemplos de este artículo.


Soluciones - campos editables y campos del sistema

Al crear un registro debe proporcionar title y category. El catálogo público de campos de negocio incluye:

customId
title
description
location
department
type
tags
section
category
visibility

Longitudes máximas definidas por el esquema público:

Campo
Longitud máxima
customId
500
title
1000
description
10000
location
300
department
300
type
300
tags
2000
section
300
category
300
visibility
100

Los siguientes valores son de solo lectura y no deben incluirse en un body normal de PATCH:

helpful
notHelpful
totalFiles
creator
updater
importId
importSource
dateImported

id y itemType forman parte de la envoltura del recurso. dateCreated y dateUpdated son datos del sistema. No intente modificarlos mediante attributes.


Soluciones - endpoints principales

Las rutas principales del módulo solutions son:

GET    /api/v1/solutions
POST   /api/v1/solutions
GET    /api/v1/solutions/{SOLUTION_ID}
PATCH  /api/v1/solutions/{SOLUTION_ID}
DELETE /api/v1/solutions/{SOLUTION_ID}
GET    /api/v1/solutions/schema
GET    /api/v1/solutions/stats
GET    /api/v1/solutions/values
GET    /api/v1/solutions/{SOLUTION_ID}/relationships
POST   /api/v1/solutions/{SOLUTION_ID}/relationships
POST   /api/v1/solutions/{SOLUTION_ID}/relationships:batch
GET    /api/v1/solutions/{SOLUTION_ID}/user-relationships
GET    /api/v1/solutions/{SOLUTION_ID}/files
POST   /api/v1/solutions/{SOLUTION_ID}/files
GET    /api/v1/solutions/{SOLUTION_ID}/files/{FILE_ID}/content
POST   /api/v1/solutions/{SOLUTION_ID}/rating

Todas las rutas requieren autenticación. Las operaciones que modifican datos también requieren Idempotency-Key, mientras que las operaciones protegidas por versión requieren el If-Match actual. Consulte el esquema y la respuesta del contexto para conocer los requisitos exactos de la operación que va a realizar.


Soluciones - listas y paginación

La lista se devuelve por páginas. El siguiente ejemplo obtiene la primera página y ordena las soluciones por título:

curl --request GET --url "$BASE_URL/api/v1/solutions?itemType=solution&page=1&pageSize=25&sort=title&direction=asc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

La respuesta incluye, entre otros valores:

data.items
data.page
data.pageSize
data.totalItems
data.totalPages
data.hasNextPage

Solicite las páginas siguientes mientras data.hasNextPage sea true. No suponga que el número de registros de la primera página representa la lista completa. Ajuste pageSize al límite devuelto por el contexto en lugar de solicitar siempre el máximo.


Soluciones - búsqueda, filtros y ordenación

Puede filtrar, entre otros campos, por ids, customId, title, description, location, department, type, tags, section, category, visibility, helpful, notHelpful, createdAfter, createdBefore, updatedAfter y updatedBefore. Codifique en la URL los valores que contengan espacios, comas o caracteres especiales.

Ejemplo: listar las soluciones de la categoría Public API:

curl --request GET --url "$BASE_URL/api/v1/solutions?category=Public%20API&page=1&pageSize=25&sort=title&direction=asc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

El parámetro search busca en los datos textuales de la solución, incluidos el título, la descripción, el tipo, las etiquetas, la sección, la categoría, la visibilidad, la ubicación y el departamento:

curl --request GET --url "$BASE_URL/api/v1/solutions?search=backup&page=1&pageSize=25" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Ordene únicamente por un campo que exponga el esquema. No suponga que todos los campos visibles en el formulario se pueden utilizar como parámetro sort.


Soluciones - proyección de campos y datos incluidos

Si la integración necesita solo una parte del registro, limite la respuesta mediante fields:

curl --request GET --url "$BASE_URL/api/v1/solutions?customId=PUBLIC-API-SOLUTION-20260905134845-SOURCE&fields=title%2Ccategory%2Cvisibility&page=1&pageSize=10" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Puede obtener un registro junto con sus archivos, relaciones y datos del autor o del editor:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}?fields=title%2Ccategory%2Cdescription%2Cvisibility&include=files%2Crelationships%2Cusers" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Los valores permitidos para include son files, relationships y users. Cada uno requiere el scope correspondiente. fields=* solicita todos los campos disponibles, pero los campos técnicos solo aparecen cuando se concede el scope técnico adecuado.


Soluciones - estadísticas y valores de campos

Utilice las estadísticas para contar registros y agruparlos por un campo:

curl --request GET --url "$BASE_URL/api/v1/solutions/stats?field=category&limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

La respuesta incluye, entre otros datos, total, field y una matriz values. El valor category=Public API puede servir como filtro práctico para los datos de demostración.

Para obtener los valores distintos de un campo, utilice la ruta values:

curl --request GET --url "$BASE_URL/api/v1/solutions/values?field=visibility&search=internal&limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

limit debe estar dentro del intervalo admitido por la API. El intervalo actual para estos endpoints es de 1 a 500. Las solicitudes de estadísticas y valores son de solo lectura y no modifican las soluciones.


Soluciones - crear un registro

Al crear un registro, incluya el tipo técnico solution en el body y los campos editables dentro de attributes. El payload mínimo requiere title y category:

{
  "itemType": "solution",
  "attributes": {
    "customId": "PUBLIC-API-SOLUTION-20260905134845-SOURCE",
    "title": "PUBLIC-API-SOLUTION-20260905134845 integration knowledge article",
    "description": "Created through the Codenica Public API Solutions flow.",
    "location": "Warsaw",
    "department": "IT",
    "type": "How-to",
    "tags": "public-api,solution,integration",
    "section": "Integrations",
    "category": "Public API",
    "visibility": "team"
  }
}

Guarde el contenido como solution-create.json y envíelo:

curl --request POST --url "$BASE_URL/api/v1/solutions" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-solution-create-20260905134845" \
  --data-binary @solution-create.json

Una creación correcta devuelve 201 Created. La respuesta contiene el UUID de la solución, data.itemType=solution, los atributos guardados, las fechas del sistema y data.meta.etag. En la mayoría de las integraciones, deje que el sistema asigne el id.


Soluciones - repetir la creación de forma segura

Si el resultado de una solicitud es incierto, repita exactamente el mismo payload con la misma Idempotency-Key. Así evitará que la integración cree una segunda solución:

curl --request POST --url "$BASE_URL/api/v1/solutions" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-solution-create-20260905134845" \
  --data-binary @solution-create.json

Utilice la misma clave únicamente para la misma intención y el mismo body. Genere una clave nueva para una nueva solución o un nuevo payload. Después de un timeout, no cambie la clave antes de comprobar si la primera escritura terminó en el servidor.


Soluciones - leer un registro y su ETag

Después de crear o localizar una solución, obtenga el registro individual y guarde el ETag devuelto en la cabecera HTTP y en data.meta.etag:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}?fields=title%2Ccategory%2Cdescription%2Cvisibility%2Ctags" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Una respuesta correcta devuelve 200 OK y una cabecera ETag:

ETag: "..."
data.meta.etag: "..."
meta.etag: "..."

Utilice el valor actual para la siguiente actualización, modificación de relación, operación de archivo, valoración o eliminación. El ETag representa la versión de toda la solución, por lo que un cambio en sus atributos, relaciones o archivos puede invalidar el valor anterior.


Soluciones - actualización parcial con If-Match

Actualice únicamente los campos que deban cambiar. La siguiente solicitud modifica la descripción y la visibilidad:

{
  "attributes": {
    "description": "Updated through the Solutions Public API flow.",
    "visibility": "internal",
    "tags": "public-api,solution,updated",
    "section": "Updated integrations"
  }
}
curl --request PATCH --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-update-20260905134845" \
  --data-binary @solution-update.json

Una actualización correcta devuelve 200 OK, el UUID sin cambios y un ETag nuevo tanto en la cabecera de respuesta como en los metadatos. Guarde el nuevo valor antes de realizar otra mutación.


Soluciones - ETag obsoleto y ausencia de If-Match

La API evita que una solución sobrescriba una versión más reciente. Un ETag antiguo se rechaza:

Si dos procesos leen la misma solución y uno guarda primero, el segundo tiene un ETag obsoleto. El intento de escribir con ese valor se rechaza:

HTTP 412 Precondition Failed
code: if_match_failed

Después de HTTP 412, vuelva a leer el registro, decida cómo combinar los cambios y envíe solo entonces un nuevo PATCH. Una solicitud rechazada por un ETag obsoleto no debe modificar los datos.

Una mutación sin la cabecera requerida devuelve:

HTTP 428 Precondition Required
code: if_match_required

No intente eludir este requisito enviando un valor vacío. Lea primero el registro actual y utilice su ETag exacto.


Soluciones - operaciones por lotes

Utilice POST /api/v1/solutions:batch cuando deba crear, actualizar o eliminar varias soluciones en un único conjunto enviado. Cada elemento declara su operación:

{
  "items": [
    {
      "operation": "create",
      "create": {
        "itemType": "solution",
        "attributes": {
          "customId": "PUBLIC-API-SOLUTION-BATCH-A",
          "title": "Batch Solution A",
          "category": "Public API",
          "description": "Batch-created Solution A",
          "type": "How-to",
          "visibility": "team"
        }
      }
    },
    {
      "operation": "create",
      "create": {
        "itemType": "solution",
        "attributes": {
          "customId": "PUBLIC-API-SOLUTION-BATCH-B",
          "title": "Batch Solution B",
          "category": "Public API",
          "description": "Batch-created Solution B",
          "type": "Reference",
          "visibility": "team"
        }
      }
    }
  ]
}
curl --request POST --url "$BASE_URL/api/v1/solutions:batch" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-solution-batch-create-20260905134845" \
  --data-binary @solutions-batch.json

Para una actualización, el elemento contiene operation=update, id, ifMatch y update.attributes:

{
  "items": [
    {
      "operation": "update",
      "id": "{SOLUTION_A_ID}",
      "ifMatch": "{SOLUTION_A_ETAG}",
      "update": {
        "attributes": {
          "description": "Batch update A"
        }
      }
    }
  ]
}

Para una eliminación, el elemento contiene operation=delete, id y el ifMatch actual. La respuesta puede incluir succeeded y failed. Un resultado parcial también puede utilizar HTTP 207 Multi-Status. Compruebe cada elemento por separado. Un batch no es una transacción.


Soluciones - relaciones únicamente con Problemas

Las Soluciones admiten relaciones de objetos únicamente con el módulo Problemas. Un objetivo habitual devuelto por el esquema es:

targetDataSet: problems
targetItemType: problem

No suponga que una solución se puede conectar mediante estos endpoints con un Recurso, un Documento, un Cliente, un Proveedor, una Incidencia, un Cambio o una Versión. Si el esquema de una base de datos concreta no devuelve el objetivo, la integración no debe utilizarlo.

Primero busque un Problema que se pueda leer mediante un campo de ordenación público:

curl --request GET --url "$BASE_URL/api/v1/problems?itemType=problem&page=1&pageSize=10&sort=subject&direction=asc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

En el flujo de demostración se utilizó el Problema con el identificador 9793181f-a225-4928-8062-80d6e69cb792. Su integración debe buscar el objetivo actual y no tratar este UUID como una constante.


Soluciones - añadir, leer y eliminar relaciones

El body para añadir directamente una relación puede tener este formato:

{
  "targetId": "9793181f-a225-4928-8062-80d6e69cb792",
  "targetDataSet": "problems",
  "targetItemType": "problem",
  "relationshipType": "related"
}

Antes de cada mutación, obtenga el ETag actual de la solución:

curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/relationships" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-problem-relation-add-20260905135119" \
  --data-binary @solution-problem-relation.json

Una adición correcta devuelve 201 Created. Lea la relación mediante una ruta independiente:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/relationships?targetDataSet=problems&targetItemType=problem&page=1&pageSize=50" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

La eliminación directa requiere el ETag actual y el identificador del objetivo:

curl --request DELETE --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/relationships/problems/9793181f-a225-4928-8062-80d6e69cb792?relationshipType=related" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-problem-relation-delete-20260905135119"

La respuesta de eliminación devuelve 200 y data=true. Después de la operación, vuelva a leer la colección.


Soluciones - relaciones por lotes con Problemas

Para añadir y eliminar relaciones al mismo tiempo, utilice la ruta relationships:batch:

{
  "add": [
    {
      "targetId": "9793181f-a225-4928-8062-80d6e69cb792",
      "targetDataSet": "problems",
      "targetItemType": "problem",
      "relationshipType": "related"
    }
  ],
  "remove": []
}
curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/relationships:batch" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-problem-relation-batch-add-20260905135119" \
  --data-binary @solution-problem-relation-batch.json

Para eliminar una relación mediante un batch, deje add vacío y coloque el elemento en remove:

{
  "add": [],
  "remove": [
    {
      "targetId": "9793181f-a225-4928-8062-80d6e69cb792",
      "targetDataSet": "problems",
      "targetItemType": "problem",
      "relationshipType": "related"
    }
  ]
}

La respuesta contiene los contadores added, removed y skipped. Después de añadir, compruebe added=1 y después de eliminar, removed=1. Antes de cada nueva escritura, utilice un ETag reciente.


Soluciones - relaciones de autores y editores

En este módulo, las relaciones de usuarios son metadatos sobre la autoría y la última edición. Los tipos permitidos son author y editor:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/user-relationships?page=1&pageSize=50" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Un elemento de ejemplo puede contener:

{
  "targetId": "8e9cbff3-340f-41f6-97ec-6997bb915829",
  "targetDataSet": "users",
  "relationshipType": "author",
  "displayName": "Fred Savage",
  "email": "[email protected]",
  "role": "Administrator"
}

Las relaciones author y editor se leen de los campos de autor y editor de la solución. El módulo público de Soluciones no ofrece endpoints para añadirlas, modificarlas o eliminarlas. No intente crear los tipos agent, watcher, appUserRequester o clientRequester, ya que pertenecen a otros objetos.


Soluciones - archivos

Antes de cualquier operación de archivos, lea la solución actual y su ETag. Lista de archivos:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/files?page=1&pageSize=100" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Cada elemento de la lista incluye, entre otros datos, id, name, fileName, contentType, size, width, height, relationshipType, isMain y downloadUrl. En Soluciones, isMain siempre es false. El módulo no ofrece un endpoint set-main, por lo que no debe intentar establecer un archivo principal.

El envío de un archivo requiere el formato multipart/form-data:

curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/files?relationshipType=documentation" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-file-20260905134845" \
  --form "[email protected];type=text/plain"

Una subida correcta devuelve 201 Created y el recurso del archivo. En el ejemplo se utiliza solution-one.txt con el tipo text/plain. La subida cambia la versión de la solución, así que después debe obtener un ETag nuevo.

Descargue el contenido mediante una ruta autenticada:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/files/{FILE_ID}/content" \
  --header "Accept: application/octet-stream" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --output solution-one-downloaded.txt

Trate downloadUrl como una ruta de la API, no como un enlace público anónimo. Si el archivo ya existe en el mismo espacio de archivos, puede asociarlo a otra solución:

curl --request POST --url "$BASE_URL/api/v1/solutions/{TARGET_SOLUTION_ID}/files/{FILE_ID}?relationshipType=manual" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $TARGET_CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-file-attach-20260905134845"

Al asociarlo, utilice el ETag de la solución de destino, no el del registro del que procede el archivo. Para eliminar un archivo se requiere el ETag actual:

curl --request DELETE --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/files/{FILE_ID}" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-file-delete-20260905134845"

Después de recibir 200, vuelva a leer la lista de archivos para confirmar que el archivo ya no se devuelve.


Soluciones - valoración de utilidad

La valoración es una mutación independiente. Puede marcar una solución como útil, como no útil o retirar su propia valoración:

{
  "rating": 1
}
  • 1 - útil;
  • 0 - no útil;
  • -1 - retirar su propia valoración.

Marcar como útil:

curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/rating" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-rating-helpful-20260905134845" \
  --data '{"rating":1}'

Retirar su propia valoración:

curl --request POST --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}/rating" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $RATING_CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-rating-reset-20260905134845" \
  --data '{"rating":-1}'

Ambas operaciones requieren un ETag. La respuesta contiene los contadores actuales helpful y notHelpful y un ETag nuevo. No actualice helpful ni notHelpful mediante un PATCH normal.


Soluciones - eliminar un registro

La eliminación no se puede deshacer. Por eso, lea primero el registro y obtenga el ETag actual:

curl --request DELETE --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $CURRENT_ETAG" \
  --header "Idempotency-Key: public-api-solution-delete-20260905134845"

La respuesta correcta es 200 con data=true. Después, realice un GET de comprobación y consulte una lista filtrada:

curl --request GET --url "$BASE_URL/api/v1/solutions/{SOLUTION_ID}" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

curl --request GET --url "$BASE_URL/api/v1/solutions?customId=PUBLIC-API-SOLUTION-20260905134845-SOURCE&page=1&pageSize=10" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Después de eliminarlo, el GET individual devuelve 404 Not Found con el código solution_not_found. La lista filtrada por customId debe tener totalItems=0. Conviene comprobar o limpiar antes las relaciones y los archivos mediante la integración.


Soluciones - errores, límites y seguridad

Los errores de la API utilizan el formato Problem Details. Los campos principales son status, code, detail y requestId:

{
  "type": "https://docs.codenica.com/errors/if_match_failed",
  "title": "Precondition failed.",
  "status": 412,
  "detail": "The supplied ETag is not the current solution version.",
  "instance": "/api/v1/solutions/{SOLUTION_ID}",
  "code": "if_match_failed",
  "requestId": "..."
}
HTTP
Significado
Respuesta
400
campo, filtro, body o relación no válidos
corrige la solicitud según el esquema
401
falta autenticación o no es válida
comprueba la dirección y la clave
403
falta un scope o el acceso a la base de datos
corrige el scope o los permisos del usuario
404
la solución, el problema, el archivo o el objetivo de la relación no existe o no es visible
comprueba el UUID y la dirección de la instalación
409
conflicto de identificador o de una relación existente
lee el estado y decide si el conflicto es esperado
412
el ETag ya no es actual
obtén el registro y un ETag nuevo
413
el archivo o el body son demasiado grandes
comprueba el límite en context
422
el valor del campo o el flujo existente rechaza la operación
analiza code y detail
428
falta If-Match o Idempotency-Key
añade la cabecera correspondiente
429
se ha superado el límite de solicitudes
aplica backoff y Retry-After
500
error del servidor
guarda requestId y no repitas mutaciones sin idempotencia

Lea las cabeceras X-RateLimit-Limit y X-RateLimit-Remaining. Después de un 429, respete Retry-After cuando se devuelva y aplique reintentos controlados con un retraso cada vez mayor.

Las soluciones pueden contener información operativa e instrucciones internas. Reduzca la selección de campos, utilice HTTPS y limite la clave a la base de datos concreta. Guarde Client ID y Client Secret fuera del código fuente, no los escriba en los registros ni los envíe en incidencias.


Soluciones - orden recomendado para la integración

  1. Determine la dirección real de Cloud u On-Premise y establezca BASE_URL.
  2. Cree una clave independiente para la aplicación y el entorno desde Ajustes - API - API Keys.
  3. Conceda únicamente los scopes necesarios para leer, escribir, gestionar relaciones, archivos o valoraciones.
  4. Envíe GET /api/v1/context y compruebe la base de datos, el caller, los scopes y los límites.
  5. Obtenga GET /api/v1/solutions/schema y cree el mapeo de campos.
  6. Obtenga la lista o busque una solución existente.
  7. Cree el registro mediante POST con un Idempotency-Key único.
  8. Guarde el UUID y el ETag de la respuesta.
  9. Actualice el ETag antes de cada modificación, relación, operación de archivos, valoración o eliminación.
  10. Cree relaciones de objetos únicamente con un Problema devuelto por el esquema.
  11. Lea las relaciones de autores y editores, ya que no tienen endpoints públicos de escritura.
  12. Después de cada mutación, lea el resultado y guarde el ETag nuevo.
  13. Ante un 412, vuelva a leer el registro, resuelva el conflicto y solo después repita la operación.
  14. En las operaciones por lotes, compruebe cada resultado porque un error parcial no revierte los elementos que sí tuvieron éxito.
  15. Antes de eliminar, confirme el ETag actual y después compruebe el HTTP 404 y una lista vacía filtrada por customId.

Este flujo permite sincronizar las soluciones de la base de conocimientos con otro sistema sin basar la integración en suposiciones sobre campos, relaciones o datos del sistema.