Files
balam/planeacion/Investigacion-API-Jira.md
T
JohannVelazquez 980baf0a0a Documenta la API de Jira FAC y protege su token
Consolida los hallazgos y decisiones pendientes para continuar el desarrollo sin exponer credenciales.
2026-08-01 12:38:39 -06:00

22 KiB
Raw Blame History

Investigación de la API de Jira — qué probar exactamente

Fecha: 30-jul-2026 Propósito: lista cerrada de pruebas y preguntas para habilitar la integración Jira → cotización BIND (estimada en ~10 h, REGISTRO #51). Documento de trabajo interno; sirve también como briefing para el agente/chat especializado en la API de Jira.

Estado validado (30-jul):

  • Sitio: https://balam-jsm-temp.atlassian.net. El token regenerado de Pedro, usado con Basic auth y pedro.ayala@balamtalentoestrategico.com, respondió 200 a GET /rest/api/3/myself.
  • Facturación es el proyecto JSM FAC (projectId: 10034, serviceDeskId: 35), de tipo service_desk y estilo classic (company-managed).
  • La búsqueda de FAC devolvió 66 tickets. La API vigente es GET /rest/api/3/search/jql, con paginación por nextPageToken; el endpoint clásico /rest/api/3/search responde 410 Gone.
  • Estatus confirmados: Open, En proceso de facturación, En espera por colaborador, En validación nacional, En validación extranjera, Facturado y Cancelado. No se observó un estatus llamado “Resuelto”.
  • Límites de consumo ya aclarados por Pedro (sin tope mensual; 3 límites de velocidad; telemetría solo en headers X-RateLimit-*).
  • Pendiente antes de escribir código productivo: decisión de negocio sobre el estatus disparador, definición de qué request type debe observarse, fuente de monto y conceptos para la cotización, y aprobación explícita de cada prueba de escritura.

Bloque 0 — Acceso autenticado

El 401 del 29-jul quedó explicado por la combinación de token previo y datos de conexión incompletos. Pedro confirmó el correo, regeneró el token y compartió el dominio del sitio.

Configuración que funcionó:

GET https://balam-jsm-temp.atlassian.net/rest/api/3/myself
Authorization: Basic base64(pedro.ayala@balamtalentoestrategico.com:<token>)
Accept: application/json

El resultado fue HTTP 200. Por tanto, para esta integración se usará la API directa del sitio con Basic auth; no hay evidencia de que se requiera una ruta api.atlassian.com/ex/jira/{cloudId}.

Prueba canónica de auth (la primera que debe correrse siempre):

GET /rest/api/3/myself

Interpretación de la respuesta:

  • 200 → auth OK; además devuelve accountId (identidad con la que la plataforma va a escribir — dato de gobierno, ver Bloque 7).
  • 401 → credencial inválida/inactiva o esquema mal armado.
  • 403 → credencial VÁLIDA pero sin permiso → problema de permisos, no de token. Distinguir 401 de 403 es el diagnóstico más barato que existe.

⚠️ Registrar siempre los headers de la respuesta 401 completos. Ahí vive la pista (WWW-Authenticate, X-Seraph-LoginReason, X-Failure-Category).


Bloque 1 — Topología: Jira Service Management confirmado

FAC está confirmado como Jira Service Management (JSM). Por ello la integración requiere dos familias de API:

API Para qué Cuándo usarla
/rest/api/3/... Issues genéricos: JQL, campos, transiciones, adjuntos, changelog Lectura/sync, transiciones, trazabilidad
/rest/servicedeskapi/... Requests de portal: request types, campos del formulario, aprobaciones, SLA, comentarios públicos vs internos Crear tickets como los crea un humano; leer aprobaciones y SLA

Resultados:

GET /rest/api/3/project/FAC

projectTypeKey: service_desk, style: classic, id: 10034.

GET /rest/servicedeskapi/servicedesk

→ FAC corresponde a serviceDeskId: 35.

Request types disponibles:

requestTypeId Nombre
84 Bajas
83 Facturación adicional
389 Automatización
12 Facturación

Contratos ya consultados:

Request type Hallazgo
Bajas (84) Exige Empresa origen, Summary, Cálculo de Finiquito // VoBo de Finiquito (adjunto), Nombre del Cliente, Nombre del Colaborador, Fecha de la Baja y Motivo de la Baja.
Facturación adicional (83) Exige Empresa origen, Summary, Cliente Nuevo, Nombre del Cliente, cotización/CSF adjuntos, Tipo de Moneda, Días de Crédito, Periodo de Incidencias, Facturación recurrente y Periodo de recurrencia. Es el contrato más completo, pero no expone monto ni conceptos como campos estructurados.
Automatización (389) Solo exige Summary.
Facturación (12) Solo exige Summary.

Implicación: la integración no debe asumir que “Facturación” (12) es el formulario origen de datos; Facturación adicional (83) es el candidato más completo, pero todavía no basta para crear una cotización en BIND. Falta confirmar con Balam qué request type entra en la automatización y si monto/conceptos se leerán de la cotización adjunta o se incorporarán como campos de Jira. Mantener una cotización adjunta como entrada mientras la integración genera otra en BIND puede duplicar el proceso.


Bloque 2 — Modelo de datos del ticket FAC (el mapeo) 🔴

Esto es lo que decide si la integración es de 10 h o de 25. La pregunta de fondo: ¿los datos de facturación vienen en campos estructurados o en texto libre? Si vienen en texto libre, hay que negociar campos nuevos con Pedro o meter parsing frágil.

Lo que la plataforma necesita de cada ticket para armar una cotización en BIND:

Dato requerido Por qué Qué verificar
Cliente Match contra Clients de BIND (por RFC o nombre normalizado) ¿Campo custom? ¿Lista desplegable? ¿Texto libre? ¿Trae RFC?
Monto y moneda Cotización BIND; la cartera jamás mezcla monedas ¿Campo numérico? ¿Viene la moneda separada o embebida en el texto?
Nacional vs internacional Determina PDF+XML (nacional) vs solo PDF (extranjero) ¿Se deduce del cliente o hay campo/etiqueta?
Concepto / descripción Línea de la cotización Ver formato (ver ⚠️ ADF abajo)
Tipo de solicitud adicional / recurrente / baja / headhunting / staff augmentation ¿Request type, issue type, o campo?
Folio FAC-nnn Trazabilidad ticket ↔ cotización ↔ factura (persistir en el modelo) Confirmar formato y estabilidad (ver Bloque 5, ⚠️ moves)
Solicitante / área Auditoría reporter vs requester de JSM (no son lo mismo)
Adjuntos Constancia fiscal, Excel de horas (CEMEX), estado de cuenta Cómo se descargan y con qué auth

Resultados de lectura:

GET /rest/api/3/issue/FAC-98?expand=names,renderedFields

→ caso real de tipo Bajas: cliente Axians, colaborador, fecha y motivo de baja en campos estructurados; una evidencia adjunta; sin descripción. Los valores de texto enriquecido regresan como ADF.

Sigue pendiente una muestra deliberada de facturación nacional, extranjera, recurrente y el caso ACUNTIA (un ticket con Excel de 4048 facturas, REGISTRO #55 punto 6). Esto debe confirmar dónde viven monto y conceptos, cómo se usa la cotización adjunta y si el supuesto contractual de un ticket → una cotización se cumple en los casos reales.

⚠️ ADF (Atlassian Document Format). En Jira Cloud v3, description y los comentarios no son texto plano ni wiki markup: son JSON estructurado. Hay que decidir ya si se parsea ADF o se pide expand=renderedFields (HTML). Y al escribir comentarios/descripciones hay que construir ADF válido, no mandar un string. Es la trampa que más tiempo cuesta si se descubre tarde.

⚠️ Adjuntos: confirmar si content (URL de descarga) requiere el mismo Basic auth y si redirige. Y aplica la misma regla que con BIND: los adjuntos traen datos reales de clientes (constancias, estados de cuenta) — no van a disco del repo ni a documentos.


Bloque 3 — Workflow, estatus y transiciones (el disparador) 🟡

La regla de negocio (qué estatus dispara qué) sigue bloqueada por la definición interna de Balam. Pero el inventario técnico se puede levantar hoy y es justo lo que hace que esa sesión dure 20 minutos en vez de una hora: llegar con la lista real de estatus en pantalla.

Inventario confirmado:

GET /rest/api/3/project/FAC/statuses          → estatus por tipo de issue, con id y statusCategory
Estatus ID Categoría
Open 1 To Do
En proceso de facturación 10305 In Progress
Facturado 10306 Done
En espera por colaborador 10339 In Progress
Cancelado 10372 Done
En validación nacional 10635 In Progress
En validación extranjera 10669 In Progress

Transiciones de lectura confirmadas (son contextuales al estatus actual):

Ticket / estatus actual transitionId Destino
FAC-98 / En proceso de facturación 6 En espera por colaborador
FAC-98 / En proceso de facturación 8 En validación nacional
FAC-98 / En proceso de facturación 9 En validación extranjera
FAC-98 / En proceso de facturación 2 Cancelado
FAC-91 / En validación nacional 2 Cancelado
FAC-89 / Cancelado 12 Open

FAC-97 ya está Facturado y no expone transiciones. Las respuestas consultadas no devolvieron campos obligatorios para las transiciones anteriores. Aun así, no se ejecutará ninguna transición sin la sesión acompañada.

Diagrama de workflow compartido por Balam: confirma la ruta completa y los nombres de transición:

Open --[Iniciar facturación]--> En proceso de facturación
En proceso de facturación --[Pausar actividad]--> En espera por colaborador
En espera por colaborador --[Retomar actividad]--> En proceso de facturación
En proceso de facturación --[Validar documentación nacional]--> En validación nacional
En proceso de facturación --[Validar documentación extranjera]--> En validación extranjera
En validación nacional o extranjera --[Facturación completa]--> Facturado
En validación nacional o extranjera --[Rechazar actividad]--> En proceso de facturación

El diagrama también contempla cancelación desde los estados de trabajo y reapertura; la API confirmó al menos Cancelado --[Reabrir Ticket]--> Open en FAC-89. No existe un estado “Resuelto” en el workflow. El diagrama describe el movimiento del ticket, pero no establece en qué transición se debe crear la cotización BIND. Esa regla debe ser confirmada por Balam: la candidata natural es la entrada a En proceso de facturación mediante Iniciar facturación; Facturado es la confirmación final de que la factura se emitió.

⚠️ Dos trampas conocidas:

  1. Facturado como estatus ≠ campo resolution. En Jira son cosas distintas: un ticket puede estar en Facturado con resolution: null, o cerrarse con resolution: Done. Hay que confirmar cuál de los dos es la señal confiable de “esta factura sí se emitió”, aunque el workflow muestra que Facturado es la salida de Facturación completa.
  2. Las transiciones son contextuales: /transitions solo devuelve las salidas del estado actual, y pueden tener pantallas con campos obligatorios. Probar con expand=transitions.fields para saber si transicionar por API exige llenar algo.

Changelog = la fuente de la detección. expand=changelog da cada cambio de estatus con timestamp y autor. Es el equivalente en Jira del enfoque ya usado con BIND para detectar pagos por transición (ADR-004): la plataforma detecta el cruce de estado, no lo infiere del estado actual. Verificar que el changelog venga completo o si pagina (/rest/api/3/issue/{key}/changelog).


Bloque 4 — Estrategia de sincronización: polling vs webhooks 🟡

El scheduler de la plataforma ya existe (BackgroundService + PeriodicTimer a 15 min). La pregunta es qué le pega a Jira.

a) Búsqueda por JQL — validado. El endpoint clásico GET /rest/api/3/search respondió 410 Gone. La integración debe usar GET /rest/api/3/search/jql, con nextPageToken. La lectura de FAC recuperó 66 tickets con ese mecanismo.

JQL de delta a validar:

project = FAC AND updated >= "-20m" ORDER BY updated ASC

⚠️ updated en JQL tiene granularidad de minuto, no de segundo → el checkpoint necesita ventana de solape (igual que el re-barrido de facturas abiertas de BIND) o se pierden tickets en el borde.

Validar también: fields= para pedir solo lo necesario (menos payload, menos puntos), y el tope real de maxResults.

b) Webhooks. Tres caminos, con dueños distintos:

