Problemas en Codenica API

Para trabajar con problemas mediante Codenica API, empieza por crear una clave en los ajustes de Codenica. Si todavía no has creado una clave, abre en una pestaña nueva Codenica API - introducción. Allí encontrarás las reglas comunes para emitir claves, guardar el secreto y autenticar las solicitudes.

El nombre técnico del módulo es problems y el tipo de un objeto individual es problem. Un problema sirve para registrar la causa o el origen de incidentes recurrentes. Además de los datos descriptivos, cuenta con los campos de diagnóstico isKnown, symptoms, rootCause e impactInfo.

En las secciones siguientes encontrarás la dirección, los scopes, el esquema, las listas, los filtros, la creación, la edición, ETag, las operaciones batch, las relaciones, los usuarios, los archivos, las acciones de flujo de trabajo, el escalado, la aprobación y la eliminación de problemas.

Los ejemplos utilizan el prefijo PUBLIC-API-PROBLEM-20260905131727. En tu integración, sustitúyelo por tu propio identificador y adapta las direcciones de correo, los identificadores y los valores de los campos a los datos de tu base.


Problemas - dirección de la API y modelo de instalación

Todas las rutas relacionadas con los problemas comienzan por:

{BASE_URL}/api/v1/problems

En Codenica Cloud, utiliza el dominio público asignado a la instalación correspondiente:

export BASE_URL="https://twoja-firma.codenica.com"

En la instalación On-Premise predeterminada, la dirección registrada localmente por Codenica Discovery es:

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

Si el administrador ha publicado la instalación con un dominio de empresa, mediante un proxy inverso, con HTTPS o en otro puerto, utiliza la dirección exacta proporcionada para esa instalación:

export BASE_URL="https://api.twoja-firma.example"

No utilices localhost si la integración se ejecuta en un equipo distinto de la API. No envíes tenantId en el body ni en la query string. La base de datos correcta se selecciona a partir de la dirección del host al que se conecta la integración.


Problemas - clave API y límites de licencia

Crea una clave API en Codenica, en Ajustes - API - API Keys. El secreto solo se muestra una vez, justo después de crear o rotar la clave. En ese momento, guarda el Client ID y el Client Secret en el almacén seguro que utilice la integración.

Codenica API está disponible con las licencias Plus y Enterprise. Plus permite crear hasta 50 claves activas y Enterprise hasta 100. Starter no ofrece Codenica API. Crea una clave independiente para cada aplicación y entorno para poder limitar sus scopes, rotar el secreto o eliminar el acceso por separado.

Licencia
Codenica API
Claves activas
Starter
no disponible
0
Plus
disponible
máximo 50
Enterprise
disponible
máximo 100

La validez predeterminada de una clave es de 90 días si no estableces otra fecha en el panel. El plazo máximo de validez es de 5 años. Las claves caducadas o inactivas no ocupan un slot activo, pero siguen visibles hasta que utilices la opción Eliminar. La eliminación del registro es permanente.


Problemas - autenticación y solicitudes seguras

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

export CLIENT_ID="cna_twoj_client_id"
export CLIENT_SECRET="cns_twoj_client_secret"

curl --request GET --url "$BASE_URL/api/v1/problems?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 incluyas la clave en un repositorio, en código enviado al navegador, en una URL, en el historial de comandos ni en los registros. Fuera de las pruebas locales, utiliza HTTPS.

Conserva meta.requestId de la respuesta. Sirve para diagnosticar una solicitud concreta, pero no sustituye al identificador del problema ni debe utilizarse como secreto.


Problemas - comprobación del contexto de conexión

Obtén el contexto antes del primer registro. Así podrás comprobar que la dirección lleva a la base correcta y que la clave seleccionada 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"

En la respuesta, verifica:

  • data.apiVersion y data.contractVersion;
  • data.tenant.id, data.tenant.name y data.tenant.resolvedDomain;
  • data.caller.authentication igual a api_key;
  • la presencia de problems en data.capabilities.resources;
  • los scopes asignados a la clave;
  • los límites de páginas, batch, archivos y solicitudes.

Si el contexto indica otra base o no contiene un scope necesario, detén la integración y corrige la dirección o la clave. Los scopes no se pueden añadir a una solicitud individual.


