---
title: "Obtiene los mensajes del contacto"
method: GET
path: "/contacts/{contactId}/messages"
tags: ["Contacts"]
---

# Obtiene los mensajes del contacto

`GET /contacts/{contactId}/messages`

## Request

- Base URL: `https://api.met.meteor.com.co/api/v1`
- URL: `https://api.met.meteor.com.co/api/v1/contacts/{contactId}/messages`
- Auth: one of:
  - `bearer` (a scheme the document does not define)
  - HTTP bearer

Devuelve **un array plano** en orden cronológico, del mensaje más viejo al más nuevo.

**Sin parámetros devuelve el hilo COMPLETO**, como siempre. Es el comportamiento por defecto y no cambió: si ya integrabas contra este endpoint, no tienes que tocar nada.

Con **`limit`** (1–200) devuelve en cambio la ventana MÁS RECIENTE — los últimos N mensajes, igual en orden cronológico. Para seguir hacia atrás, manda **`before`** con el `id` del mensaje más viejo que ya tienes y recibes la ventana anterior.

No hay campo `has_more`: si volvieron menos de `limit` mensajes, llegaste al principio de la conversación.

Quién habló se lee en **`role`** (`user` = el contacto, `operator` = tu equipo, `agent` = el Met). No existe un campo `direction`.

**Ojo con el scope**: aunque la ruta cuelga de `/contacts`, este endpoint pide `conversations:read`, no `contacts:read`. Una key emitida solo con `contacts:read` / `contacts:write` lista contactos pero recibe `403 missing_scope` acá. Es la causa más frecuente de error en este endpoint.

Un `404 Contacto no encontrado` no distingue entre "no existe", "no es de tu workspace" y "tu usuario no lo tiene a la vista": se responde igual en los tres casos, a propósito, para no confirmar la existencia de contactos ajenos.

## Path parameters

- `contactId` number, required

## Query parameters

- `limit` number
- `before` number
- `line_id` string

## Response `200`

- object: Sobre en el que viaja toda respuesta correcta de la API. El recurso está en `data`. Los SDKs oficiales lo desenvuelven por ti; un cliente hecho a mano tiene que leer `.data`.
  - `success` true, required: Siempre `true` en una respuesta 2xx.
  - `data` ContactMessageDto[], required
    - `agent_id` number, nullable: Met que produjo el mensaje, cuando `role` es `agent`.
    - `attachments` object[]: Adjuntos del mensaje (`{ url, mime_type, name, size, kind }`). Un audio transcrito trae además `transcript` con el texto; `content` sigue siendo `"[Audio]"`.
    - `channel_id` number, required
    - `client_message_id` string, uuid, nullable: Id estable generado por el navegador para reconciliar reintentos.
    - `contact_id` number, required
    - `content` string, required: Texto del mensaje. En mensajes de solo adjunto puede venir vacío.
    - `created_at` string, nullable: Cuándo se guardó el mensaje: ISO 8601 en UTC, siempre con `Z`.
    - `id` number, required
    - `message_type` string, required: Qué clase de mensaje es: `text`, `image`, `audio`, `video`, `document`, `location`, `template`, `note` (nota interna, nunca se envió al contacto), `system_event` o `tool_use`.
    - `metadata` object: Metadatos del mensaje. En `template` lleva `template.{name,language,params}`; en `tool_use` el JSON de la invocación; en los de WhatsApp el estado de entrega que reporta Meta.
    - `origin` 'contact' | 'met' | 'panel' | 'api' | 'mcp' | 'flow' | 'automation' | 'broadcast' | 'phone' | 'system' | 'unknown', required: `contact`: lo escribió el contacto. `met`: respuesta de un Met. `panel`: una persona desde la app de Meteor (bandeja, ficha, notas). `api`: una integración con API key o SDK. `mcp`: un asistente de IA conectado por MCP. `flow`: un flujo. `automation`: una automatización programada o disparada por una regla. `broadcast`: una difusión (envío masivo). `phone`: escrito desde el celular con WhatsApp Business (coexistencia). `system`: un evento de la conversación (asignación, cambio de estado, etiqueta). `unknown`: mensaje anterior al 25-sep-2026 cuyo origen no quedó registrado. Los mensajes enviados antes del 25-sep-2026 por una integración con API key aparecen como `panel`: en ese momento el origen no se registraba.
    - `role` 'user' | 'operator' | 'agent', required: Quién habló: el contacto (`user`), tu equipo (`operator`) o el Met (`agent`).
    - `sent_by_name` string, nullable: Nombre visible de `sent_by_user_id`, ya resuelto. `null` cuando no lo mandó una persona. **Solo viene en `GET /contacts/{id}/messages`**; el mensaje que devuelve un envío no lo trae.
    - `sent_by_user_id` number, nullable: Persona de tu equipo que lo envió, cuando `role` es `operator`.
    - `source` string, nullable: De dónde entró o salió el mensaje. `null` para los que no lo declaran.

## Other responses

- `400`: La request no es válida: un campo no pasa validación, falta un parámetro requerido o el recurso no admite la transición solicitada.
- `401`: API key ausente, inválida, revocada o expirada — o el workspace está bloqueado.
- `403`: La key está autenticada pero no puede ejecutar esta operación: scope faltante, capacidad deshabilitada, modo test restringido o recurso fuera de su cartera.
- `404`: El recurso no existe o no está disponible dentro del alcance de la key. No revela la existencia de recursos de otros tenants.
- `429`: Se superó el límite por minuto de la key o la cuota del plan. Respeta `Retry-After`; el SDK ya reintenta solo.
- `500`: Error del servidor o del Met que ejecutaba. El SDK reintenta los 5xx con backoff.

---

[API](https://skmtc.dev/meteor/apis/met-public-api.md) · [All operations](https://skmtc.dev/meteor/apis/met-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/meteor/apis/met-public-api/revisions/5d9ca294295c?raw)
