Ir al contenido

Estados

Los estados (status, las historias de 24 horas) se publican y se reciben en el chat especial status@broadcast. Con estas rutas tu app:

  • prueba la audiencia de estados del número, sin publicar nada;
  • publica un estado de texto, imagen o vídeo declarando a quién sale;
  • consulta los estados que el motor todavía retiene: los de tus contactos y los del número;
  • recibe status.received cuando un contacto publica y status.revoked cuando lo borra.
  • Una instancia conectado. Probar la audiencia responde 409 no_conectada sin conexión.
  • Una API key con estos scopes:
Operación Ruta Scope
Probar la audiencia GET /v1/instances/{id}/status/audience status:read
Listar los estados retenidos GET /v1/instances/{id}/status status:read
Publicar un estado POST /v1/instances/{id}/status status:write

Para recibir los eventos, además, events:read o una suscripción de webhooks. Para publicar una imagen o un vídeo, súbelo antes con media:write (ver Multimedia).

Los ejemplos de Go y JavaScript usan una función auxiliar, llamar, que se define en el primer paso: el SDK de Go no trae métodos de estados, así que es HTTP directo con el token del cliente.

GET /v1/instances/{id}/status/audience pregunta a WhatsApp la privacidad de estados del número (la que se elige en el teléfono) y cuenta su audiencia. Es lo que vas a declarar al publicar.

Campo Qué es
privacidad contacts (mis contactos), allowlist (solo compartir con…) o denylist (mis contactos excepto…).
destinatarios Cuántos contactos tiene esa audiencia ahora (sin contar a quien no usa WhatsApp).
max_destinatarios_ajustes Lo más que puede declarar una publicación (Ajustes del operador; de fábrica, 256).
horas_retencion Cuánto guarda el motor un estado (de 1 a 24; de fábrica, 24).
Ventana de terminal
curl https://motor.ejemplo.com/v1/instances/INSTANCIA_ID/status/audience \
-H "Authorization: Bearer TU_API_KEY"
200 OK
{
"privacidad": "contacts",
"destinatarios": 42,
"max_destinatarios_ajustes": 256,
"horas_retencion": 24
}

POST /v1/instances/{id}/status va por el mismo outbox que un mensaje: la Idempotency-Key es obligatoria y responde 202 con el comando en_cola.

Campo Qué es
tipo text (por omisión), image o video. Otros tipos, como una ubicación o un audio, no se publican como estado.
texto Hasta 700 caracteres: el texto (obligatorio en text) o el pie de la imagen o el vídeo.
fondo Solo en text: el color de fondo, #RRGGBB.
medio Solo en image y video: media_id (una subida de esta instancia, lista) o url (un host de los destinos permitidos).
audiencia Obligatoria. Ver abajo.
expires_at, correlation_id Como en un mensaje: si no salió antes de expires_at, no sale.

La audiencia dice a quién sale y nunca se adivina:

Campo Qué es
modo privacidad: la audiencia de la privacidad de estados del número. lista: solo los destinos.
privacidad En modo: privacidad, la que esperas (contacts, allowlist o denylist). Si la del número es otra, no sale.
destinos En modo: lista, de 1 a max_destinatarios usuarios (telefono, jid o peer_ref). Tienen que estar dentro de la privacidad del número.
max_destinatarios Obligatorio, de 1 a 5000: lo más que aceptas. Si la audiencia tiene más, no sale. No puede pasar el máximo de Ajustes.

Un estado no lleva cita, menciones ni vista previa.

Ventana de terminal
curl -X POST https://motor.ejemplo.com/v1/instances/INSTANCIA_ID/status \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: estado-horario-feriado" \
-d '{
"tipo": "text",
"texto": "El lunes feriado abrimos de 10 a 14 h.",
"fondo": "#1F6FEB",
"audiencia": {"modo": "privacidad", "privacidad": "contacts", "max_destinatarios": 256}
}'
# Solo a dos contactos, con una imagen:
curl -X POST https://motor.ejemplo.com/v1/instances/INSTANCIA_ID/status \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: estado-catalogo-mayoristas" \
-d '{
"tipo": "image",
"medio": {"media_id": "8a1d2c3e-0000-4000-8000-0000000000e2"},
"texto": "Nuevo catálogo para mayoristas",
"audiencia": {
"modo": "lista",
"destinos": [{"telefono": "+NUMERO_DEL_CONTACTO"}, {"peer_ref": "4b7d9e01-0000-4000-8000-0000000000b3"}],
"max_destinatarios": 2
}
}'

Cuando sale, el comando queda enviado y su result dice la audiencia real:

GET /v1/commands/{id} · result
{
"provider_message_id": "PROVIDER_MESSAGE_ID",
"vence_en": "2026-10-25T16:30:00Z",
"audiencia_conocida": true,
"privacidad": "contacts",
"destinatarios": 41,
"omitidos": ["CONTACTO@s.whatsapp.net"],
"sin_cifrar": [],
"parcial": true
}
  • omitidos: quienes no tienen dispositivos (no usan WhatsApp).
  • sin_cifrar: quienes no recibieron su copia cifrada en ningún dispositivo; no lo pueden ver y no cuentan como destinatarios.
  • parcial: hubo omitidos o sin cifrar.
  • vence_en: cuándo vence en WhatsApp (24 horas).

