Ejemplo completo: termómetro
Una aplicación que publica lecturas en un canal, recibe la respuesta del equipo, verifica el aviso y contesta en el hilo sin entrar en bucle.
Actualizado el . 2 min de lectura
Incluido en todos los planes. Ver precios
Este ejemplo junta todas las piezas en un caso real. «Termómetro» es una aplicación que publica la temperatura de la sala de servidores en un canal del Chat. Cuando alguien del equipo contesta, la aplicación recibe un aviso, comprueba que es auténtico y responde en el mismo hilo, sin contestarse nunca a sí misma ni a otras aplicaciones.
Necesitas una aplicación externa con su clave de API, los scopes chat:messages:send, chat:messages:view y chat:events:subscribe, una dirección de webhook con su secreto y el SDK de JavaScript o Python. Si te falta algo, empieza por Autenticación en el chat.
El recorrido completo de Termómetro
Participan: Termómetro, UTILIA OS, Equipo.
De Termómetro a UTILIA OS:
POST /api/external/v1/chat/channels/:channelId/messages
Publica la lectura con su identidad.De UTILIA OS a Equipo:
Mensaje en el canal
Aparece firmado por Termómetro y llega como aviso.De Equipo a UTILIA OS:
Respuesta en el hilo
Alguien del equipo contesta.De UTILIA OS a Termómetro:
Aviso CHAT_MESSAGE_CREATED
Firmado con HMAC; solo trae el messageId y el channelId.Nota en Termómetro:
Verifica la firma del aviso y contesta 200 enseguida.De Termómetro a UTILIA OS:
GET /api/external/v1/chat/messages/:messageId
Lee el mensaje; si el autor es una aplicación, se detiene.De Termómetro a UTILIA OS:
POST .../messages con parentMessageId
Contesta en el mismo hilo.
Da acceso a la aplicación en el canal
Un propietario o administrador del canal abre el panel del canal, pestaña «Apps», pulsa «Dar acceso a una app», elige Termómetro y marca «Leer los mensajes del canal» y «Escribir mensajes». Desde ese momento la aplicación es miembro del canal. Apunta el identificador del canal (
channelId).Publica una lectura
import { UtiliaSDK } from '@utilia-os/sdk-js'; const sdk = new UtiliaSDK({ baseURL: 'https://os.utilia.ai/api', apiKey: process.env.UTILIA_API_KEY, // utl_xxx }); const CHANNEL_ID = process.env.CHANNEL_ID; // cnv_xxx async function publicarLectura(temperatura) { const mensaje = await sdk.chat.sendMessage(CHANNEL_ID, { content: `Temperatura de la sala de servidores: ${temperatura.toFixed(1)} °C`, }); console.log('Publicado:', mensaje.id); return mensaje; } await publicarLectura(21.4);Recibe el aviso, verifícalo y contesta
Cuando alguien responde en el canal, UTILIA OS envía el aviso
CHAT_MESSAGE_CREATEDa la dirección de webhook de la aplicación. El receptor verifica la firma, lee el mensaje congetMessagey contesta en su hilo, solo si el autor no es una aplicación.import express from 'express'; const app = express(); app.use(express.raw({ type: 'application/json' })); // cuerpo tal como llega app.post('/webhooks/chat', async (req, res) => { let aviso; try { aviso = sdk.webhooks.verify(req.body.toString('utf8'), req.headers, process.env.UTILIA_WEBHOOK_SECRET); } catch { return res.status(401).end(); // firma no válida o aviso caducado } res.status(200).end(); // contesta enseguida; el resto, después if (aviso.event === 'CHAT_MESSAGE_CREATED') { const mensaje = await sdk.chat.getMessage(aviso.data.messageId); if (mensaje.author.kind === 'APP') return; // nunca respondas a una aplicación await sdk.chat.sendMessage(mensaje.channelId, { content: 'Recibido. Vuelvo a leer el sensor y publico la lectura.', parentMessageId: mensaje.id, }); } }); app.listen(3000);
Antes de ponerlo en producción
- Lee la clave de API y el secreto del webhook de variables de entorno o de un gestor de secretos, nunca del código.
- Descarta los avisos repetidos guardando su
X-Utilia-Delivery-Id, como en el receptor de Webhooks de chat. - No publiques más de 600 mensajes por hora: es el límite de cada aplicación.
Siguiente paso
Si Termómetro debe avisar en un canal propio, puede crearlo e invitar a las personas de guardia con los endpoints de canales.