Opción Quién la configura Nota
Webhook de sitio (admin) Pedro (requiere admin de Jira) El más limpio; exige endpoint público
Regla de Jira Automation con "Send web request" Pedro, sin escribir código La más realista a corto plazo; se puede acotar a FAC y a un estatus
Webhook dinámico vía OAuth app Desarrollo Expiran a los 30 días, hay que refrescarlos

Recomendación: arrancar con polling y dejar el webhook para después. Ningún webhook sirve hasta que exista un endpoint público, y Azure sigue pendiente del lado de Balam. El polling además es reversible y no depende de que Pedro toque su instancia.

c) Rate limits. Ya documentados por Pedro. Lo que falta es verificar en la práctica que los headers X-RateLimit-Limit / Remaining / NearLimit efectivamente vienen en las respuestas (no todos los endpoints los emiten) y capturar un 429 real si se puede, para confirmar Retry-After y RateLimit-Reason.


Bloque 5 — La bandeja padre: de dónde nacen realmente los tickets 🟡

Pedro dijo que procesos que se cierran en RH o Administración General caen en Facturación. Técnicamente eso puede ser cuatro cosas distintas, y cada una se sincroniza diferente:

Mecanismo Cómo detectarlo Implicación
Issue link (RH-45 relacionado con FAC-89) issuelinks en el issue Escuchar FAC basta; el link da contexto
Clon / creación por Automation changelog + campo creator (usuario de automation) Escuchar FAC basta
Subtarea / hijo parent / subtasks Relevante para ACUNTIA (1 ticket ↔ 40 facturas)
Move entre proyectos changelog con cambio del campo project 🔴 La llave del ticket CAMBIA (RH-45 → FAC-89). Cualquier folio persistido se rompe

