Enlace a la conversación desde tu CRM
Guarda en la ficha de cada cliente de tu sistema un enlace que abre su conversación en Meteor, buscándolo por teléfono, NIT o cédula.
Tu equipo vive en tu CRM, pero las conversaciones con los clientes pasan en Meteor. Cada contacto trae un app_url: el enlace que abre su conversación en Meteor. Si lo guardas en la ficha del cliente de tu sistema, quien esté mirando esa ficha llega al chat con un clic.
El enlace es estable: no lleva el nombre del workspace, así que sigue funcionando aunque el workspace cambie de nombre. Abrirlo pide una sesión en Meteor con acceso a ese contacto. No es un enlace público a la conversación.
{
"id": 4821,
"data": { "$name": "Ada Lovelace", "$phone": "+573001112233", "nit": "900123456" },
"app_url": "https://met.meteor.com.co/abrir/137/contacto/4821"
}
Hay dos formas de llenarlo. Puedes consultar a Meteor cuando lo necesites (paso 2) o dejar que Meteor te avise cada vez que un contacto se crea, cambia o escribe (paso 3). Si tu sistema tiene dónde recibir un POST, la segunda deja la ficha al día sin que consultes nada.
Antes de empezar
Tu key necesita contacts:read. Para recibir eventos, además webhooks:manage y conversations:read.
1. Decide con qué dato cruzas
El cruce lo hace tu sistema, con un dato que tengan los dos lados:
- Teléfono —
data.$phone, en formato internacional con+(+573001112233). Si tu sistema lo guarda distinto (3001112233,57 300 111 2233), normalízalo antes de comparar: el filtro compara el texto exacto. - NIT, cédula u otro documento — sirve si existe como campo personalizado del contacto en Meteor y está lleno. Los campos personalizados van con su
field_keysin$(nit,cedula). Descubre los del workspace conGET /variables/contact-fields.
2. Consultar el enlace de un cliente
Busca el contacto con un filtro y lee su app_url:
import Met from '@meteor.ia/sdk';
const met = new Met({ apiKey: process.env.MET_API_KEY! });
async function enlaceDeMeteor(nit: string): Promise<string | null> {
const pagina = await met.contacts.list({
filters: JSON.stringify([{ field: 'nit', op: 'eq', value: nit }]),
limit: 2,
});
if (pagina.data.length !== 1) return null; // 0: no está en Meteor · 2+: revisa duplicados
return pagina.data[0].app_url ?? null;
}
Una condición mal formada se ignora, no da error: si escribes mal el nombre del campo, el filtro devuelve todos los contactos. Por eso el ejemplo pide limit: 2 y solo acepta exactamente un resultado.
Si ya tienes el id del contacto, met.contacts.retrieve(id) también trae el app_url.
3. Que Meteor te lo mande
Suscríbete a los eventos de contacto. Todos los que hablan de un contacto llevan su app_url en data: contact.created, contact.updated, contact.message.received, contact.message.sent y conversation.handoff.
const sub = await met.webhooks.subscriptions.create({
url: 'https://tu-crm.com/webhooks/met',
enabled_events: ['contact.created', 'contact.updated', 'contact.message.received'],
description: 'Enlace a la conversación en la ficha del cliente',
});
console.log(sub.secret); // whsec_… — se muestra UNA sola vez
El endpoint verifica la firma, responde rápido y guarda el enlace en tu ficha:
app.post('/webhooks/met', express.raw({ type: 'application/json' }), async (req, res) => {
let evento;
try {
evento = met.webhooks.constructEvent(
req.body,
req.headers['x-met-signature'] as string,
process.env.MET_WEBHOOK_SECRET!,
);
} catch {
return res.status(400).send('firma inválida');
}
res.sendStatus(200);
const { contact_id, app_url } = evento.data as { contact_id: number; app_url?: string };
if (!app_url) return;
const contacto = await met.contacts.retrieve(contact_id);
await tuCrm.guardarEnlace({
telefono: contacto.data.$phone,
nit: contacto.data.nit,
enlace: app_url,
});
});
Guardar el mismo enlace dos veces no hace daño. Por eso este endpoint aguanta los reintentos sin llevar la cuenta de qué eventos procesó. La receta Recibir eventos firmados en tu backend explica la firma y los reintentos en detalle.
Sin programar: desde un flujo
Si no tienes un backend, un flujo de Meteor puede mandar el enlace a tu sistema con un nodo de petición HTTP. La variable es $contact.app_url, igual que $contact.phone o $contact.name.