Problemas - scopes de permisos

La gestión completa de problemas requiere los scopes correspondientes a las operaciones que vayas a utilizar:

problems:read
problems:write
problems:delete
problems:schema
problems:stats
problems:relationships:read
problems:relationships:write
problems:users:read
problems:users:write
problems:files:read
problems:files:write
problems:technical:read
problems:technical:write
problems:pin:write
problems:spam:write
problems:reopen:write
problems:rating:write
problems:escalation:write
problems:approval:write

Para una lectura normal basta con problems:read. El esquema y las estadísticas requieren los scopes independientes problems:schema y problems:stats. La lectura de relaciones, usuarios y archivos requiere los scopes de lectura correspondientes. Las operaciones de escritura utilizan los scopes :write equivalentes.

Las relaciones con otros módulos también requieren acceso de lectura al módulo indicado, por ejemplo assets:read, documents:read, tickets:read o solutions:read. Para crear una aprobación y registrar su decisión, añade los scopes necesarios para el propio módulo approvals. Concede los scopes siguiendo el principio de mínimo privilegio.


Problemas - esquema y campos de diagnóstico

El esquema muestra qué campos se pueden leer y escribir en una base concreta. Obtenlo antes de preparar un formulario o un mapeo:

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

Para cada campo, comprueba entre otros readable, writable, required, technical, unique y maxLength. El esquema también devuelve los diccionarios y los destinos de relación disponibles.

Actualmente, el registro mínimo de un problema requiere subject y requesterEmail. Los problemas tienen su propio grupo de diagnóstico:

Grupo
Campos
Uso
Básicos
subject, requesterEmail, description, comments
descripción del problema y persona que lo solicita
Clasificación
type, status, priority, impact, urgency, severity
forma de tratamiento e importancia del problema
Diagnóstico
isKnown, symptoms, rootCause, impactInfo
problema conocido, síntomas, causa e impacto
Integración
source, services, tags, externalNumber, referenceNumber
enlace con otro sistema

Los campos pin e isSpam son técnicos y se modifican mediante acciones específicas. Los campos del sistema y los de solo lectura, incluidos los datos de valoración y escalado, no deben enviarse en un PATCH normal. Los problemas no admiten los campos de costes currency, estimatedCost y totalValue conocidos de otros módulos.


Problemas - endpoints básicos

Estas son las rutas de problemas más utilizadas:

  • GET /api/v1/problems - lista de problemas;
  • GET /api/v1/problems/{id} - problema individual;
  • POST /api/v1/problems - creación;
  • PATCH /api/v1/problems/{id} - edición parcial;
  • DELETE /api/v1/problems/{id} - eliminación;
  • GET /api/v1/problems/schema - esquema de campos y relaciones;
  • GET /api/v1/problems/stats - estadísticas;
  • GET /api/v1/problems/values - valores utilizados en los filtros;
  • POST /api/v1/problems:batch - operaciones de creación, actualización y eliminación.

Las relaciones, los usuarios, los archivos, las acciones de flujo de trabajo y las aprobaciones tienen rutas independientes. Así, la integración puede recibir únicamente los permisos que realmente necesita.


Problemas - listado y paginación

Obtén la lista por páginas. Incluso con pocos registros, indica expresamente el número y el tamaño de la página:

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

La respuesta contiene data.items y los datos page, pageSize, totalItems, totalPages y hasNextPage. Obtén las páginas siguientes mientras hasNextPage tenga el valor true:

curl --request GET --url "$BASE_URL/api/v1/problems?page=2&pageSize=25&sort=dateUpdated&direction=desc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Para la sincronización, normalmente resulta más práctico ordenar por dateUpdated y guardar los últimos registros procesados. No establezcas pageSize por encima del límite devuelto en el contexto.


Problemas - búsqueda, filtros y ordenación

Puedes combinar los parámetros de la lista. El ejemplo siguiente busca un registro por identificador, limita el resultado al tipo problem y a los problemas conocidos, y después lo ordena por fecha de actualización:

curl --get --url "$BASE_URL/api/v1/problems" \
  --data-urlencode "itemType=problem" \
  --data-urlencode "customId=PUBLIC-API-PROBLEM-20260905131727-SOURCE" \
  --data-urlencode "isKnown=true" \
  --data-urlencode "sort=dateUpdated" \
  --data-urlencode "direction=desc" \
  --data-urlencode "page=1" \
  --data-urlencode "pageSize=25" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Para la sincronización diaria también son útiles los parámetros search, status, priority, subject, requesterEmail, source, externalNumber, referenceNumber, symptoms, rootCause, impactInfo, createdAfter, createdBefore, updatedAfter y updatedBefore, siempre que estén disponibles en el esquema actual.

El filtro estructural tiene el formato field:operator:value. Los operadores disponibles son eq, ne, in, contains, startsWith, endsWith, empty, notEmpty, gt, gte, lt y lte:

curl --get --url "$BASE_URL/api/v1/problems" \
  --data-urlencode "filter=status:eq:Closed" \
  --data-urlencode "filter=rootCause:contains:connection" \
  --data-urlencode "page=1" \
  --data-urlencode "pageSize=25" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Codifica los valores de texto y las fechas según las reglas de las URL. No des por hecho que el diccionario es idéntico en dos bases.


Problemas - selección de campos y datos incluidos

El parámetro fields limita la respuesta a los campos que necesita la integración. El parámetro include añade datos relacionados:

curl --get --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --data-urlencode "fields=subject,requesterEmail,status,priority,isKnown,symptoms,rootCause,impactInfo" \
  --data-urlencode "include=files,relationships,users" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Para leer el modelo completo puedes utilizar fields=*. Incluir archivos, relaciones y usuarios requiere los scopes de lectura correspondientes. fields no evita el control de acceso ni muestra campos técnicos para los que la clave no tiene permisos.

En la respuesta, presta atención a data.id, data.itemType, data.attributes y data.meta. Lee los campos técnicos, como pin o isSpam, pero modifícalos mediante las acciones específicas descritas más adelante.


Problemas - estadísticas y valores de diccionario

Las estadísticas permiten, por ejemplo, contar los problemas según el campo isKnown. Es una operación de lectura y no modifica los registros:

curl --get --url "$BASE_URL/api/v1/problems/stats" \
  --data-urlencode "field=isKnown" \
  --data-urlencode "limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Obtén por separado los valores del campo rootCause cuando los necesites para sugerencias o filtros:

curl --get --url "$BASE_URL/api/v1/problems/values" \
  --data-urlencode "field=rootCause" \
  --data-urlencode "search=connection" \
  --data-urlencode "limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Obtén primero el diccionario y envía el valor en el body solo después. Esto es especialmente importante para status, priority, type y los campos de diagnóstico configurados en la base concreta.


Problemas - creación de un registro

Crea un problema nuevo mediante POST /api/v1/problems. Incluye el tipo técnico problem en el body y los campos modificables dentro de attributes. El ejemplo contiene datos descriptivos, clasificación, información de integración y el grupo de diagnóstico completo:

export IDEMPOTENCY_KEY="public-api-problem-create-20260905131727"

curl --request POST --url "$BASE_URL/api/v1/problems" \
  --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: $IDEMPOTENCY_KEY" \
  --data-raw '{
    "itemType": "problem",
    "attributes": {
      "customId": "PUBLIC-API-PROBLEM-20260905131727-SOURCE",
      "subject": "Problema de integración de Codenica API",
      "requesterEmail": "[email protected]",
      "description": "Problema creado mediante la integración de Codenica API.",
      "comments": "Ejemplo de diagnóstico para el módulo Problems.",
      "source": "Codenica API",
      "type": "Standard",
      "status": "Closed",
      "priority": "High",
      "impact": "Medium",
      "urgency": "High",
      "severity": "High",
      "services": "Codenica API",
      "tags": "codenica-api,problem",
      "externalNumber": "EXT-CODENICA-API-PROBLEM-20260905131727",
      "referenceNumber": "REF-CODENICA-API-PROBLEM-20260905131727",
      "isKnown": true,
      "symptoms": "Los usuarios no pueden completar la sincronización.",
      "rootCause": "Error de conexión con el servicio externo.",
      "impactInfo": "La sincronización del grupo de datos afectado se ha retrasado."
    },
    "customValues": [
      {
        "name": "description",
        "valuePattern": "[problem-test] PUBLIC-API-PROBLEM-20260905131727"
      }
    ]
  }'