Prueba: tomar 510 tickets FAC recientes con expand=changelog y clasificar cómo llegaron ahí. Si aparecen moves, hay que persistir el id numérico del issue (inmutable), no solo la llave FAC-nnn — decisión de modelo de datos que conviene tomar antes de escribir la entidad.

Pregunta ligada, ya identificada el 27-jul: ¿basta escuchar FAC o hay que rastrear también el origen en RH/AG?


Bloque 6 — Escritura (CRUD): qué probar, cómo aprobarlo y dónde 🔴

Noe autorizó una prueba de creación en vivo y acompañada. La recomendación es conservar esa condición: el sitio es producción y el token efectivo tiene permisos para crear, editar, transicionar, comentar, adjuntar e incluso borrar tickets en FAC.

Protocolo obligatorio para cualquier prueba de escritura:

  1. Preparar un script idempotente y de una sola operación; sin bucles, sin búsquedas masivas y sin credenciales embebidas.
  2. Compartir el script y el payload de ejemplo con Pedro/Arturo antes de la sesión; documentar endpoint, ticket destino, efecto esperado y reversión.
  3. Acordar el ticket de prueba y una ventana de ejecución. Preferir un proyecto sandbox (FACTEST) o un ticket creado expresamente para la prueba.
  4. Ejecutarlo acompañado, registrar el HTTP status, el issue.id/key y verificar el resultado por API.
  5. No probar DELETE; no es una capacidad necesaria para la plataforma y no es reversible en producción.