Si un estado quedó ambiguo (pudo salir sin respuesta) y después llega su eco o un recibo, pasa a enviado con su vence_en. Si el motor no sabe a quién salió, audiencia_conocida es false y no hay destinatarios: nunca un cero inventado.

GET /v1/instances/{id}/status devuelve los estados que el motor todavía guarda, los más nuevos primero, de a limit (1 a 200; por omisión, 50), con next_cursor y has_more. Con direccion=entrante solo los de tus contactos; con saliente, los del número.

Cada uno trae status_id, provider_id, autor (en los entrantes), tipo, texto (el texto o el pie), mime, momento, vence_en, retener_hasta, revocado y, si lo publicó el motor, su command_id. El archivo de un estado recibido no se descarga: solo su tipo, su MIME y su pie.

Ventana de terminal
curl "https://motor.ejemplo.com/v1/instances/INSTANCIA_ID/status?direccion=entrante&limit=50" \
-H "Authorization: Bearer TU_API_KEY"

Un estado vence en WhatsApp a las 24 horas. El motor lo guarda hasta retener_hasta: las horas de estados.horas_retencion (Ajustes del operador, de 1 a 24; de fábrica, 24), nunca más que su vencimiento. Después lo borra de la lista y el contenido de su status.received queda redactado (data: {"motivo": "retencion", "redactado": true}). Vencer no produce ningún evento: no hay un status.expired. Un estado que llega cuando ya pasó su retención no se guarda.

Publicar crea un envío del tipo message.status_text, message.status_image o message.status_video, que nace en_cola y termina enviado (con message.sent), fallido o ambiguo, como un mensaje (ver Comandos asíncronos y eventos). Un estado publicado por el motor no produce status.received: su hecho es el message.sent.

Un contacto publicó un estado (o el número publicó uno desde el teléfono, con from_me: true). tipo es el del contenido (texto, imagen, video…); texto es el texto o el pie.

{
"status_id": "7d3c1b20-0000-4000-8000-0000000000f1",
"autor": { "peer_ref": "…", "jid": "CONTACTO@s.whatsapp.net", "clase": "usuario", "aliases": [] },
"provider_id": "PROVIDER_MESSAGE_ID",
"from_me": false,
"tipo": "imagen",
"texto": "Nueva temporada",
"mime": "image/jpeg",
"vence_en": "2026-10-25T16:40:00Z",
"retener_hasta": "2026-10-25T16:40:00Z"
}

Quien lo publicó lo borró. El estado queda revocado, sin contenido, y su status.received se redacta con motivo: "revocado". Llega una sola vez.

{
"status_id": "7d3c1b20-0000-4000-8000-0000000000f1",
"autor": { "peer_ref": "…", "jid": "CONTACTO@s.whatsapp.net", "clase": "usuario", "aliases": [] },
"provider_id": "PROVIDER_MESSAGE_ID",
"from_me": false
}

La publicación se valida antes de guardarse (errores HTTP) y otra vez antes de salir (el comando termina fallido sin que salga nada).

HTTP error_code Cuándo
403 — A tu key le falta status:write o status:read.
409 no_conectada Probar la audiencia con la instancia sin conexión.
409 — La misma Idempotency-Key con otro estado.
422 — Un estado de texto sin texto o con medio; uno de imagen o vídeo sin medio o con fondo.
422 audiencia_invalida modo: privacidad sin privacidad o con destinos; modo: lista sin destinos o con más de max_destinatarios; un fondo que no es #RRGGBB.
422 audiencia_maxima max_destinatarios pasa el máximo de Ajustes.
422 no_en_status Un estado con cita, menciones o vista previa.
429 — El ritmo de la instancia o la cola llena, como en un mensaje.

Los error_code de un estado que no salió:

error_code Qué pasó
privacidad_distinta La privacidad de estados del número no es la que declaraste.
privacidad_desconocida WhatsApp informó una privacidad que el motor no conoce.
fuera_de_privacidad En modo: lista, algún destino no está dentro de la privacidad del número.
audiencia_excedida La audiencia tiene más que tu max_destinatarios.
sin_destinatarios No hay nadie a quien mandarlo.
sin_cifrar No se pudo cifrar la copia de nadie de la audiencia.
comando_vencido Pasó expires_at antes de salir.
  • No se puede borrar un estado propio por la API (caso A69, 21/10/2026): no hay ruta para eso; bórralo desde el teléfono o espera las 24 horas. Ver Otros límites observados.
  • El borrado solo llega a los contactos actuales (caso A69, 22/10/2026): borrado desde el teléfono, el estado llegó como status.revoked a la otra instancia, lo hubiera publicado el motor o el teléfono. Pero si el contacto ya no estaba en la libreta de quien publicó, WhatsApp no le avisó del borrado: el estado quedó hasta vencer.
  • La privacidad de estados se cambia en el teléfono (caso A67, 21 y 22/10/2026): la API no la cambia. Con la privacidad en «Solo compartir con…», declarar contacts falló con privacidad_distinta a los 0,1 s, sin salir nada.
  • Una lista explícita (caso A68, 21/10/2026): un estado de imagen con modo: lista y un solo contacto salió enviado con destinatarios: 1 y solo lo vio ese contacto.
  • Publicar con la red cortada (caso A70, 22/10/2026): el estado no se publicó dos veces; al reconectar salió una sola vez con su vence_en y su audiencia. El caso ambiguo conciliado por un recibo no se pudo provocar en real.