Consolida los hallazgos y decisiones pendientes para continuar el desarrollo sin exponer credenciales.
22 KiB
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 ypedro.ayala@balamtalentoestrategico.com, respondió 200 aGET /rest/api/3/myself. - Facturación es el proyecto JSM
FAC(projectId: 10034,serviceDeskId: 35), de tiposervice_desky estiloclassic(company-managed). - La búsqueda de FAC devolvió 66 tickets. La API vigente es
GET /rest/api/3/search/jql, con paginación pornextPageToken; el endpoint clásico/rest/api/3/searchresponde 410 Gone. - Estatus confirmados:
Open,En proceso de facturación,En espera por colaborador,En validación nacional,En validación extranjera,FacturadoyCancelado. 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 40–48 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,
descriptiony los comentarios no son texto plano ni wiki markup: son JSON estructurado. Hay que decidir ya si se parsea ADF o se pideexpand=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:
Facturadocomo estatus ≠ camporesolution. En Jira son cosas distintas: un ticket puede estar en Facturado conresolution: null, o cerrarse conresolution: Done. Hay que confirmar cuál de los dos es la señal confiable de “esta factura sí se emitió”, aunque el workflow muestra queFacturadoes la salida deFacturación completa.- Las transiciones son contextuales:
/transitionssolo devuelve las salidas del estado actual, y pueden tener pantallas con campos obligatorios. Probar conexpand=transitions.fieldspara 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 5–10 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:
- Preparar un script idempotente y de una sola operación; sin bucles, sin búsquedas masivas y sin credenciales embebidas.
- 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.
- Acordar el ticket de prueba y una ventana de ejecución. Preferir un proyecto sandbox (
FACTEST) o un ticket creado expresamente para la prueba. - Ejecutarlo acompañado, registrar el
HTTP status, elissue.id/keyy verificar el resultado por API. - 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):
- Comentar —
POST /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}/commentconpublic: 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. - Adjuntar —
POST /rest/api/3/issue/{key}/attachments. ⚠️ Exige el headerX-Atlassian-Token: no-checkymultipart/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. - Transicionar —
POST /rest/api/3/issue/{key}/transitionscon eltransition.iddel Bloque 3. - 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) vsPOST /rest/servicedeskapi/request(respeta request type y se ve como uno normal). Si es JSM, la segunda es la correcta. - Editar —
PUT /rest/api/3/issue/{key}. - Borrar —
DELETE /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:
- Pedir a Pedro un proyecto de pruebas (p. ej.
FACTEST) que replique el workflow de FAC. Barato para él, elimina el riesgo.- 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.txtNO está en.gitignore(aparece como no rastreado, no como ignorado): ungit add .lo commitea al historial. Agregarlo al.gitignorey mover el token a user-secrets / Key Vault. Mismo pendiente que arrastrabind_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/myselfcon qué identidad se está actuando. - 🔴 Alcance de permisos: validado con
GET /rest/api/3/mypermissionspara 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:
- ¿Puede crear un proyecto de pruebas
FACTESTcon el mismo workflow de FAC? - ¿Quién puede crear webhooks o reglas de Automation apuntando a una URL nuestra, y bajo qué proceso?
- ¿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. - ¿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.
- ¿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.
- 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 Basicemail:tokenfunciona. 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 pornextPageTokeny aplicar una ventana de solape al checkpoint deupdated. No usar/rest/api/3/search: responde 410.Para JSM, usar
/rest/servicedeskapial 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.