# Crear canales y gestionar miembros

Crea, edita y archiva canales del Chat y gestiona sus miembros desde tu aplicación, siempre dentro de los permisos de quien le dio acceso.

Estos endpoints permiten a tu aplicación organizar el Chat: crear canales, cambiarles el nombre o la descripción, archivarlos y decidir quién está en ellos. Por ejemplo, una herramienta de incidencias puede abrir un canal por cada incidencia grave y meter en él a las personas de guardia.

| Endpoint | Scope |
| - | - |
| `POST /api/external/v1/chat/channels` | `chat:channels:create` |
| `PATCH /api/external/v1/chat/channels/:channelId` | `chat:channels:manage` |
| `POST /api/external/v1/chat/channels/:channelId/archive` | `chat:channels:manage` |
| `POST /api/external/v1/chat/channels/:channelId/members` | `chat:members:manage` |
| `DELETE /api/external/v1/chat/channels/:channelId/members/:userId` | `chat:members:manage` |

Cada una de estas acciones se ejecuta en nombre de la persona que concedió el acceso al canal: tu aplicación nunca puede más que ella. Antes de cambiar nada, UTILIA OS comprueba tres cosas:

**Antes de cambiar un canal**

1. **¿Tiene la aplicación el scope?** (Ficha de la aplicación): chat:channels:create, chat:channels:manage o chat:members:manage, según la acción. Si no: 403 INSUFFICIENT_SCOPE.
2. **¿La concesión incluye esa capacidad?** (Panel del canal › Apps): «Crear y organizar canales» o «Gestionar miembros». Si no: 403 APP_NOT_AUTHORIZED_IN_CHANNEL, o 404 sin concesión activa.
3. **¿Quien concedió conserva el permiso hoy?** (Usuarios y permisos): Se revalida en cada llamada: si lo pierde, tu aplicación deja de poder hacerlo al momento. Si no: 403 APP_NOT_AUTHORIZED_IN_CHANNEL.

Solo se gobiernan canales y grupos, nunca conversaciones directas ni las del portal del cliente. Ninguna petición acepta la organización: sale de la clave de API. Y cada operación queda en el registro de auditoría de tu organización.

## Crear un canal

Crea un canal nuevo y, en general, deja a tu aplicación dentro con acceso.

**`POST /api/external/v1/chat/channels`**

Crea un canal con la app como creadora; le concede acceso automáticamente, acotado a los permisos de su usuario principal

Crear es lo único que no necesita una concesión previa. El canal se crea en nombre del usuario principal de la aplicación (la persona que la registró), que pasa a ser su propietario y tiene que poder crear canales. Después, UTILIA OS da a tu aplicación acceso al canal nuevo, limitado a sus scopes y a lo que ese usuario puede hacer. Si no coincide nada, el canal se crea igualmente, pero sin tu aplicación dentro; un responsable puede darle acceso después.

### Cuerpo de la petición

| Nombre | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `name` | `string` | Sí | Nombre del canal. Obligatorio, entre 1 y 120 caracteres |
| `description` | `string` | No | Descripción del canal. Máximo 500 caracteres |
| `isDiscoverable` | `boolean` | No | Si el canal aparece en el directorio de canales de la organización. Por defecto false |

### Respuesta (201)

