Los tickets en Codenica API
Para trabajar con tickets a través de la API, empieza creando una clave API en los ajustes de Codenica. Si todavía no la has creado, abre en una pestaña nueva el artículo Codenica API - introducción. Allí se explican la creación de claves, los límites de licencia y las reglas de autenticación comunes de la API.
Un ticket es un objeto de Service Desk. Además de datos básicos como el asunto, la descripción y el solicitante, puede incluir prioridad, impacto, urgencia, gravedad, estado, datos de SLA, información de resolución, relaciones con otros objetos y archivos. La API también ofrece acciones propias de los tickets: fijarlos, marcarlos como spam, reabrirlos, valorarlos, solicitar una escalación y tomar una decisión de aprobación.
Los ejemplos utilizan los nombres técnicos de los campos y las rutas porque esos son los valores exactos que debes enviar en las solicitudes. Sustituye los textos de ejemplo por los datos de tu aplicación.
Tickets - dirección de la API
Todas las operaciones sobre tickets se realizan en esta dirección:
{BASE_URL}/api/v1/ticketsEn Codenica Cloud utiliza la dirección pública asignada a tu instalación. En el ejemplo siguiente se utiliza una dirección ficticia de empresa:
https://tu-empresa.codenica.com/api/v1/ticketsEn una instalación On-Premise, la dirección predeterminada registrada por Codenica Discovery es:
http://codenica.local:5150/api/v1/ticketsSi el administrador ha publicado la instalación con otra dirección, utiliza exactamente esa dirección, por ejemplo:
https://api.tu-empresa.example/api/v1/ticketsUtiliza localhost solo cuando la aplicación que realiza la integración se ejecuta en el mismo ordenador que la API. No añadas tenantId a las solicitudes. La base de datos correcta se selecciona a partir de la dirección a la que te conectas.
Tickets - clave API y límites de licencia
Crea la clave en Codenica, en Ajustes - API - API Keys. El secreto solo se muestra una vez, justo después de crear o rotar la clave. Guarda inmediatamente ambos valores en el almacén seguro de secretos utilizado por la integración.
El número de claves depende de la licencia asignada a la instalación:
Lo recomendable es crear una clave independiente para cada integración y entorno, por ejemplo una para producción, otra para pruebas y otra para automatización. Al crearla, selecciona solo los ámbitos de permisos que necesita esa conexión. La clave utilizada en este artículo debe tener como mínimo tickets:read, tickets:write y los demás ámbitos necesarios para las operaciones previstas.
Tickets - autenticación y solicitudes seguras
La integración se autentica con dos cabeceras. No necesita el JWT del administrador ni las cookies del panel de Codenica.
export BASE_URL="https://tu-empresa.codenica.com"
export CLIENT_ID="cna_example"
export CLIENT_SECRET="cns_example"
curl --request GET "$BASE_URL/api/v1/tickets?page=1&pageSize=25" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"No incluyas la clave en el código de la aplicación, en un repositorio, en los registros ni en los mensajes de error. Los valores CLIENT_ID y CLIENT_SECRET de los ejemplos son simbólicos. En producción, léelos desde variables de entorno o desde un almacén de secretos específico.
La respuesta de la API incluye el identificador de la solicitud en meta.requestId. Consérvalo en los registros técnicos porque ayuda a localizar una solicitud concreta durante el diagnóstico. No guardes el secreto de la clave junto con ese identificador.
Tickets - comprobar el contexto de conexión
Antes de realizar la primera operación sobre tickets, comprueba que la dirección, la clave y los ámbitos están configurados correctamente. El endpoint de contexto devuelve, entre otros datos, la versión de la API, el identificador de la base de datos, la identidad del emisor, los ámbitos y las capacidades disponibles para la clave.
curl --request GET "$BASE_URL/api/v1/context" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"En una respuesta válida, comprueba:
data.apiVersion- debe indicar la versiónv1;data.contractVersion- la versión del contrato utilizada por la integración;data.tenant.idydata.tenant.resolvedDomain- la base de datos y la dirección reconocida;data.caller.authentication- el valorapi_key;data.caller.scopes- los ámbitos asignados a la clave;data.capabilities.resources- la presencia del recursotickets;- los límites de páginas, operaciones por lotes y solicitudes por minuto.
Si falta un ámbito en este punto, cambia los permisos de la clave en los ajustes o crea una clave nueva. No intentes enviar los ámbitos dentro de la propia solicitud.
Tickets - ámbitos de permisos
Para gestionar tickets de forma completa se necesitan los siguientes ámbitos:
tickets:read
tickets:write
tickets:delete
tickets:schema
tickets:stats
tickets:relationships:read
tickets:relationships:write
tickets:users:read
tickets:users:write
tickets:files:read
tickets:files:write
tickets:technical:read
tickets:technical:write
tickets:pin:write
tickets:spam:write
tickets:reopen:write
tickets:rating:write
tickets:escalation:write
tickets:approval:writeNo todas las integraciones necesitan el conjunto completo. Una integración de solo lectura puede utilizar tickets:read; para leer el esquema, las estadísticas y los valores de los diccionarios, añade según sea necesario tickets:schema y tickets:stats. La lectura de relaciones, usuarios y archivos requiere los ámbitos correspondientes :relationships:read, :users:read y :files:read.
Si vas a utilizar decisiones de aprobación de tickets, necesitas tickets:approval:write. Si la integración también crea y gestiona por sí misma objetos de aprobación, necesita además los ámbitos de approvals. No concedas permisos de escritura solo porque resulten cómodos durante la primera prueba.
Tickets - esquema y campos
El esquema permite consultar la configuración actual de los campos de tu base de datos. Es especialmente importante para los valores de diccionario, como estado, prioridad, impacto, urgencia, gravedad, tipo y categoría.
curl --request GET "$BASE_URL/api/v1/tickets/schema" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"En la respuesta, busca los campos marcados como required, writable, technical y hasAutoGeneration. Para crear un ticket se necesitan como mínimo subject y requesterEmail. Guarda los demás campos solo cuando estén disponibles y sean necesarios para tu flujo de trabajo.
subject, requesterEmail, description, commentstype, category, priority, impact, urgency, severity, statuslocation, department, teams, servicesexternalNumber, referenceNumber, link, tagsLos campos sla, rating, feedback, pin, isSpam y las fechas relacionadas con las acciones los gestiona el sistema o endpoints específicos. No supongas que pueden modificarse con un PATCH normal.
Tickets - rutas principales
Las rutas utilizadas con más frecuencia son:
GET /api/v1/tickets- lista de tickets;GET /api/v1/tickets/{id}- un ticket;POST /api/v1/tickets- crear un ticket;PATCH /api/v1/tickets/{id}- actualización parcial;DELETE /api/v1/tickets/{id}- eliminar;GET /api/v1/tickets/schema- esquema de campos;GET /api/v1/tickets/stats- estadísticas;GET /api/v1/tickets/values- valores utilizados en los filtros;POST /api/v1/tickets:batch- varias operaciones en una solicitud.
Las relaciones, los usuarios, los archivos y las acciones tienen rutas independientes que se describen más adelante. Esta separación permite conceder a la integración exactamente los permisos que necesita.
Tickets - listas y paginación
Lee la lista con GET. Conviene indicar siempre el número y el tamaño de la página, aunque al principio esperes pocos registros.
curl --request GET "$BASE_URL/api/v1/tickets?page=1&pageSize=25" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"La respuesta contiene un objeto data con items, page, pageSize, totalItems, totalPages y hasNextPage. Cuando hasNextPage sea true, solicita la página siguiente.
curl --request GET "$BASE_URL/api/v1/tickets?page=2&pageSize=25&sort=dateUpdated&direction=desc" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"La ordenación depende del campo admitido por la API. Para sincronizar datos, ordena por dateUpdated de forma ascendente o descendente y guarda el último registro procesado.
Tickets - búsqueda y filtros
La API permite combinar la búsqueda de texto con filtros de campos. Utiliza search para una búsqueda general y filter para indicar un operador y un valor.
curl --get "$BASE_URL/api/v1/tickets" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=25" \
--data-urlencode "search=VPN" \
--data-urlencode "filter=status:eq:Open" \
--data-urlencode "filter=priority:eq:High" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Ejemplos de filtros útiles para trabajar con tickets:
filter=status:eq:Closed- tickets cerrados;filter=priority:eq:High- prioridad alta;filter=subject:contains:VPN- asunto que contiene el texto indicado;filter=description:notEmpty:- tickets con descripción;filter=isSpam:eq:false- tickets que no están marcados como spam.
Obtén el estado, la prioridad y los demás valores de diccionario de la configuración de tu base de datos mediante el endpoint values. No supongas que todas las instalaciones utilizan los mismos nombres.
Tickets - campos de respuesta y ampliaciones
Para una lista básica, conserva el conjunto de campos predeterminado. Solicita campos adicionales con fields y datos relacionados con include.
curl --get "$BASE_URL/api/v1/tickets" \
--data-urlencode "fields=id,itemType,subject,status,priority,requesterEmail,dateUpdated" \
--data-urlencode "include=relationships,users,files" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=10" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Utiliza fields=* cuando necesites el modelo completo. Las ampliaciones pueden requerir ámbitos adicionales. Si la integración no tiene acceso a usuarios, relaciones o archivos, elimina el elemento correspondiente de include o concede el permiso adecuado.
Al sincronizar, presta atención a id, itemType, attributes y meta. El identificador del objeto es estable, mientras que meta.etag se utiliza para realizar actualizaciones seguras.
Tickets - estadísticas y valores de campos
Las estadísticas resultan útiles, por ejemplo, para contar tickets por prioridad. No modifican los datos.
curl --get "$BASE_URL/api/v1/tickets/stats" \
--data-urlencode "field=priority" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Puedes solicitar los valores de un campo con una búsqueda opcional:
curl --get "$BASE_URL/api/v1/tickets/values" \
--data-urlencode "field=priority" \
--data-urlencode "search=High" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Antes de enviar un ticket nuevo, consulta los valores disponibles en esa misma base de datos. Así evitarás que la integración envíe un valor que la configuración local no reconoce.
Tickets - crear un ticket
Crea un ticket nuevo con el método POST. El conjunto mínimo útil incluye itemType, un asunto y la dirección de correo del solicitante. Elige el resto de los datos según tu proceso de soporte.
curl --request POST "$BASE_URL/api/v1/tickets" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: ticket-create-ERP-2026-001" \
--data '{
"itemType": "ticket",
"attributes": {
"customId": "ERP-TICKET-2026-001",
"subject": "VPN no disponible para el departamento financiero",
"requesterEmail": "[email protected]",
"description": "La conexión VPN se interrumpe después de unos minutos de uso.",
"comments": "Ticket creado desde el sistema ERP.",
"source": "ERP",
"type": "Incident",
"category": "Network",
"status": "Open",
"priority": "High",
"impact": "Department",
"urgency": "High",
"severity": "Major",
"services": "VPN",
"tags": "vpn;finance;integration",
"externalNumber": "ERP-4581",
"referenceNumber": "INC-2026-001",
"currency": "PLN",
"estimatedCost": 150.00
}
}'Los valores de diccionario de este ejemplo son ilustrativos. Sustitúyelos por los valores devueltos por el esquema y por el endpoint values de tu base de datos. Una creación correcta devuelve 201 Created, data.id y el ETag actual en la cabecera y en data.meta.etag. Guarda estos valores porque los necesitarás en las operaciones siguientes.
Tickets - idempotencia de las operaciones de escritura
Toda solicitud que cree, modifique o elimine datos debe incluir una cabecera Idempotency-Key única. Esto evita crear dos veces el mismo ticket si la aplicación repite una solicitud después de una interrupción de conexión.
curl --request POST "$BASE_URL/api/v1/tickets" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: ticket-create-ERP-2026-001" \
--data '{
"itemType": "ticket",
"attributes": {
"subject": "VPN no disponible para el departamento financiero",
"requesterEmail": "[email protected]"
}
}'Repetir la misma solicitud con el mismo método, ruta, contenido y clave de idempotencia debe devolver el mismo registro. Una operación nueva debe utilizar una clave nueva. No utilices una clave permanente para todos los tickets.
Guarda la clave de idempotencia en la integración junto con el estado de procesamiento. Si cambias el contenido de la solicitud, utiliza una clave nueva aunque se refiera al mismo ticket.
Tickets - leer un registro
Después de crear o encontrar el identificador del ticket, léelo mediante su UUID:
export TICKET_ID="TICKET_UUID"
curl --get "$BASE_URL/api/v1/tickets/$TICKET_ID" \
--data-urlencode "fields=*" \
--data-urlencode "include=relationships,users,files" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Lee data.attributes y data.meta.etag de la respuesta. El ETag puede cambiar después de modificar datos, relaciones, usuarios o archivos, y después de ejecutar una acción. Antes de una operación de escritura, utiliza el ETag actual y no un valor guardado de una lectura anterior.
Tickets - edición y protección con ETag
Realiza las actualizaciones con PATCH. Envía solo los campos que quieras cambiar y el ETag leído de la versión actual del ticket.
curl --request PATCH "$BASE_URL/api/v1/tickets/$TICKET_ID" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-update-ERP-2026-001" \
--data '{
"attributes": {
"status": "In Progress",
"priority": "High",
"comments": "El equipo de redes está investigando la interrupción de la sesión VPN.",
"resolutionSummary": ""
}
}'Una actualización correcta devuelve 200 OK y un ETag nuevo. Cambia los campos gestionados por acciones, como isSpam, pin y rating, mediante sus endpoints específicos. No intentes saltarte esta separación con un PATCH normal.
Cuando actualices un plazo, un coste o datos de integración, conserva la codificación de tipos que devuelve el esquema. Envía las fechas en formato ISO 8601 y los valores decimales como números JSON.
Tickets - ETag obsoleto o ausente
La API bloquea una escritura basada en una versión obsoleta del registro. Si dos procesos trabajan al mismo tiempo, el segundo no puede sobrescribir los cambios del primero sin un reintento consciente.
Un ETag obsoleto devuelve 412 Precondition Failed con el código if_match_failed. Si falta la cabecera If-Match, devuelve 428 Precondition Required con el código if_match_required.
curl --request PATCH "$BASE_URL/api/v1/tickets/$TICKET_ID" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-update-retry-ERP-2026-001" \
--data '{
"attributes": {
"comments": "Reintentando la actualización después de leer la versión actual."
}
}'Después de recibir uno de estos errores, vuelve a leer el ticket, comprueba si el cambio sigue siendo necesario y envíalo con un ETag nuevo y una clave de idempotencia nueva. No desactives la protección ETag en la integración.
Tickets - relaciones con objetos
Un ticket puede vincularse con los objetos visibles en el esquema de relaciones, como activos, documentos, otros tickets, cambios, problemas, versiones, notas, aprobaciones, tareas de trabajo y solicitudes. El catálogo disponible puede depender de la configuración y de los ámbitos de la clave, así que comprueba relationshipTargets en el esquema antes de guardar una relación.
Leer las relaciones:
curl --request GET "$BASE_URL/api/v1/tickets/$TICKET_ID/relationships?page=1&pageSize=50" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Una relación con un activo puede añadirse así:
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/relationships" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-relation-asset-ERP-2026-001" \
--data '{
"targetId": "ASSET_UUID",
"targetDataSet": "assets",
"targetItemType": "computer",
"relationshipType": "related"
}'Para añadir varias relaciones en una sola solicitud, utiliza la operación por lotes:
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/relationships:batch" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-relationship-batch-ERP-2026-001" \
--data '{
"add": [
{
"targetId": "OTHER_TICKET_UUID",
"targetDataSet": "tickets",
"targetItemType": "ticket",
"relationshipType": "related"
},
{
"targetId": "DOCUMENT_UUID",
"targetDataSet": "documents",
"targetItemType": "document",
"relationshipType": "related"
}
],
"remove": []
}'El valor de targetItemType debe coincidir con el tipo real del objeto indicado. El ETag del ticket cambia después de añadir o eliminar una relación. Elimina la relación mediante el nombre de la colección y el identificador del objeto, normalmente con el parámetro de consulta relationshipType:
curl --request DELETE "$BASE_URL/api/v1/tickets/assets/$ASSET_ID?relationshipType=related" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-relation-remove-ERP-2026-001"Tickets - relaciones con usuarios y clientes
Las relaciones con usuarios están separadas de las relaciones con objetos. Puedes asignar un empleado como agent, añadir un observador con el tipo watcher, indicar al usuario solicitante con appUserRequester o indicar un cliente con clientRequester.
Lista de relaciones con usuarios:
curl --get "$BASE_URL/api/v1/tickets/$TICKET_ID/user-relationships" \
--data-urlencode "relationshipType=agent" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Asignar un empleado:
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/user-relationships" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-agent-ERP-2026-001" \
--data '{
"targetId": "USER_UUID",
"targetDataSet": "users",
"relationshipType": "agent"
}'Puedes cambiar varias relaciones con usuarios en una sola solicitud:
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/user-relationships:batch" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-user-relationship-batch-ERP-2026-001" \
--data '{
"add": [
{
"targetId": "WATCHER_USER_UUID",
"targetDataSet": "users",
"relationshipType": "watcher"
}
],
"remove": []
}'Añadir un observador utiliza el mismo formato, pero con el tipo watcher. Guarda una relación con un cliente usando targetDataSet igual a clients y el tipo clientRequester. El ámbito tickets:users:write no da acceso a todos los usuarios ni evita sus permisos.
Para eliminar una asignación hay que indicar el tipo de relación en el parámetro de consulta:
curl --request DELETE "$BASE_URL/api/v1/tickets/$TICKET_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: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-agent-remove-ERP-2026-001"Tickets - archivos
Los archivos tienen sus propias rutas. Para subir un archivo necesitas el ETag actual del ticket, una cabecera de idempotencia y una solicitud multipart.
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/files?relationshipType=documentation" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-file-ERP-2026-001" \
--form "[email protected];type=text/plain"Una subida correcta devuelve 201 Created y los datos del archivo, incluido su identificador y la ruta downloadUrl. Lee la lista de archivos así:
curl --request GET "$BASE_URL/api/v1/tickets/$TICKET_ID/files?page=1&pageSize=50" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"El contenido del archivo es binario, por lo que debes guardar la respuesta en un archivo:
curl --request GET "$BASE_URL/api/v1/tickets/$TICKET_ID/files/$FILE_ID/content" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--output archivo-descargado.txtPuedes asociar un archivo existente a otro ticket mediante POST /api/v1/tickets/{id}/files/{fileId}. Antes de eliminarlo, comprueba el identificador del archivo y utiliza el ETag del ticket. Elimina un archivo con DELETE /api/v1/tickets/{id}/files/{fileId}. Los tickets no tienen una acción independiente para seleccionar un archivo principal.
Asociar un archivo existente a otro ticket:
curl --request POST "$BASE_URL/api/v1/tickets/$OTHER_TICKET_ID/files/$FILE_ID?relationshipType=manual" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $OTHER_TICKET_ETAG" \
--header "Idempotency-Key: ticket-file-attach-ERP-2026-001"Eliminar un archivo del ticket actual:
curl --request DELETE "$BASE_URL/api/v1/tickets/$TICKET_ID/files/$FILE_ID" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-file-delete-ERP-2026-001"Tickets - fijar, marcar como spam y reabrir
Algunas propiedades de los tickets se cambian mediante acciones específicas. Cada acción requiere el ETag actual y su propia clave de idempotencia.
Fijar un ticket:
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/pin" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-pin-ERP-2026-001" \
--data '{"pin":2}'Quita la fijación enviando null:
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/pin" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-unpin-ERP-2026-001" \
--data '{"pin":null}'Marcar un ticket como spam:
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/spam" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-spam-ERP-2026-001" \
--data '{"isSpam":true}'Quita la marca mediante la misma ruta con el contenido {"isSpam":false}. Para reabrir un ticket cerrado:
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/reopen" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-reopen-ERP-2026-001"Estas operaciones requieren, según corresponda, tickets:pin:write, tickets:spam:write o tickets:reopen:write. Después de cada acción correcta, guarda el ETag nuevo que devuelve la API.
Tickets - valoración y solicitudes de escalación
Después de gestionar un ticket, puedes guardar una valoración y el comentario de la persona que lo evalúa. La valoración va de 0 a 5.
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/rating" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-rating-ERP-2026-001" \
--data '{
"rating": 4,
"feedback": "El problema se resolvió y la comunicación con el equipo fue fluida.",
"isEscalationRequested": true,
"escalationRequestReason": "Solicito una revisión adicional de la estabilidad de la conexión VPN."
}'Si solo guardas una valoración, omite los campos de escalación. Si incluyes una solicitud de escalación, también necesitas tickets:escalation:write. La valoración por sí sola requiere tickets:rating:write. Después de guardarlos, los valores aparecen como campos de solo lectura, entre ellos rating, feedback, dateRating, dateFeedback, dateEscalationRequest y escalationRequestReason.
Tickets - decisión de aprobación
Si un ticket tiene una aprobación asignada, el aprobador designado puede tomar la decisión directamente mediante la ruta del ticket. Necesita el ámbito tickets:approval:write y debe estar asignado a esa aprobación.
export APPROVAL_ID="APPROVAL_UUID"
curl --request POST "$BASE_URL/api/v1/tickets/$TICKET_ID/approvals/$APPROVAL_ID" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-approval-ERP-2026-001" \
--data '{
"approve": true,
"remark": "El cambio se ha revisado y puede desplegarse."
}'Para rechazarlo, envía approve con el valor false y tu propio comentario. APPROVAL_ID es el identificador de la aprobación, no el de un usuario. Si la integración crea las aprobaciones por sí misma, utiliza el recurso independiente approvals, indica el aprobador y vincula la aprobación al ticket mediante una relación. Después de la decisión, vuelve a leer el ticket y guarda el ETag nuevo.
Tickets - operaciones por lotes, eliminación y errores
Puedes enviar varias operaciones mediante POST /api/v1/tickets:batch. Cada elemento describe una operación create, update o delete. Una actualización y una eliminación requieren su propio ifMatch, porque cada registro puede tener una versión diferente.
curl --request POST "$BASE_URL/api/v1/tickets:batch" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: tickets-batch-ERP-2026-001" \
--data '{
"items": [
{
"operation": "create",
"create": {
"itemType": "ticket",
"attributes": {
"subject": "Sin acceso a la impresora",
"requesterEmail": "[email protected]",
"description": "La impresora no responde a las solicitudes de impresión.",
"source": "ERP"
}
}
},
{
"operation": "update",
"id": "TICKET_UUID",
"ifMatch": "\"CURRENT_ETAG\"",
"update": {
"attributes": {
"priority": "Normal"
}
}
}
]
}'La respuesta puede tener el estado 200 o 207 Multi-Status cuando algunos elementos fallen. Procesa cada elemento de la respuesta según su índice, operación, estado y campo error. No supongas que el error de un elemento revierte todos los demás.
Para eliminar un ticket primero debes leer su ETag actual:
curl --request DELETE "$BASE_URL/api/v1/tickets/$TICKET_ID" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "If-Match: $TICKET_ETAG" \
--header "Idempotency-Key: ticket-delete-ERP-2026-001"Después de recibir 200 OK, verifica con otra lectura que el ticket devuelve 404 y el código ticket_not_found. Entre las respuestas de error más habituales están: 400 para datos no válidos, 401 para autenticación ausente, 403 para un ámbito que falta, 404 para un registro inexistente, 409 para un conflicto, 412 para un ETag obsoleto, 428 para un ETag o una clave de idempotencia ausente y 429 cuando se supera el límite. Una respuesta de problema incluye, entre otros campos, title, detail, code y requestId. Guarda esta información en los registros y repite solo las operaciones que puedan repetirse de forma segura.
Un orden práctico de trabajo es: comprobar el contexto, leer el esquema y los valores, leer o crear un ticket, guardar su ETag, realizar los cambios con idempotencia y el ETag actual y leer el nuevo estado después de cada acción. Al final, verifica la sincronización con una lista filtrada por customId o externalNumber.
