Actualiza mensajes en directo
Un mensaje no tiene por qué quedarse como se publicó. Muestra el progreso mientras se ejecuta un trabajo, cambia un loader por el resultado, quita los botones cuando alguien ya ha decidido, o bórralo. Todos en el canal ven el cambio al instante.
Qué puedes hacer
- Actualiza la tarjetaCambia el texto, el color y los botones, en el mismo sitio.
- Muestra el progresoUn loader que avanza por los pasos y después el resultado.
- BórraloQuita un mensaje cuando ya no es cierto.
- EscúchaloRespuestas, reacciones y pulsaciones de botón en tu mensaje, en directo.
En la app
Publicada con un loader
Actualizada: paso 2 de 3
Actualizada: hecho, con un botón
Un mensaje, actualizado dos veces a través de su callback URL. Nadie ve tres mensajes, solo uno que cambia.
Inicio rápido
Guarda la callback URL
Cada publicación de webhook y cada petición de comando trae una
callback_urlpara ese mensaje.bashBODY='{"message_container": {"color": "blue", "loader": true, "loader_text": "Deploying…"}}' SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$MSSGS_WEBHOOK_SECRET" | sed 's/^.* //') curl -X POST "$MSSGS_WEBHOOK_URL" -H "Content-Type: application/json" \ -H "X-Mssgs-Signature: sha256=$SIG" -d "$BODY" # {"success": true, "message_id": "...", "callback_url": "https://mss.gs/api/v1/trigger-callback/8f14e45f-..."}PUT para actualizar
Envía el nuevo estado. La tarjeta cambia en el mismo sitio para todos.
bashcurl -X PUT "$CALLBACK_URL" -H "Content-Type: application/json" \ -d '{"message_container": {"color": "green", "title": "Deploy complete", "description": "v2.1 is live."}}'DELETE para borrar
No hace falta cuerpo.
bashcurl -X DELETE "$CALLBACK_URL"
Actualizar un mensaje
Envía JSON con PUT a la callback_url. Envía solo lo que quieras cambiar.
| Campo | Tipo | Qué hace |
|---|---|---|
message_container | object | La nueva tarjeta. Consulta tarjetas de mensaje. |
actions | array | Botones nuevos. "actions": [] los quita todos; si omites el campo, se mantienen. |
content | string | Texto nuevo. |
title, description, color, loader, ... | string | Atajo: los campos de tarjeta en el nivel superior se envuelven en una tarjeta por ti. |
message_container nuevo sustituye la tarjeta anterior entera: un campo que omitas desaparece. Solo se conservan su tipo, su nombre y su avatar. Así que envía siempre la tarjeta completa.Respuestas
| Estado | Código | Significado |
|---|---|---|
200 | {"success": true} | Aceptado. La actualización llega justo después. |
400 | MISSING_FIELDS | No hay nada que actualizar en el cuerpo. |
400 | INVALID_BODY | El cuerpo no es JSON válido. |
400 | un código de botón | Algo falla en un botón, consulta botones. |
401 | INVALID_TOKEN | La URL no es válida. |
404 | TOKEN_NOT_FOUND | La URL ha caducado o se ha usado para borrar el mensaje. |
502 | PUBLISH_FAILED | No se ha podido entregar la actualización. Vuelve a intentarlo. |
Cuánto tiempo funciona
30 minutos desde el momento en que se publicó el mensaje o se usó el comando. Actualizar no lo alarga. Borrar el mensaje agota la URL. No se pueden añadir archivos con una actualización.
Mostrar el progreso
Publica una tarjeta con un loader, actualiza su texto secundario a medida que avanza el trabajo y termina con el resultado. El loader es un spinner con una línea y otra más pequeña debajo (loader_text, loader_sub_text).
const { callback_url } = await post({
message_container: { color: 'blue', loader: true, loader_text: 'Deploying…', loader_sub_text: 'Step 1 of 3: building' }
});
const update = (body) => {
return fetch(callback_url, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
};
await build();
await update({ message_container: { color: 'blue', loader: true, loader_text: 'Deploying…', loader_sub_text: 'Step 2 of 3: running migrations' } });
await migrate();
await update({
message_container: { color: 'green', title: 'Deploy complete', description: 'v2.1 is live on production.' },
actions: [{ type: 'url:https://ci.example.com/deploys/218', text: 'View logs', color: 'green' }]
});Borrar un mensaje
Envía DELETE a la callback_url y el mensaje desaparece para todos. Después, la URL ya no se puede volver a usar.
Escuchar un mensaje
Una stream_url es un stream en directo (Server-Sent Events) de lo que pasa en tu mensaje. Ábrelo y los eventos llegan en cuanto ocurren, cada uno como una línea JSON data: cuyo type dice qué es:
curl -N "$STREAM_URL"
data: {"type": "reaction", "message_id": "...", "emoji": ":tada:", "action": "add", "member_guid": "...", "member": {...}, "ts": 1790000000000}
data: {"type": "action", "message_id": "...", "action_id": "approve", "action": {"id": "approve", "payload": {"deploy": 218}, ...}, "member_guid": "...", "member": {...}, "ts": 1790000004200}
data: {"type": "reply", "message_id": "...", "content": "Ship it!", "member_guid": "...", "member": {...}, "ts": 1790000009800}
event: expired
data: {}| Evento | Cuándo | Datos |
|---|---|---|
action | Se ha pulsado un botón. | action_id, y el botón guardado en action con su payload |
reaction | Se ha añadido o quitado una reacción. | emoji, y action: add, remove o removeall |
reply | Alguien ha respondido al mensaje. | El content de la respuesta |
expired | El stream se está cerrando. Se envía como evento con nombre. | Ninguno |
message_id, quién lo hizo (member_guid, member) y cuándo (ts). Una línea de comentario cada 20 segundos mantiene abierta la conexión.Escuchar en JavaScript
const events = new EventSource(streamUrl);
// Every event arrives as a plain message; its kind is in "type".
events.onmessage = (e) => {
const ev = JSON.parse(e.data);
if ((ev.type === 'action') && (ev.action_id === 'approve')) {
startDeploy(ev.action.payload.deploy);
}
};
// The one named event: the stream is closing.
events.addEventListener('expired', () => {
events.close();
});De dónde sacas una
| De dónde sale | Abierto durante |
|---|---|
| Una publicación de webhook con botones | 10 minutos, o una hora con "sse_event_extended_timeout": true |
| Cada petición de comando | 10 minutos |
Errores
| Estado | Código | Significado |
|---|---|---|
401 | INVALID_TOKEN | El token de la URL es incorrecto. |
404 | NOT_FOUND | El stream ha caducado o nunca existió. |