El mínimo requerido es subject y requesterEmail, salvo que el esquema imponga requisitos adicionales. Una creación correcta devuelve HTTP 201, el identificador data.id y un ETag en la cabecera y en data.meta.etag. El secreto de la clave no forma parte de la respuesta del objeto.


Problemas - idempotencia de la creación

Repetir la misma solicitud con el mismo Idempotency-Key debe devolver el mismo resultado lógico y no crear un segundo problema:

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

Después de un resultado de red incierto, puedes repetir la misma clave de forma segura únicamente para esa misma solicitud. No utilices una clave para dos operaciones diferentes. Genera una clave nueva para un body nuevo.

Idempotency-Key es obligatorio en todas las solicitudes que modifican datos, incluidas la edición, las relaciones, los archivos, las acciones de flujo de trabajo y la eliminación. Reutilizar la misma clave con otra ruta u otro body provoca un conflicto de idempotencia.


Problemas - lectura y ETag

Lee un problema individual con sus datos incluidos de la siguiente manera:

curl --get --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --data-urlencode "fields=*" \
  --data-urlencode "include=files,relationships,users" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Conserva el ETag de la cabecera de respuesta. Debe coincidir con data.meta.etag y meta.etag dentro del envoltorio de respuesta. Después de cada escritura, acción, cambio de relación u operación de archivos, obtén o vuelve a leer el ETag actualizado.

Un ETag representa la versión de un problema concreto. No utilices el ETag obtenido para un problema para modificar otro.


Problemas - edición con If-Match

La edición es parcial. Envía únicamente los campos que quieras cambiar:

curl --request PATCH --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-update-20260905131727" \
  --data-raw '{
    "attributes": {
      "description": "Descripción actualizada mediante la integración.",
      "status": "Closed",
      "priority": "High",
      "isKnown": false,
      "symptoms": "Síntomas tras una nueva observación.",
      "rootCause": "Análisis actualizado de la causa raíz.",
      "impactInfo": "Impacto después de aplicar la solución alternativa."
    }
  }'

No modifiques mediante un PATCH normal los campos de solo lectura, como rating, dateRating, dateFeedback, dateReopened y dateEscalated. Pin, spam, reopen, rating, escalado y approval tienen endpoints específicos.

Después de una edición correcta recibirás HTTP 200 y un ETag nuevo. Guárdalo antes de la siguiente operación.


Problemas - control de un If-Match desactualizado

Toda mutación, excepto la creación, requiere el ETag actual. Se rechazan tanto la ausencia de la cabecera como un valor desactualizado:

curl --request PATCH --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-problem-missing-if-match-20260905131727" \
  --data-raw '{"attributes":{"isKnown":false}}'

La ausencia de If-Match devuelve HTTP 428 con el código if_match_required. Si envías un ETag anterior, recibirás HTTP 412 con el código if_match_failed. Una solicitud rechazada no debe modificar el problema.

Después de HTTP 412, vuelve a obtener el registro, lee el ETag nuevo y decide entonces si puedes repetir la edición. No sobrescribas sin comprobar los cambios realizados por otro usuario o proceso.


Problemas - operaciones batch

Batch sirve para gestionar varios elementos independientes. Una solicitud puede contener operaciones de create, update y delete:

curl --request POST --url "$BASE_URL/api/v1/problems: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-problem-batch-20260905131727" \
  --data-raw '{
    "items": [
      {
        "operation": "create",
        "create": {
          "itemType": "problem",
          "attributes": {
            "customId": "PUBLIC-API-PROBLEM-20260905131727-BATCH-A",
            "subject": "Problema del batch A",
            "requesterEmail": "[email protected]",
            "source": "Codenica API",
            "type": "Standard",
            "status": "Open",
            "priority": "Medium",
            "isKnown": true,
            "symptoms": "Síntomas del problema A",
            "rootCause": "Causa raíz del problema A",
            "impactInfo": "Impacto del problema A"
          }
        }
      },
      {
        "operation": "update",
        "id": "PROBLEM_UUID",
        "ifMatch": "\"CURRENT_ETAG\"",
        "update": {
          "attributes": {
            "isKnown": false,
            "rootCause": "Nuevo análisis de la causa raíz"
          }
        }
      },
      {
        "operation": "delete",
        "id": "OTHER_PROBLEM_UUID",
        "ifMatch": "\"OTHER_CURRENT_ETAG\""
      }
    ]
  }'