Devuelve el canal creado, con la misma forma que en los [endpoints de lectura](https://os.utilia.ai/docs/developers/chat-platform/read-endpoints). Su `type` es siempre `CHANNEL`.

### Errores

| Código | `errorCode` | Cuándo |
| - | - | - |
| 400 | `VALIDATION_ERROR` | Falta `name` o incumple las validaciones (longitud) |
| 401 | | La clave de API falta o no es válida. |
| 403 | `INSUFFICIENT_SCOPE` | La aplicación no tiene el scope `chat:channels:create` |
| 403 | `APP_NOT_AUTHORIZED_IN_CHANNEL` | La aplicación no tiene usuario principal, o ese usuario no puede crear canales |

### Ejemplo

#### curl

```bash
curl -X POST 'https://os.utilia.ai/api/external/v1/chat/channels' \
  -H 'Content-Type: application/json' \
  -H 'X-Api-Key: utl_tu_clave_de_api' \
  -d '{
    "name": "Alertas de infraestructura",
    "description": "Avisos automáticos de la sala de servidores",
    "isDiscoverable": false
  }'
```

#### fetch

```javascript
const response = await fetch(
  'https://os.utilia.ai/api/external/v1/chat/channels',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Api-Key': 'utl_tu_clave_de_api',
    },
    body: JSON.stringify({
      name: 'Alertas de infraestructura',
      description: 'Avisos automáticos de la sala de servidores',
    }),
  },
);

const channel = await response.json();
console.log(channel.id, channel.name);
```

#### Python

```python
import requests

respuesta = requests.post(
    "https://os.utilia.ai/api/external/v1/chat/channels",
    headers={
        "Content-Type": "application/json",
        "X-Api-Key": "utl_tu_clave_de_api",
    },
    json={
        "name": "Alertas de infraestructura",
        "description": "Avisos automáticos de la sala de servidores",
    },
)

canal = respuesta.json()
print(canal["id"], canal["name"])
```

## Editar un canal

Cambia el nombre, la descripción o las dos cosas de un canal donde tu aplicación tiene acceso.

**`PATCH /api/external/v1/chat/channels/:channelId`**

Edita el nombre y/o la descripción de un canal concedido, en nombre del responsable que concedió el acceso

Parámetro de ruta: `channelId`.

### Parámetros de ruta

| Nombre | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `channelId` | `string` | Sí | Identificador del canal (conversación) a editar |

### Cuerpo de la petición

| Nombre | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `name` | `string` | No | Nuevo nombre del canal (1 a 120 caracteres) |
| `description` | `string` | No | Nueva descripción del canal (máximo 500 caracteres) |

Envía al menos uno de los dos campos; sin ninguno, la respuesta es 422. La visibilidad en el directorio (`isDiscoverable`) no se puede cambiar por aquí: es decisión de las personas del equipo.

### Respuesta (200)

Devuelve el canal actualizado.

### Errores

| Código | `errorCode` | Cuándo |
| - | - | - |
| 401 | | La clave de API falta o no es válida. |
| 403 | `INSUFFICIENT_SCOPE` | La aplicación no tiene el scope `chat:channels:manage` |
| 403 | `APP_NOT_AUTHORIZED_IN_CHANNEL` | La concesión de la aplicación en el canal no incluye editar canales, el concedente ya no puede editarlo, o el canal no es de tipo canal ni grupo |
| 404 | `CHANNEL_NOT_FOUND` | El canal no existe, pertenece a otra organización, o la aplicación no tiene concesión activa ni es miembro |
| 422 | `VALIDATION_ERROR` | No se envió ningún campo a editar |

## Archivar un canal

Archiva un canal donde tu aplicación tiene acceso. Exige lo mismo que editar: la capacidad «Crear y organizar canales» en la concesión y el permiso de editar canales en quien la concedió.

**`POST /api/external/v1/chat/channels/:channelId/archive`**

Archiva un canal concedido, en nombre del responsable que concedió el acceso

Parámetro de ruta: `channelId`.

### Parámetros de ruta

| Nombre | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `channelId` | `string` | Sí | Identificador del canal (conversación) a archivar |

### Respuesta (200)

Devuelve el canal archivado.

### Errores

| Código | `errorCode` | Cuándo |
| - | - | - |
| 401 | | La clave de API falta o no es válida. |
| 403 | `INSUFFICIENT_SCOPE` | La aplicación no tiene el scope `chat:channels:manage` |
| 403 | `APP_NOT_AUTHORIZED_IN_CHANNEL` | La concesión no incluye editar canales, el concedente ya no puede editarlo, o el canal no es de tipo canal ni grupo |
| 404 | `CHANNEL_NOT_FOUND` | El canal no existe, pertenece a otra organización, o la aplicación no tiene concesión activa ni es miembro |

Por la API no se pueden borrar canales: lo más que se puede hacer es archivarlos. Borrar un canal es una acción de una persona desde el Chat.

## Añadir un miembro

Añade a una persona de tu equipo a un canal donde tu aplicación tiene acceso.

**`POST /api/external/v1/chat/channels/:channelId/members`**

Añade un usuario interno al canal concedido, en nombre del responsable que concedió el acceso; el rol es siempre MEMBER

Parámetro de ruta: `channelId`.

### Parámetros de ruta

| Nombre | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `channelId` | `string` | Sí | Identificador del canal (conversación) |

### Cuerpo de la petición

| Nombre | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `userId` | `string` | Sí | Identificador del usuario interno a añadir al canal |

La persona entra siempre con rol `MEMBER`: una aplicación no puede nombrar administradores ni propietarios. El alta se hace en nombre de quien concedió el acceso, que debe ser propietario o administrador del canal y conservar el permiso de añadir participantes.

### Respuesta (201)

| Nombre | Tipo | Descripción |
| - | - | - |
| `kind` | `string` | Clase de miembro. Para esta vía siempre USER |
| `id` | `string` | Identificador del usuario añadido |
| `displayName` | `string` | Nombre del usuario tal como aparece en el canal |
| `role` | `string` | Rol del miembro en el canal. Siempre MEMBER |

### Errores

| Código | `errorCode` | Cuándo |
| - | - | - |
| 401 | | La clave de API falta o no es válida. |
| 403 | `INSUFFICIENT_SCOPE` | La aplicación no tiene el scope `chat:members:manage` |
| 403 | `APP_NOT_AUTHORIZED_IN_CHANNEL` | La concesión no incluye añadir miembros, o el concedente ya no puede añadirlos |
| 404 | `CHANNEL_NOT_FOUND` | El canal no existe, pertenece a otra organización, o la aplicación no tiene concesión activa ni es miembro |

## Retirar un miembro

Saca a una persona de tu equipo de un canal donde tu aplicación tiene acceso.

**`DELETE /api/external/v1/chat/channels/:channelId/members/:userId`**

Retira a un usuario interno del canal concedido, en nombre del responsable que concedió el acceso

Parámetros de ruta: `channelId`, `userId`.

### Parámetros de ruta

| Nombre | Tipo | Obligatorio | Descripción |
| - | - | - | - |
| `channelId` | `string` | Sí | Identificador del canal (conversación) |
| `userId` | `string` | Sí | Identificador del usuario a retirar |

### Respuesta (200)

```json
{
  "success": true
}
```

### Errores

| Código | `errorCode` | Cuándo |
| - | - | - |
| 401 | | La clave de API falta o no es válida. |
| 403 | `INSUFFICIENT_SCOPE` | La aplicación no tiene el scope `chat:members:manage` |
| 403 | `APP_NOT_AUTHORIZED_IN_CHANNEL` | La concesión no incluye retirar miembros, o el concedente ya no puede retirarlos |
| 404 | `CHANNEL_NOT_FOUND` | El canal no existe, pertenece a otra organización, o la aplicación no tiene concesión activa ni es miembro |

El scope `chat:members:manage` cubre añadir y retirar, pero cada operación se comprueba por separado: añadir exige que quien concedió el acceso conserve el permiso de añadir participantes, y retirar, el de retirarlos.

## Siguiente paso

Con el canal listo, [publica en él](https://os.utilia.ai/docs/developers/chat-platform/post-messages). Crear, editar y archivar canales generan los avisos `CHAT_CHANNEL_CREATED`, `CHAT_CHANNEL_UPDATED` y `CHAT_CHANNEL_ARCHIVED` para las aplicaciones del canal: los tienes en [Webhooks de chat](https://os.utilia.ai/docs/developers/chat-platform/webhooks).