Operaciones a validar, en este orden (de menos a más invasivo):

  1. ComentarPOST /rest/api/3/issue/{key}/comment (cuerpo en ADF). ⚠️ En JSM hay comentarios públicos (los ve el cliente) vs internos: POST /rest/servicedeskapi/request/{id}/comment con public: true|false. La plataforma debe escribir SIEMPRE internos. Publicar por error un comentario visible al cliente es el error más caro y menos reversible de este bloque.
  2. AdjuntarPOST /rest/api/3/issue/{key}/attachments. ⚠️ Exige el header X-Atlassian-Token: no-check y multipart/form-data. Sin ese header falla con un error que no explica nada. Es la vía para dejar el PDF/XML como evidencia en el ticket.
  3. TransicionarPOST /rest/api/3/issue/{key}/transitions con el transition.id del Bloque 3.
  4. Crear — decisión real de diseño: POST /rest/api/3/issue (crudo, se salta el request type y el ticket queda "raro" en el portal) vs POST /rest/servicedeskapi/request (respeta request type y se ve como uno normal). Si es JSM, la segunda es la correcta.
  5. EditarPUT /rest/api/3/issue/{key}.
  6. BorrarDELETE /rest/api/3/issue/{key}. Requiere permiso de admin de proyecto. Probablemente ni se tenga ni convenga tenerlo; en producción el borrado no debe ser una capacidad de la plataforma.

🔴 Dónde probar — la recomendación más importante de este documento. La instancia de Pedro es producción, igual que BIND, y ya se pagó el costo de esa restricción una vez. Dos salidas, no excluyentes:

  1. Pedir a Pedro un proyecto de pruebas (p. ej. FACTEST) que replique el workflow de FAC. Barato para él, elimina el riesgo.
  2. Crear un sitio propio y gratuito de Jira Cloud (plan Free, hasta 10 usuarios) con un proyecto JSM. Sirve para desarrollar el cliente, el parser de ADF, la paginación y las transiciones sin tocar nada de Balam ni depender de que respondan. Es el sandbox que BIND nunca tuvo. Contra producción solo se corre lectura y, al final, la prueba acompañada.

