Cambios en Codenica API
Para trabajar con cambios a través de Codenica API, empiece por crear una clave en los ajustes de Codenica. Si todavía no la ha creado, abra en una pestaña nueva Codenica API - introducción. Allí se explican la creación de claves, la conservación del secreto y las reglas comunes de autenticación.
El nombre técnico del módulo es changes y el tipo de un objeto individual es change. Un cambio sirve para planificar y controlar una modificación programada de un servicio, una infraestructura o una configuración. Además de los datos básicos, incluye campos de planificación como fechas, riesgo, impacto, plan de despliegue, plan de reversión y motivo del cambio.
En las secciones siguientes encontrará el flujo completo: comprobación del esquema y de los diccionarios, listados, filtros, creación, actualización con ETag, operaciones batch, relaciones, usuarios, archivos, acciones de workflow, aprobaciones y eliminación.
Los ejemplos utilizan el prefijo PUBLIC-API-CHANGE-20260905130127. En su integración, sustitúyalo por su propio identificador y adapte las direcciones de correo, los identificadores y los valores a los datos de su base.
Cambios - dirección de la API y elección de la instalación
Todas las rutas relacionadas con cambios empiezan por:
{BASE_URL}/api/v1/changesEn Codenica Cloud, utilice el dominio público asignado a su instalación:
export BASE_URL="https://tu-empresa.codenica.com"En la instalación On-Premise predeterminada, Codenica Discovery registra el servicio localmente en:
export BASE_URL="http://codenica.local:5150"Si el administrador ha publicado la instalación On-Premise bajo un dominio de la empresa, mediante un proxy inverso, con HTTPS o en otro puerto, utilice la dirección exacta proporcionada para esa instalación:
export BASE_URL="https://api.tu-empresa.example"No utilice localhost si el programa de integración se ejecuta en un ordenador distinto de la API. No envíe tenantId en el body ni en la cadena de consulta. La base de datos correcta se selecciona a partir de la dirección del host utilizada por la integración.
Cambios - clave de API y límites de licencia
Cree una clave de API en Codenica, en Ajustes - API - API Keys. El secreto se muestra una sola vez, justo después de crear o rotar la clave. Guarde entonces el Client ID y el Client Secret en el almacén seguro de secretos utilizado por 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 incluye Codenica API. Cree una clave independiente para cada aplicación y entorno para poder limitar sus ámbitos, rotar el secreto o retirar el acceso de forma independiente.
Seleccione únicamente los permisos necesarios para trabajar con cambios. Una integración de solo lectura puede utilizar changes:read. La creación de aprobaciones y el procesamiento de decisiones de aprobación requieren además ámbitos del módulo approvals.
Cambios - autenticación y solicitudes seguras
Autentique cada solicitud de la API pública con las dos cabeceras de la clave:
export CLIENT_ID="cna_su_client_id"
export CLIENT_SECRET="cns_su_client_secret"
curl --request GET "$BASE_URL/api/v1/changes?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 coloque 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, utilice HTTPS.
Conserve meta.requestId de cada respuesta. Sirve para diagnosticar una solicitud concreta, pero no sustituye al identificador del cambio ni debe utilizarse como secreto.
Cambios - comprobación del contexto de conexión
Antes de realizar la primera escritura, lea el contexto. Así comprobará que la dirección apunta a la base correcta y que la clave seleccionada tiene los ámbitos necesarios:
curl --request GET "$BASE_URL/api/v1/context" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Compruebe:
data.apiVersionydata.contractVersion;data.tenant.idydata.tenant.resolvedDomain;data.caller.authenticationcon el valorapi_key;- la presencia de
changesendata.capabilities.resources; - los ámbitos asignados a la clave;
- los límites de páginas, batch, archivos y solicitudes.
Si el contexto indica otra base o no contiene el ámbito necesario, detenga la integración y corrija la dirección o la clave. Los ámbitos no se pueden conceder en una solicitud individual.
Cambios - ámbitos de permisos
El manejo completo de cambios requiere los ámbitos correspondientes a las operaciones que se utilicen:
changes:read
changes:write
changes:delete
changes:schema
changes:stats
changes:relationships:read
changes:relationships:write
changes:users:read
changes:users:write
changes:files:read
changes:files:write
changes:technical:read
changes:technical:write
changes:pin:write
changes:spam:write
changes:reopen:write
changes:rating:write
changes:escalation:write
changes:approval:writePara una lectura normal basta con changes:read. El esquema y las estadísticas requieren changes:schema y changes:stats. La lectura de relaciones, usuarios y archivos requiere respectivamente :relationships:read, :users:read y :files:read. Las operaciones de escritura utilizan los ámbitos :write equivalentes.
Si la integración crea, lee, modifica o elimina aprobaciones, añada:
approvals:read
approvals:write
approvals:delete
approvals:relationships:read
approvals:relationships:write
approvals:technical:read
approvals:technical:writeLas relaciones con otros módulos también requieren acceso de lectura al módulo de destino, por ejemplo assets:read, documents:read, tickets:read, problems:read o releases:read. Conceda los ámbitos siguiendo el principio de mínimo privilegio.
Cambios - esquema y campos de planificación
El esquema muestra qué campos se pueden leer y escribir en su base de datos. Descárguelo antes de preparar el body:
curl --request GET "$BASE_URL/api/v1/changes/schema" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Para cada campo, compruebe readable, writable, required, technical, unique, maxLength y las reglas de generación automática. El esquema también devuelve los destinos de relación disponibles.
Para crear un cambio, actualmente se necesitan como mínimo subject y requesterEmail. Los demás campos dependen de la configuración y del proceso:
subject, requesterEmail, description, commentstype, status, priority, impact, urgency, severitydatePlannedStart, datePlannedEnd, risk, impactInfo, rolloutPlan, backoutPlan, reasonForChangesource, externalNumber, referenceNumber, services, tagscurrency, estimatedCost, totalValueLea los valores de diccionario de estado, prioridad, tipo y riesgo en el esquema o mediante el endpoint values. Envíe las fechas en formato ISO 8601 y los números como números JSON. No dé por hecho que los diccionarios son iguales en dos bases de datos.
{
"datePlannedStart": "2030-01-15T09:00:00Z",
"datePlannedEnd": "2030-01-15T17:00:00Z",
"risk": "Medium",
"impactInfo": "Evaluación del impacto planificado",
"rolloutPlan": "Despliegue y compruebe los controles de estado.",
"backoutPlan": "Restaure la versión anterior si la comprobación falla.",
"reasonForChange": "La versión actual de la plataforma requiere una actualización controlada."
}Cambios - endpoints principales
Las rutas más utilizadas para cambios son:
GET /api/v1/changes- lista de cambios;GET /api/v1/changes/{id}- un cambio;POST /api/v1/changes- creación;PATCH /api/v1/changes/{id}- actualización parcial;DELETE /api/v1/changes/{id}- eliminación;GET /api/v1/changes/schema- esquema de campos y relaciones;GET /api/v1/changes/stats- estadísticas;GET /api/v1/changes/values- valores para filtros;POST /api/v1/changes:batch- operaciones de creación, actualización y eliminación.
Las relaciones, los usuarios, los archivos, las acciones de workflow y las aprobaciones tienen rutas independientes. Así, la integración puede recibir solo los permisos que realmente necesita.
Cambios - listados y paginación
Lea las listas página por página. Incluso con una colección pequeña, indique explícitamente el número y el tamaño de página:
curl --request GET "$BASE_URL/api/v1/changes?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 valores page, pageSize, totalItems, totalPages y hasNextPage. Solicite las páginas siguientes mientras hasNextPage sea true:
curl --request GET "$BASE_URL/api/v1/changes?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 resulta útil ordenar por dateUpdated y guardar los últimos registros procesados. No establezca pageSize por encima del límite devuelto en el contexto.
Cambios - búsqueda, filtros y ordenación
Puede combinar los parámetros de la lista. Este ejemplo busca un registro concreto, lo limita al tipo change y al riesgo Medium, y ordena el resultado por fecha de actualización:
curl --get "$BASE_URL/api/v1/changes" \
--data-urlencode "itemType=change" \
--data-urlencode "customId=PUBLIC-API-CHANGE-20260905130127-SOURCE" \
--data-urlencode "risk=Medium" \
--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 habitual también pueden ser útiles status, priority, subject, requesterEmail, source, externalNumber, referenceNumber, datePlannedStart, datePlannedEnd, createdAfter, createdBefore, updatedAfter y updatedBefore, cuando estén disponibles en el contrato actual.
Codifique para la URL los valores de texto y las fechas. Utilice search para una búsqueda general y el parámetro específico del campo admitido por el esquema para filtrar un campo concreto. No dé por hecho que todos los valores de diccionario tienen un nombre en inglés.
Cambios - selección de campos e inclusión de datos
El parámetro fields limita la respuesta a las propiedades que necesita la integración. El parámetro include añade datos relacionados:
curl --get "$BASE_URL/api/v1/changes/PUBLIC_CHANGE_UUID" \
--data-urlencode "fields=subject,requesterEmail,status,priority,risk,datePlannedStart,datePlannedEnd" \
--data-urlencode "include=files,relationships,users" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Para obtener el modelo completo puede utilizar fields=*. Incluir archivos, relaciones y usuarios requiere los ámbitos de lectura correspondientes. fields no evita el control de acceso ni muestra campos técnicos para los que la clave no tiene permiso.
En la respuesta, preste atención a data.id, data.itemType, data.attributes y data.meta. Lea campos técnicos como pin o isSpam, pero modifíquelos mediante las acciones específicas descritas más adelante.
Cambios - estadísticas y valores de diccionario
Las estadísticas permiten, por ejemplo, contar los cambios por nivel de riesgo. Es una operación de lectura y no modifica los registros:
curl --get "$BASE_URL/api/v1/changes/stats" \
--data-urlencode "field=risk" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Obtenga por separado los valores de un campo cuando necesite construir controles de filtro:
curl --get "$BASE_URL/api/v1/changes/values" \
--data-urlencode "field=risk" \
--data-urlencode "search=Medium" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Lea primero el diccionario y envíe después el valor devuelto en el body. Esto es especialmente importante para risk, status, priority y type, porque sus valores pueden depender del idioma y de la configuración de una base concreta.
Cambios - creación de un registro
Cree un cambio con POST /api/v1/changes. Coloque el tipo técnico change y los campos que se pueden escribir dentro de attributes. El ejemplo siguiente incluye datos básicos, clasificación, información de integración y el grupo completo de planificación:
export IDEMPOTENCY_KEY="public-api-change-create-20260905130127"
curl --request POST "$BASE_URL/api/v1/changes" \
--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": "change",
"attributes": {
"customId": "PUBLIC-API-CHANGE-20260905130127-SOURCE",
"subject": "PUBLIC-API-CHANGE-20260905130127 solicitud de integración",
"requesterEmail": "[email protected]",
"description": "Creado mediante el flujo de Changes de la API pública",
"comments": "Cambio de integración ITSM",
"source": "Public API",
"type": "Standard",
"status": "Closed",
"priority": "High",
"impact": "Medium",
"urgency": "High",
"severity": "High",
"services": "Codenica Public API",
"tags": "public-api,change",
"externalNumber": "EXT-PUBLIC-API-CHANGE-20260905130127",
"referenceNumber": "REF-PUBLIC-API-CHANGE-20260905130127",
"currency": "PLN",
"estimatedCost": 12.5,
"totalValue": 12.5,
"datePlannedStart": "2030-01-15T09:00:00Z",
"datePlannedEnd": "2030-01-15T17:00:00Z",
"risk": "Medium",
"impactInfo": "Evaluación del impacto planificado para la solicitud de integración",
"rolloutPlan": "Despliegue el cambio aprobado y compruebe los controles de estado.",
"backoutPlan": "Restaure la versión anterior si la comprobación falla.",
"reasonForChange": "La versión actual de la plataforma requiere una actualización controlada."
}
}'Una solicitud correcta devuelve 201 Created. Guarde data.id, el ETag de la cabecera HTTP y data.meta.etag. La propiedad opcional customValues sirve para campos personalizados cuando la integración conoce su configuración.
Si la base requiere otros valores de diccionario, no copie los nombres anteriores sin comprobar el esquema y el endpoint values.
Cambios - reintentos seguros con Idempotency-Key
Envíe una Idempotency-Key única con cada operación que modifique datos. Si la respuesta se pierde por una interrupción de red, repita exactamente la misma solicitud con la misma clave:
curl --request POST "$BASE_URL/api/v1/changes" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: public-api-change-create-20260905130127" \
--data-binary @change.jsonLa idempotencia hace que un reintento idéntico devuelva el resultado de la operación original en lugar de crear un segundo cambio. La misma clave no debe utilizarse con otro body. Genere una clave nueva para un cambio, una actualización, una relación, un archivo o una acción nuevos.
La idempotencia no sustituye al ETag. En las operaciones que requieren control de versión, envíe también el If-Match actual.
Cambios - lectura del registro y del ETag
Después de crear o localizar un identificador, lea un cambio:
export CHANGE_ID="PUBLIC_CHANGE_UUID"
curl --get "$BASE_URL/api/v1/changes/$CHANGE_ID" \
--data-urlencode "fields=*" \
--data-urlencode "include=files,relationships,users" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"El ETag se devuelve en la cabecera HTTP ETag y en data.meta.etag. Trátelo como la versión de ese cambio concreto y guárdelo antes de cada modificación posterior.
El ETag puede cambiar después de editar campos, modificar relaciones, asignar un usuario, cargar o eliminar un archivo o ejecutar una acción de workflow. Después de cada modificación correcta, lea el nuevo estado o tome el nuevo ETag de la respuesta.
Cambios - actualización con If-Match
Utilice PATCH para una actualización parcial. Envíe solo los campos que deben cambiar, el ETag actual y una clave de idempotencia nueva:
curl --request PATCH "$BASE_URL/api/v1/changes/$CHANGE_ID" \
--header "Accept: application/json" \
--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-change-update-20260905130127" \
--data-raw '{
"attributes": {
"description": "Cambio actualizado PUBLIC-API-CHANGE-20260905130127",
"status": "Closed",
"priority": "High",
"risk": "Low",
"impactInfo": "Evaluación del impacto actualizada",
"rolloutPlan": "Ejecute el plan de despliegue revisado y compruebe el servicio.",
"backoutPlan": "Restaure la versión anterior si el cambio revisado falla.",
"reasonForChange": "Justificación de implementación actualizada."
}
}'Con un ETag actual, la respuesta es 200 OK y contiene una nueva versión del registro. Modifique campos técnicos como pin e isSpam mediante sus endpoints específicos. No intente cambiarlos con un PATCH normal si el esquema los marca como de solo lectura.
Las fechas de planificación son campos normales del cambio, por lo que se actualizan dentro de attributes. Antes de guardar, compruebe que el esquema las marca como writable.
Cambios - ETag obsoleto o ausente
Si otro proceso modificó el registro después de su lectura, un ETag antiguo no puede sobrescribir la versión nueva. Para un valor obsoleto, la API devuelve 412 Precondition Failed y el código if_match_failed:
{
"status": 412,
"code": "if_match_failed"
}Si falta If-Match en una modificación que lo exige, se devuelve 428 Precondition Required con el código if_match_required:
{
"status": 428,
"code": "if_match_required"
}Después de cualquiera de las dos respuestas, vuelva a leer el cambio, revise su estado actual y decida si la actualización sigue siendo necesaria. Después envíela con el nuevo ETag y una clave de idempotencia nueva. No desactive el control de concurrencia en la integración.
Cambios - operaciones batch
Una operación batch combina varias operaciones independientes en una sola solicitud. El ejemplo siguiente crea dos cambios:
curl --request POST "$BASE_URL/api/v1/changes:batch" \
--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-change-batch-create-20260905130127" \
--data-raw '{
"items": [
{
"operation": "create",
"create": {
"itemType": "change",
"attributes": {
"customId": "PUBLIC-API-CHANGE-20260905130127-BATCH-A",
"subject": "Cambio batch A",
"requesterEmail": "[email protected]",
"description": "Cambio batch A",
"source": "Public API",
"type": "Standard",
"status": "Open",
"priority": "Medium",
"risk": "Low",
"datePlannedStart": "2030-02-10T09:00:00Z",
"datePlannedEnd": "2030-02-10T12:00:00Z"
}
}
},
{
"operation": "create",
"create": {
"itemType": "change",
"attributes": {
"customId": "PUBLIC-API-CHANGE-20260905130127-BATCH-B",
"subject": "Cambio batch B",
"requesterEmail": "[email protected]",
"description": "Cambio batch B",
"source": "Public API",
"type": "Standard",
"status": "Open",
"priority": "Low",
"risk": "High",
"datePlannedStart": "2030-02-11T09:00:00Z",
"datePlannedEnd": "2030-02-11T12:00:00Z"
}
}
}
]
}'La respuesta contiene items, el estado de cada operación y los contadores succeeded y failed. Procese cada elemento por separado. Un batch no es una transacción de todo o nada, por lo que el error de un elemento no tiene por qué revertir los demás.
La actualización y la eliminación requieren el ETag de cada registro. El body de un batch con una actualización y una eliminación puede tener este aspecto:
{
"items": [
{
"operation": "update",
"id": "CHANGE_A_UUID",
"ifMatch": "\"CHANGE_A_ETAG\"",
"update": {
"attributes": {
"description": "Actualización batch A"
}
}
},
{
"operation": "delete",
"id": "CHANGE_B_UUID",
"ifMatch": "\"CHANGE_B_ETAG\""
}
]
}Una sola clave de idempotencia identifica toda la solicitud batch, no cada elemento. Después de recibir el resultado, guarde los identificadores y ETag únicamente de los registros creados o modificados correctamente.
Cambios - relaciones con objetos
Los posibles destinos de las relaciones se devuelven en changes/schema. Según el acceso y los datos, un cambio puede vincularse con activos, documentos, otros cambios, tickets, problemas y releases. Cada destino debe ser visible para la clave y targetItemType debe coincidir con el tipo real del objeto.
Para añadir una relación:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/relationships" \
--header "Accept: application/json" \
--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-change-relationship-asset-20260905130127" \
--data-raw '{
"targetId": "ASSET_UUID",
"targetDataSet": "assets",
"targetItemType": "computer",
"relationshipType": "related"
}'Una adición individual devuelve 201 Created. Puede añadir varias relaciones en una sola solicitud:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/relationships:batch" \
--header "Accept: application/json" \
--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-change-relationship-batch-20260905130127" \
--data-raw '{
"add": [
{
"targetId": "ASSET_UUID",
"targetDataSet": "assets",
"targetItemType": "computer",
"relationshipType": "related"
},
{
"targetId": "DOCUMENT_UUID",
"targetDataSet": "documents",
"targetItemType": "document",
"relationshipType": "related"
}
],
"remove": []
}'Para leer las relaciones:
curl --request GET "$BASE_URL/api/v1/changes/$CHANGE_ID/relationships?page=1&pageSize=100" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"La respuesta batch devuelve los contadores added, removed y skipped. Cada modificación de una relación cambia el ETag de origen, por lo que debe leer un valor nuevo antes de la siguiente modificación.
Cambios - eliminación de relaciones
Elimine una relación con el ETag actual del cambio de origen. Indique en la ruta la colección y el identificador del destino:
curl --request DELETE "$BASE_URL/api/v1/changes/$CHANGE_ID/relationships/changes/$TARGET_CHANGE_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: "CURRENT_ETAG"' \
--header "Idempotency-Key: public-api-change-relationship-delete-20260905130127"Para un activo utilice relationships/assets/{TARGET_ID}; para un documento, relationships/documents/{TARGET_ID}. El parámetro relationshipType debe coincidir con el tipo guardado.
También puede eliminar relaciones como parte de una actualización parcial:
curl --request PATCH "$BASE_URL/api/v1/changes/$CHANGE_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-change-relationship-patch-20260905130127" \
--data-raw '{
"relationshipsToRemove": [
{
"targetId": "TARGET_UUID",
"targetDataSet": "changes",
"targetItemType": "change",
"relationshipType": "related"
}
]
}'Después de eliminarla, vuelva a leer la lista y confirme que se ha quitado el destino correcto. Eliminar una relación no elimina el registro que era su destino.
Cambios - relaciones con usuarios
Las relaciones con usuarios son un mecanismo independiente. Un cambio admite tres roles: agent para la persona que realiza el trabajo, watcher para un observador y appUserRequester para el usuario que envió la solicitud. Este objeto no admite clientRequester.
Asignar un agente:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/user-relationships" \
--header "Accept: application/json" \
--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-change-agent-20260905130127" \
--data-raw '{
"targetId": "USER_UUID",
"targetDataSet": "users",
"relationshipType": "agent"
}'Añadir un observador mediante batch:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/user-relationships:batch" \
--header "Accept: application/json" \
--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-change-watcher-20260905130127" \
--data-raw '{
"add": [
{
"targetId": "WATCHER_USER_UUID",
"targetDataSet": "users",
"relationshipType": "watcher"
}
],
"remove": []
}'Leer las relaciones con usuarios:
curl --request GET "$BASE_URL/api/v1/changes/$CHANGE_ID/user-relationships?page=1&pageSize=100" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Eliminar una asignación indicando el tipo de relación:
curl --request DELETE "$BASE_URL/api/v1/changes/$CHANGE_ID/user-relationships/users/$USER_ID?relationshipType=appUserRequester" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "CURRENT_ETAG"' \
--header "Idempotency-Key: public-api-change-app-user-requester-delete-20260905130127"Utilice la misma ruta para eliminar un agente, un observador o el solicitante y cambie relationshipType. También puede eliminar un observador mediante batch, con un array add vacío y una entrada en remove.
Cambios - archivos
Un archivo cargado en un cambio tiene su propio identificador y metadatos. La carga requiere el ETag actual, una clave de idempotencia nueva y una solicitud multipart/form-data:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/files?relationshipType=documentation" \
--header "Accept: application/json, application/problem+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-change-file-one-20260905130127" \
--form "[email protected];type=text/plain"Una carga correcta devuelve 201 Created con el identificador y los metadatos del archivo. Lea la lista de archivos así:
curl --request GET "$BASE_URL/api/v1/changes/$CHANGE_ID/files?page=1&pageSize=100" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Descargue el contenido como datos binarios y guárdelo en un archivo:
export FILE_ID="FILE_UUID"
curl --request GET "$BASE_URL/api/v1/changes/$CHANGE_ID/files/$FILE_ID/content" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--output downloaded-change-file.binPuede adjuntar un archivo existente a otro cambio. En ese caso, el ETag pertenece al cambio de destino:
curl --request POST "$BASE_URL/api/v1/changes/OTHER_CHANGE_UUID/files/$FILE_ID?relationshipType=manual" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "OTHER_CHANGE_ETAG"' \
--header "Idempotency-Key: public-api-change-file-attach-20260905130127"Elimine un archivo con DELETE /api/v1/changes/{id}/files/{fileId}. La operación devuelve 200 OK si finaliza correctamente. Después de cargar, adjuntar o eliminar, actualice el ETag del cambio y la lista de archivos.
curl --request DELETE "$BASE_URL/api/v1/changes/$CHANGE_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-change-file-delete-20260905130127"Cambios - fijar, marcar como spam y reabrir
Fijar, marcar como spam y reabrir son acciones independientes. Cada una requiere el If-Match actual y una Idempotency-Key nueva.
Fijar un cambio:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/pin" \
--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-change-pin-20260905130127" \
--data-raw '{"pin":2}'Para quitar la fijación, utilice la misma ruta con null, si el esquema y los permisos lo permiten:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/pin" \
--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-change-unpin-20260905130127" \
--data-raw '{"pin":null}'Marcar como spam y deshacer la marca:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/spam" \
--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-change-spam-20260905130127" \
--data-raw '{"isSpam":true}'
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/spam" \
--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-change-spam-undo-20260905130127" \
--data-raw '{"isSpam":false}'Reabrir un cambio cerrado:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_ID/reopen" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "CURRENT_ETAG"' \
--header "Idempotency-Key: public-api-change-reopen-20260905130127"Después de cada acción, vuelva a leer el cambio y guarde el ETag nuevo. Los ámbitos necesarios son respectivamente changes:pin:write, changes:spam:write y changes:reopen:write.
Cambios - valoración y escalado
Guarde una valoración mediante un endpoint independiente. Puede incluir una solicitud de escalado:
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_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-change-rating-20260905130127" \
--data-raw '{
"rating": 4,
"feedback": "Valoración enviada por la integración",
"isEscalationRequested": true,
"escalationRequestReason": "Solicitud de escalado mediante la API pública"
}'Para guardar la valoración se necesita changes:rating:write y para incluir una solicitud de escalado, changes:escalation:write. Utilice un valor de valoración admitido por la API. Después de guardarla, lea campos técnicos como rating, feedback, las fechas de valoración y escalationRequestReason.
Si no necesita escalar, omita isEscalationRequested y escalationRequestReason. No envíe una solicitud de escalado sin explicar el motivo.
Cambios - aprobación y decisión
Cree la aprobación como un objeto approval independiente y relaciónela con el cambio. Necesita los ámbitos del módulo de aprobaciones y el identificador de la persona que debe tomar la decisión:
export APPROVER_ID="USER_UUID"
curl --request POST "$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-change-approval-create-20260905130127" \
--data-raw '{
"itemType": "approval",
"approverId": "USER_UUID",
"attributes": {
"customId": "PUBLIC-API-CHANGE-20260905130127-APPROVAL",
"category": "Public API",
"description": "Aprobación del cambio"
},
"relationships": [
{
"targetId": "CHANGE_UUID",
"targetDataSet": "changes",
"targetItemType": "change"
}
]
}'La persona indicada en approverId puede tomar la decisión mediante la ruta del cambio. APPROVAL_ID es el identificador de la aprobación, no el de un usuario:
export APPROVAL_ID="APPROVAL_UUID"
curl --request POST "$BASE_URL/api/v1/changes/$CHANGE_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: "CURRENT_ETAG"' \
--header "Idempotency-Key: public-api-change-approval-decision-20260905130127" \
--data-raw '{
"approve": true,
"remark": "Aprobado mediante la API pública de Changes."
}'Para rechazarla, envíe approve con el valor false y un comentario propio. Después de la decisión, lea la aprobación y compruebe su estado y la fecha de decisión. A continuación, actualice el cambio porque la decisión puede modificar su ETag y el estado del proceso.
Cambios - eliminación de un registro
Vuelva a leer el cambio antes de eliminarlo y utilice su ETag actual:
curl --request DELETE "$BASE_URL/api/v1/changes/$CHANGE_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: "CURRENT_ETAG"' \
--header "Idempotency-Key: public-api-change-delete-20260905130127"Después de 200 OK, envíe un GET para el mismo UUID. Espere un 404 con el código change_not_found o el código correspondiente al registro. Para comprobar la sincronización, haga un listado filtrado por customId y confirme que totalItems sea cero.
La eliminación no debe utilizarse para archivar el historial. Antes de realizarla en producción, compruebe la política de conservación, las relaciones y los requisitos de auditoría. Si el registro debe permanecer en el historial, cambie su estado en lugar de eliminarlo.
Cambios - errores, límites y seguridad
Los errores utilizan el formato Problem Details application/problem+json. Ejemplo:
{
"type": "https://docs.codenica.com/errors/change_not_found",
"title": "No se encontró el cambio.",
"status": 404,
"detail": "El cambio no existe o está fuera del ámbito de acceso del solicitante.",
"instance": "/api/v1/changes/PUBLIC_CHANGE_UUID",
"code": "change_not_found",
"requestId": "request-id-from-response"
}En la lógica de integración, utilice principalmente status y code. El campo detail está destinado a las personas y su texto puede cambiar.
Lea X-RateLimit-Limit y X-RateLimit-Remaining. Después de 429, aplique backoff y respete Retry-After cuando aparezca. No intente eludir los límites creando más claves o aumentando el paralelismo. Registre el método, el endpoint, el estado y requestId, pero nunca el Client Secret ni las cabeceras completas de autenticación.
Cambios - orden recomendado de integración
- Establezca
BASE_URLpara la instalación Cloud u On-Premise correcta. - Cree una clave independiente en Ajustes - API - API Keys y seleccione los ámbitos mínimos.
- Guarde el Client ID y el Client Secret en un almacén seguro.
- Envíe
GET /api/v1/contexty compruebe la base, los ámbitos y los límites. - Obtenga
GET /api/v1/changes/schemay los valores de los campos utilizados por la integración. - Lea la lista de cambios o cree uno mediante
POSTcon unaIdempotency-Keyúnica. - Guarde el UUID del cambio y su ETag.
- Actualice el ETag antes de cada modificación y utilice una clave de idempotencia nueva.
- Añada relaciones, usuarios y archivos solo después de comprobar el catálogo de destinos del esquema.
- Ejecute por separado las acciones de workflow y las decisiones de aprobación, y lea el estado nuevo después de cada una.
- Ante un
412, lea el registro, resuelva el conflicto y repita la operación de forma consciente. - En los batch, compruebe cada elemento, porque un error parcial no tiene por qué revertir los éxitos.
- Gestione
429, guarderequestIdsin secretos y elimine la clave cuando la integración deje de utilizarse.
Este flujo permite sincronizar cambios planificados con otro sistema sin depender de la estructura interna de la base de datos. Si cambia la configuración de campos, la dirección de la instalación o los ámbitos de la clave, vuelva a leer el contexto y el esquema.
