Webhooks — Identidad del contacto
Cómo saber a qué persona corresponde cada evento, incluidos los contactos que ocultan su número de teléfono.
Si va a leer una sola página de esta sección, que sea esta.Meta permite a los usuarios de WhatsApp ocultar su número de teléfono. Esos contactos
llegan conphone: null. Una integración que use el teléfono como llave primaria los
pierde.
Los cuatro identificadores
| Campo | Qué es | ¿Siempre presente? | ¿Estable? |
|---|---|---|---|
uuid | Identificador del contacto en Wasapi | ✅ Sí | ✅ Nunca cambia |
id | Id numérico interno del contacto | ✅ Sí | ✅ Nunca cambia |
phone | Teléfono, solo dígitos, sin + | ❌ null si el contacto lo oculta | ⚠️ Puede corregirse |
bsuid | Business-Scoped User ID: el identificador que Meta asigna a esa persona para su empresa | ❌ null si el contacto no lo tiene | ✅ Estable dentro de su portafolio |
wa_username | Username público de WhatsApp (por ejemplo ana.gomez) | ❌ null si no tiene | ❌ El usuario lo puede cambiar |
Useuuidcomo llave primaria del contacto.Es el único que está siempre, no cambia y no depende de que la persona muestre su teléfono.
phonesirve para contactar;wa_usernamesirve para mostrarle algo legible a un humano;
ninguno de los dos sirve como identidad.
Sobre el bsuid
bsuidTiene el formato XX.<alfanumérico> — por ejemplo CO.1234567890123456. Dos precisiones
que importan:
- Es por portafolio de negocio de Meta, no por línea. Si sus números están en un solo
portafolio, la misma persona tiene el mismo BSUID en todos. Si tiene varios portafolios,
la misma persona tendrá un BSUID distinto en cada uno. - No es un teléfono y no sirve para escribirle a alguien nuevo. Identifica a una persona
que ya conversó con su empresa.
Sobre el wa_username
wa_usernameEs mutable y reasignable: el usuario puede cambiarlo, y un username liberado puede
quedar disponible para otra persona. Sirve para mostrar y para buscar, nunca como
identidad guardada.
⚠️ wa_id no siempre es un teléfono
wa_id no siempre es un teléfonoEn la familia de eventos de mensaje, el campo wa_id es la clave de conversación:
wa_id = phone si el contacto muestra su número
wa_id = bsuid si el contacto lo oculta
Es decir, wa_id puede traerle CO.1234567890123456 donde su código espera 573001234567.
Se mantiene así a propósito. Vaciarlo para los contactos ocultos rompería a todas las
integraciones que hoy leen ese campo. En vez de cambiarlo, se agregaron bsuid y
wa_username para que usted pueda distinguir el caso.
Cómo distinguir el caso
si data.bsuid no es null y data.wa_id == data.bsuid
→ contacto de número oculto
→ no hay teléfono; muestre data.wa_username
si no
→ data.wa_id es el teléfono
En PHP:
$esNumeroOculto = ! empty($data['bsuid']) && $data['wa_id'] === $data['bsuid'];
$telefono = $esNumeroOculto ? null : $data['wa_id'];
$paraMostrar = $esNumeroOculto
? ($data['wa_username'] ?? $data['bsuid'])
: $data['wa_id'];En JavaScript:
const esNumeroOculto = Boolean(data.bsuid) && data.wa_id === data.bsuid;
const telefono = esNumeroOculto ? null : data.wa_id;
const paraMostrar = esNumeroOculto ? (data.wa_username ?? data.bsuid) : data.wa_id;El mismo criterio vale en GET /v1/conversations de la API REST.
En la familia de encuestas, el campo equivalente es contact_wa_id y sigue exactamente
la misma semántica.
Los campos están siempre, con null cuando no hay valor
null cuando no hay valorbsuid y wa_username viajan en todos los eventos de las familias mensaje, contacto,
encuesta y publicidad, incluso cuando valen null.
Eso es deliberado: permite distinguir «este contacto no tiene BSUID» de «este evento no
trae el campo». No use isset() / array_key_exists() para decidir; compare contra null.
Ejemplos comparados
Contacto con teléfono visible (receive_message, recortado):
{
"event": "receive_message",
"data": {
"wa_id": "573001234567",
"bsuid": null,
"wa_username": null,
"message": "Hola, quiero información",
"version": 1
}
}El mismo evento, contacto con número oculto:
{
"event": "receive_message",
"data": {
"wa_id": "CO.1234567890123456",
"bsuid": "CO.1234567890123456",
"wa_username": "ana.gomez",
"message": "Hola, quiero información",
"version": 1
}
}Un contacto que oculta su número, en create_contact (recortado):
{
"event": "create_contact",
"data": {
"id": 987654,
"uuid": "9f8c1e3a-4b21-4d77-9a10-2c5e6f0b1d34",
"first_name": "Ana",
"phone": null,
"bsuid": "CO.1234567890123456",
"wa_username": "ana.gomez",
"version": 1
}
}Escribir usando estos identificadores
La API REST acepta los mismos identificadores, así que puede operar un contacto sin teléfono:
| Qué quiere hacer | Cómo |
|---|---|
| Leer, editar u operar un contacto | GET/PUT/DELETE /v1/contacts/{identificador} acepta teléfono, uuid, bsuid o wa_username en la URL |
| Enviar un mensaje | POST /v1/whatsapp-messages acepta wa_id (teléfono), bsuid o wa_username |
| Crear un contacto sin teléfono | POST /v1/contacts acepta bsuid en vez de phone |
| Cambiar el estado de una conversación | POST /whatsapp-messages/change-status acepta los tres en el campo wa_id |
Dos límites que conviene conocer:
- Solo se resuelven contactos que Wasapi ya conoce. Meta no ofrece búsqueda por
username o BSUID, así que si nunca vimos a esa persona la respuesta es un 422
explícito, no un envío que fallaría. bsuidse puede escribir al crear, no al actualizar. Cambiarlo movería la clave de
una conversación que ya existe y dejaría el historial huérfano.
Preguntas frecuentes
¿Qué tan común es un contacto sin teléfono?
Meta está desplegando la función gradualmente, así que hoy son una minoría — pero una
minoría que crece todos los días, y casi todos esos contactos sí traen wa_username.
Conviene contemplar el caso desde ahora en vez de esperar a que aparezca en volumen.
Si un contacto oculta su número, ¿pierdo el historial anterior?
No. La conversación previa sigue asociada al teléfono con el que empezó.
¿Puedo escribirle primero a alguien que oculta su número?
No. Sin teléfono no hay a quién iniciarle conversación: solo puede responder a alguien que
le escribió a usted.
¿El bsuid es el mismo que ve otra empresa?
No. Es business-scoped: Meta le asigna un identificador distinto a cada portafolio de
negocio. No sirve para cruzar datos con terceros.
Updated 17 days ago