Esta segunda opción sigue siendo útil para desarrollar el cliente y probar ADF sin tocar datos de Balam. El 401 ya está resuelto, pero el riesgo de escribir en producción permanece.


Bloque 7 — Gobierno y seguridad 🟡

  • 🔴 propuesta/token-jira.txt NO está en .gitignore (aparece como no rastreado, no como ignorado): un git add . lo commitea al historial. Agregarlo al .gitignore y mover el token a user-secrets / Key Vault. Mismo pendiente que arrastra bind_token_api.txt.
  • Cuenta de servicio vs cuenta personal de Pedro (ya planteado en el borrador de correo del 29-jul): hoy todo lo que la plataforma escriba en Jira queda firmado con el nombre de Pedro, y una rotación suya deja la integración muerta. Verificar con GET /rest/api/3/myself con qué identidad se está actuando.
  • 🔴 Alcance de permisos: validado con GET /rest/api/3/mypermissions para FAC. El token puede navegar, crear, editar, transicionar, comentar, adjuntar y borrar tickets. Es un alcance excesivo para producción; la integración no debe implementar borrado y conviene migrar a una cuenta de servicio con permisos mínimos.
  • Vigencia 27-jul-2027 → dejar registrado el vencimiento y el plan de rotación desde ahora.
  • Datos de clientes en adjuntos y descripciones — misma regla que BIND: nunca a disco del repo ni a documentos compartidos.

Bloque 8 — Preguntas para Pedro / Balam (no se resuelven con la API)

Estas van por correo o en la siguiente sesión; ninguna se contesta probando:

  1. ¿Puede crear un proyecto de pruebas FACTEST con el mismo workflow de FAC?
  2. ¿Quién puede crear webhooks o reglas de Automation apuntando a una URL nuestra, y bajo qué proceso?
  3. ¿Debe observarse/automatizarse Facturación adicional (83), Facturación (12) u otro request type? El 83 contiene campos estructurados útiles; el 12 solo exige Summary.
  4. ¿Cuál estatus dispara la cotización y cuál confirma la factura? Los nombres reales y las transiciones de salida ya se conocen, pero la regla de negocio no.
  5. ¿De dónde deben obtenerse monto y conceptos? No existen como campos estructurados en el request type 83; definir si se extraen del adjunto o se agregan a Jira.
  6. PUE vs PPD — la pregunta que no se ha alcanzado a hacer en tres sesiones (REGISTRO #52).

Orden de ataque sugerido

# Acción Bloqueado por
1 Blindar el token (.gitignore + secrets)
2 Completar la muestra de tickets y el mapeo a BIND Definición del caso de negocio
3 Implementar lectura con /search/jql, cursor y ventana de solape
4 Preparar y compartir el script de escritura mínimo para revisión Definición de flujo de Balam
5 Levantar un sandbox Jira propio o FACTEST Apoyo de Pedro si se usa FACTEST
6 Ejecutar una única prueba de escritura acompañada Aprobación, script revisado y ticket de prueba

Lo que puede avanzar ya: el cliente de lectura, manejo de ADF, paginación por cursor, mapeo de campos y detección incremental. La escritura queda deliberadamente fuera del flujo automático hasta que haya sandbox o una sesión de validación acompañada.


Briefing corto para desarrollo / revisión técnica

Contexto validado: Jira Cloud JSM en balam-jsm-temp.atlassian.net; proyecto FAC company-managed (projectId: 10034, serviceDeskId: 35). La autenticación directa con Basic email:token funciona. El token tiene permisos de escritura amplios, pero no se debe ejecutar ningún POST, PUT o DELETE fuera de una prueba acompañada y aprobada.

Para la capa de lectura, usar GET /rest/api/3/search/jql, paginar por nextPageToken y aplicar una ventana de solape al checkpoint de updated. No usar /rest/api/3/search: responde 410.

Para JSM, usar /rest/servicedeskapi al consultar request types y su contrato de campos. FAC tiene los request types Bajas (84), Facturación adicional (83), Automatización (389) y Facturación (12). Bajas y Facturación adicional ya tienen su contrato verificado; el segundo incluye cliente, moneda, crédito, periodo y recurrencia, pero no monto ni conceptos estructurados.

Pendientes técnicos: revisar changelog y origen de tickets; muestrear tickets nacionales, extranjeros y recurrentes; y diseñar un script de escritura de una sola operación para revisión previa. El script debe ser idempotente, no incluir credenciales y ejecutarse únicamente en sandbox o acompañado en un ticket de prueba acordado.