> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://naturgy-comer-documentation-p5mde.vercel.app/api/mcp` to find what you need.

# API de integración

TeLeo expone una frontera para workflows de HappyRobot y una API Super App para
integradores externos. Ambas terminan en el mismo modelo de ticketing, pero sus
credenciales y contratos no se deben intercambiar.

## Autenticación

* **Ingesta HappyRobot:** usa una credencial M2M server-side en el header Bearer
  acordado con el owner.
* **API Super App:** usa una clave M2M server-side en el header
  `x-superapp-key`.
* **Consola:** usa la sesión propia del agente en cookie; no da acceso a la API
  pública.

Los valores de las credenciales no pertenecen a esta documentación. No deben
llegar al navegador, al modelo, a un fixture, a un screenshot ni a un log.

## Operaciones públicas

| Método | Ruta | Uso |
|---|---|---|
| `POST` | `/api/hr/tickets` | Crear un ticket desde un escalado de HappyRobot. |
| `POST` | `/api/hr/tickets/{session_id}/messages` | Añadir un mensaje posterior del cliente al ticket de la sesión. |
| `POST` | `/api/v1/tickets` | Crear un ticket desde un integrador externo. |
| `PUT` | `/api/v1/tickets/{id}` | Añadir un mensaje o cambiar un estado permitido. |
| `GET` | `/api/v1/tickets/{id}` | Consultar estado, asignación y timestamps. |

El contrato observado usa `PUT` para la actualización pública. Si el OpenAPI del
entorno aprobado expone una variante, prevalecen ese método y su schema; no se
debe cambiar el payload por intuición.

## Crear un ticket

El payload mínimo debe tener un identificador estable de sesión y contexto que
permita al agente continuar sin volver a preguntar lo ya conocido:

```json
{
  "ticket": {
    "id": "session-id-from-runtime",
    "status": "OPEN",
    "subject": "Resumen breve del motivo",
    "priority": "medium",
    "comment": {
      "sender_type": "bot",
      "body": "Contexto inicial saneado",
      "public": false
    },
    "customer_profile": {
      "firstName": "nombre-autorizado",
      "email": "contacto-autorizado"
    },
    "via": {
      "channel": "messenger"
    },
    "naturgy": {
      "language": "es",
      "validated": false,
      "environment": "test",
      "escalation_reason": "motivo-catalogado",
      "bot_summary": {
        "summary": "Resumen breve",
        "fault_description": "Descripción mínima"
      }
    }
  },
  "tags": {
    "importance": "normal"
  },
  "metadata": {
    "correlation_id": "correlation-id"
  }
}
```

El ejemplo es estructural: los valores deben proceder del runtime y no de datos
inventados. Añade `case_id`, `routing_key`, `session_id`, `hr_run_link` o
`hr_webhook_url` únicamente cuando el contrato del canal los autorice.

### Idempotencia

* `ticket.id` representa el identificador externo de la sesión.
* Repetir la creación con el mismo identificador debe devolver el ticket
  existente, con una marca equivalente a `already_existed`, sin duplicar la
  atención.
* Un reintento sin el mismo identificador puede crear otra atención; el
  integrador debe detenerse y corregir el payload.

### Tags y metadata

`tags` puede recibirse como objeto clave/valor, array de strings o cadena
separada por comas. La aplicación normaliza las etiquetas y las une a las
existentes. Tags y metadata sirven para clasificación y correlación; nunca deben
contener secretos, transcript completo, DNI, IBAN o datos que no sean necesarios.

## Añadir un mensaje

Para un mensaje posterior, usa el mismo `session_id`/ticket ID y envía solo el
nuevo contenido:

```json
{
  "ticket": {
    "comment": {
      "body": "Mensaje posterior del cliente",
      "sender_type": "customer",
      "author_id": "customer",
      "public": true
    },
    "via": {
      "channel": "messenger"
    }
  }
}
```

El receptor debe evitar duplicados mediante la clave de mensaje o una
correlación equivalente. Si no hay confirmación, consulta el estado antes de
reenviar.

## Consultar y actualizar

`GET /api/v1/tickets/{id}` debe permitir comprobar estado, prioridad, asignación,
creación, última actividad y cierre dentro del alcance autorizado.

La actualización pública puede cambiar un estado permitido o añadir un mensaje.
El cierre desde la consola además aplica las reglas de ciclo y las señales; un
integrador no debe simularlo cambiando un campo sin contrato explícito.

## Webhook saliente

Cuando un agente responde públicamente, TeLeo:

1. guarda el mensaje;
2. resuelve el webhook de la sesión;
3. envía el evento al workflow;
4. registra un fallo sin borrar la respuesta guardada.

La forma conceptual es:

```json
{
  "ticket_id": "session-id-from-runtime",
  "message": {
    "id": "message-id",
    "body": "Respuesta pública del agente",
    "author_id": "agent-id",
    "created_at": "timestamp"
  }
}
```

Las notas privadas nunca deben formar parte de este webhook. El consumidor debe
ser idempotente, validar la autenticación y conservar la correlación sin guardar
el header secreto.

## APIs internas de consola

Estas rutas sirven a la UI autenticada y no son la API de integración:

| Método | Ruta | Uso |
|---|---|---|
| `POST` | `/api/auth/login` | Iniciar sesión de agente. |
| `POST` | `/api/auth/logout` | Cerrar sesión. |
| `GET` | `/api/auth/me` | Consultar la sesión actual. |
| `GET` | `/api/tickets` | Listar con filtros de vista, estado, prioridad y búsqueda. |
| `GET` | `/api/tickets/{id}` | Leer detalle y mensajes. |
| `PATCH` | `/api/tickets/{id}` | Actualizar estado, prioridad, asignación, equipo o tags. |
| `POST` | `/api/tickets/{id}/messages` | Responder o añadir nota privada. |
| `POST` | `/api/tickets/{id}/snooze` | Aparcar con un límite si aplica. |
| `POST` | `/api/tickets/{id}/close` | Cerrar desde la consola. |
| `POST` | `/api/tickets/{id}/reopen` | Reabrir una atención permitida. |
| `GET` | `/api/agents`, `/api/teams`, `/api/stats` | Consultar equipo y contadores autorizados. |

Estas rutas deben aplicar permisos server-side. Ocultar un botón no es control
de acceso.

## Errores y límites

| Situación | Tratamiento |
|---|---|
| Payload inválido | Corregir el schema; no reintentar sin cambios. |
| Credencial ausente o inválida | Fallo de integración; no crear un ticket alternativo sin autorización. |
| Servicio mal configurado | Error controlado y alerta al owner; no exponer configuración sensible. |
| Timeout | Consultar idempotencia/estado antes de repetir una mutación. |
| Webhook no entregado | Mantener la respuesta, registrar fallo y reintentar según contrato. |
| Entorno incorrecto | Rechazar o bloquear antes de escribir. |

Las rutas y métodos deben comprobarse contra el OpenAPI vigente del entorno de
prueba antes de UAT. Esta página no autoriza acceso ni publicación.