En batch update y delete, utiliza el ETag del registro concreto. La clave de idempotencia identifica toda la solicitud batch, no cada elemento. Comprueba la respuesta elemento por elemento, según su índice, estado, identificador y error. El éxito completo suele devolver HTTP 200 y un resultado parcial HTTP 207 Multi-Status. Batch no es una transacción all-or-nothing.


Problemas - relaciones con objetos

Los destinos de relación disponibles se devuelven en /api/v1/problems/schema. El contrato actual puede incluir:

assets
documents
changes
tickets
problems
solutions
releases
notes
approvals
worktasks
requesteditems

Que un destino aparezca en el esquema no significa que exista un registro accesible en la base concreta. Antes de añadir una relación, comprueba el identificador, targetDataSet, targetItemType y los permisos de lectura del destino.

Para assets, documents, problems, changes, tickets, solutions y releases, utiliza un relationshipType permitido por el esquema, por ejemplo related. Para notes, approvals, worktasks y requesteditems, deja relationshipType en null. No fuerces related cuando no esté admitido.

Añadir varias relaciones:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_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: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-relationships-20260905131727" \
  --data-raw '{
    "add": [
      {
        "targetId": "ASSET_UUID",
        "targetDataSet": "assets",
        "targetItemType": "computer",
        "relationshipType": "related"
      },
      {
        "targetId": "DOCUMENT_UUID",
        "targetDataSet": "documents",
        "targetItemType": "invoice",
        "relationshipType": "related"
      },
      {
        "targetId": "NOTE_UUID",
        "targetDataSet": "notes",
        "targetItemType": "note",
        "relationshipType": null
      }
    ],
    "remove": []
  }'

La respuesta HTTP 200 contiene los contadores added, removed y skipped. skipped no es un error de transporte, por lo que después de la operación debes obtener la colección de relaciones y comprobar su contenido.


Problemas - lectura y eliminación de relaciones

Obtén la lista de relaciones de esta forma:

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

Elimina una relación individual con el ETag actual del problema de origen. Para un destino que conserve relationshipType, indícalo en la query string:

curl --request DELETE --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/relationships/tickets/{TICKET_ID}?relationshipType=related" \
  --header "Accept: application/json, application/problem+json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-relationship-delete-20260905131727"

Para un destino como notes, cuyo esquema indica que no utiliza tipo de relación, omite el parámetro relationshipType. También puedes eliminar una relación mediante una edición parcial:

curl --request PATCH --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-relationship-patch-20260905131727" \
  --data-raw '{
    "relationshipsToRemove": [
      {
        "targetId": "TICKET_UUID",
        "targetDataSet": "tickets",
        "targetItemType": "ticket",
        "relationshipType": "related"
      }
    ]
  }'

Eliminar una relación no elimina el registro que era su destino. Después de cada cambio, vuelve a obtener la colección y guarda el ETag nuevo del problema.


Problemas - relaciones con usuarios

Un problema puede tener las siguientes relaciones de usuario:

  • agent - persona responsable de la gestión;
  • watcher - observador;
  • appUserRequester - usuario de la aplicación que comunicó el problema.

Para Problems, no des por supuesta una relación clientRequester. Los destinos son usuarios activos y están sujetos a los controles de acceso de ubicación y departamento.

Asignar un agente:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/user-relationships" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-agent-20260905131727" \
  --data-raw '{
    "targetId": "USER_UUID",
    "targetDataSet": "users",
    "relationshipType": "agent"
  }'

Añadir un observador mediante batch:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/user-relationships:batch" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-watcher-20260905131727" \
  --data-raw '{
    "add": [
      {
        "targetId": "WATCHER_USER_UUID",
        "targetDataSet": "users",
        "relationshipType": "watcher"
      }
    ],
    "remove": []
  }'

Leer y eliminar relaciones:

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

curl --request DELETE --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/user-relationships/users/{USER_ID}?relationshipType=agent" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-agent-delete-20260905131727"

También puedes eliminar un observador mediante batch dejando add vacío e incluyendo la entrada en remove. Lee el ETag nuevo después de cada cambio.


Problemas - archivos

Antes de operar con un archivo, lee el problema actual y su ETag. Para enviar un archivo se necesita una solicitud multipart/form-data:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/files?relationshipType=documentation" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-file-one-20260905131727" \
  --form "[email protected];type=text/plain"

Lista de archivos:

curl --request GET --url "$BASE_URL/api/v1/problems/{PROBLEM_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 contiene, entre otros, id, name, fileName, contentType, size, relationshipType, isMain y downloadUrl. Trata downloadUrl como una ruta de la API, no como un enlace público anónimo. En Problems, isMain siempre es false.

Descarga el contenido como datos binarios:

curl --request GET --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/files/{FILE_ID}/content" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --output problem-evidence.txt

Puedes asociar un archivo existente a otro problema. En ese caso, el ETag corresponde al problema de destino:

curl --request POST --url "$BASE_URL/api/v1/problems/{OTHER_PROBLEM_ID}/files/{FILE_ID}?relationshipType=manual" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $OTHER_PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-file-attach-20260905131727"

Eliminar un archivo:

curl --request DELETE --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/files/{FILE_ID}" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-file-delete-20260905131727"

Lee el límite de tamaño de archivo en context antes de subirlo. No cargues un archivo grande en memoria sin comprobar antes el límite.


Problemas - fijar, spam y reabrir

Fijar, marcar como spam y reabrir son acciones independientes. Cada acción requiere el ETag actual y una clave de idempotencia nueva.

Fijar un problema:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/pin" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-pin-20260905131727" \
  --data-raw '{"pin":2}'

El valor de pin puede ser un número del 0 al 3 o null, según el esquema. Marcar y desmarcar como spam:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/spam" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-spam-on-20260905131727" \
  --data-raw '{"isSpam":true}'

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/spam" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-spam-off-20260905131727" \
  --data-raw '{"isSpam":false}'

Reabrir un problema cerrado:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/reopen" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-reopen-20260905131727"

Los scopes necesarios son, respectivamente, problems:pin:write, problems:spam:write y problems:reopen:write. Obtén de nuevo el problema después de cada acción y guarda el ETag actualizado.


Problemas - valoración y escalado

La valoración se guarda mediante un endpoint independiente. Puedes incluir una solicitud de escalado:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/rating" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-rating-20260905131727" \
  --data-raw '{
    "rating": 4,
    "feedback": "Valoración de la integración de Codenica API.",
    "isEscalationRequested": true,
    "escalationRequestReason": "El problema requiere el análisis del equipo de segundo nivel."
  }'

La valoración va de 0 a 5 y requiere el scope problems:rating:write. Añadir una solicitud de escalado requiere además problems:escalation:write y los permisos adecuados para el usuario. Si solo guardas una valoración, omite los campos de escalado. Después de guardarla, vuelve a leer al menos rating, feedback, las fechas de valoración y escalationRequestReason.


Problemas - aprobación y decisión

Puedes crear una aprobación como objeto approval independiente y relacionarla con el problema. La persona indicada en approverId debe tener permiso para tomar la decisión:

curl --request POST --url "$BASE_URL/api/v1/approvals" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-problem-approval-create-20260905131727" \
  --data-raw '{
    "itemType": "approval",
    "approverId": "APPROVER_USER_UUID",
    "attributes": {
      "customId": "PUBLIC-API-PROBLEM-20260905131727-APPROVAL",
      "category": "Codenica API",
      "description": "Aprobación del análisis del problema."
    },
    "relationships": [
      {
        "targetId": "PROBLEM_UUID",
        "targetDataSet": "problems",
        "targetItemType": "problem"
      }
    ]
  }'

Después de crearla, lee la aprobación y registra la decisión mediante la ruta del problema. APPROVAL_ID es el identificador de la aprobación, no el de un usuario:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/approvals/{APPROVAL_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-approval-decision-20260905131727" \
  --data-raw '{
    "approve": true,
    "remark": "Aprobado mediante la integración de Codenica API."
  }'

Para rechazarla, envía approve con el valor false y tu propio comentario. Después de la decisión, vuelve a leer la aprobación y comprueba su estado o la fecha de decisión. A continuación, actualiza el problema, porque la decisión puede cambiar su ETag y el estado del proceso.


Problemas - eliminación de un registro

Antes de eliminarlo, vuelve a obtener el problema y utiliza su ETag actual:

curl --request DELETE --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --header "Accept: application/json, application/problem+json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-delete-20260905131727"

Después de HTTP 200, realiza un GET de control con el mismo UUID. Espera HTTP 404 con el código problem_not_found u otro código indicado en el contrato. Si el problema tiene relaciones, archivos o una aprobación, comprueba antes las consecuencias en el esquema y los requisitos de tu base.

Eliminar un problema no debe sustituir al archivado del historial. Si el registro debe permanecer en la documentación, cambia su estado o traslada los datos a un sistema destinado a conservar el historial.


Problemas - errores, límites y seguridad

Los errores se devuelven en formato application/problem+json. Ejemplo de respuesta:

{
  "type": "https://docs.codenica.com/errors/problem_not_found",
  "title": "Problem not found.",
  "status": 404,
  "detail": "The problem does not exist or is outside the caller's access scope.",
  "instance": "/api/v1/problems/PROBLEM_UUID",
  "code": "problem_not_found",
  "requestId": "request-id-from-response"
}

En la lógica de integración, utiliza principalmente status y code. El campo detail está pensado para las personas y su texto puede cambiar.

HTTP
Significado
Respuesta
400
datos no válidos o campo fuera del esquema
lee los errores de los campos y corrige el mapeo
401
autenticación ausente o no válida
comprueba el host y la clave
403
falta un scope o el acceso a la base
cambia el scope de la clave o los permisos del usuario
404
el problema, el archivo o el destino de la relación no existe o no es visible
verifica el UUID y la dirección de la instalación
409
conflicto de datos, versión o idempotencia
no crees un segundo registro sin analizarlo
412
ETag desactualizado
obtén el problema y su ETag nuevo
413
el body o el archivo es demasiado grande
comprueba el límite en context
422
el body o los valores de los campos no son válidos
corrige el payload según el esquema
428
falta If-Match o Idempotency-Key
añade la cabecera correcta
429
límite de solicitudes superado
utiliza backoff y Retry-After

Lee las cabeceras X-RateLimit-Limit y X-RateLimit-Remaining. Después de 429, aplica un retraso progresivo y respeta el posible Retry-After. En los registros guarda el método, el endpoint, el estado y requestId, pero nunca el Client Secret ni las cabeceras de autenticación completas.

Los datos de problemas pueden contener información operativa, personal y de diagnóstico. Limita los campos, utiliza HTTPS y restringe el acceso de la integración a la base concreta.


Problemas - flujo de integración

  1. Establece BASE_URL para la instalación Cloud u On-Premise correcta.
  2. Crea una clave independiente en Ajustes - API - API Keys y selecciona los scopes mínimos.
  3. Guarda Client ID y Client Secret en un almacén seguro.
  4. Envía GET /api/v1/context y comprueba la base, el caller y los límites.
  5. Obtén GET /api/v1/problems/schema y crea el mapeo de los campos de diagnóstico.
  6. Obtén la lista de problemas o crea uno nuevo con POST y un Idempotency-Key único.
  7. Guarda el UUID del problema y su ETag.
  8. Actualiza el ETag antes de cada mutación y utiliza una clave de idempotencia nueva.
  9. Añade relaciones, usuarios y archivos solo después de comprobar los destinos en el esquema.
  10. Ejecuta pin, spam, rating, escalado, reopen y las decisiones de aprobación como operaciones independientes.
  11. Ante un 412, obtén el registro, resuelve el conflicto y repite la operación de forma consciente.
  12. En batch, comprueba el resultado de cada elemento, porque un error parcial no tiene por qué deshacer los éxitos.
  13. Gestiona 429, guarda requestId sin secretos y elimina la clave cuando la integración deje de utilizarse.
  14. Antes de eliminar, confirma el ETag actual y comprueba después HTTP 404.

Este flujo permite sincronizar los problemas y su análisis con otro sistema sin depender de la estructura interna de la base. Si cambia la configuración de los campos, la dirección de la instalación o los scopes de la clave, vuelve a leer el contexto y el esquema.