> ## Documentation Index
> Fetch the complete documentation index at: https://help.wizebot.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Ler mensagens de uma conversa

> Do mais recente para o mais antigo, por cursor. A entrada é só o `conversation_id`.

### A janela recente

**Sem `since`, a leitura cobre os últimos 30 dias.** Isso é decisão de produto, não limite técnico — medimos que a paginação profunda é barata e de custo constante, então o teto não existe para proteger o servidor. Ele existe para separar *ler a conversa* de *baixar o histórico inteiro*: para alcançar o que está além da janela, informe `since` e a intenção fica declarada na requisição.

A resposta devolve em `window` a janela efetivamente aplicada, para você nunca precisar adivinhar.

### Mídia vem em dois passos

A mensagem **nunca** traz URL nem caminho de armazenamento. Ela traz `media.media_id`; troque por um endereço temporário em `GET /v1/attachments/{media_id}`.

<Warning>
  **Nem toda mensagem de mídia tem arquivo recuperável.** Quando `media.media_id` vier `null`, não chame o anexo — não há o que resolver. O bloco `media` nunca é omitido: se a mensagem é de mídia, ele existe, e `media_status` diz o que houve.
</Warning>

| `media_status` | O que significa | `media_id` |
|---|---|---|
| `available` | Arquivo registrado e recuperável | preenchido |
| `unknown` | Mídia recebida antes do registro interno, ou cujo arquivo não foi guardado. É o caso da maior parte do histórico antigo | `null` |
| `no_reference` | A mensagem não carrega nenhuma informação de mídia | `null` |

Numa conversa com histórico longo, esperar que toda imagem resolva é a suposição errada — trate `media_id: null` como caso normal, não como erro.

### Formas especiais

Reações **não** aparecem como mensagens próprias: elas vêm no campo `reactions` da mensagem reagida. Mensagens de sistema e não suportadas vêm com o tipo explícito e sem corpo — `text`, `media` e `raw` nulos.

<Note>
  O campo **`raw` está fora de contrato**. Ele carrega a forma interna do conteúdo, útil para os tipos que os campos próprios não cobrem, e **pode mudar sem aviso** — inclusive entre versões sem nota de mudança. Não construa integração que dependa da forma dele.
</Note>

Esta leitura também não traz contagem de mensagens da conversa; veja a nota em `GET /v1/conversations`.



## OpenAPI

````yaml /openapi.json get /conversations/{conversation_id}/messages
openapi: 3.1.0
info:
  title: API WizeBot
  version: 3.0.0
  description: >-
    A API da WizeBot tem duas camadas sobre a **mesma base**
    `https://api.wizebot.com.br/v1`.


    **Contrato multicanal** — a camada neutra. Os mesmos endpoints falam com
    WhatsApp, com Telegram e com os canais que vierem depois. O canal não
    aparece na URL nem no corpo: ele vem da conta escolhida como remetente.
    Campos, códigos e mensagens em inglês.


    **API de WhatsApp** — a camada específica do canal, com o que só o WhatsApp
    tem. Continua existindo e não muda; quem já integrou com ela não precisa
    migrar.


    Toda requisição se autentica por cabeçalho. Não há autenticação por corpo
    nem por query string.
servers:
  - url: https://api.wizebot.com.br/v1
    description: Produção
security:
  - bearerAuth: []
tags:
  - name: Canais
    description: Contas de canal conectadas e o que cada uma aceita.
  - name: Mensagens
    description: Envio e status pelo contrato neutro, em qualquer canal.
  - name: WhatsApp · Mensagens
    description: Envio, status e modelos na camada específica de WhatsApp.
  - name: WhatsApp · Contatos
    description: Contatos e campos personalizados.
  - name: WhatsApp · Etiquetas
    description: Etiquetas e sua atribuição a contatos.
  - name: WhatsApp · Sequências
    description: Sequências agendadas de um contato.
  - name: WhatsApp · Conta
    description: Verificação da chave de API.
  - name: Conversas
    description: Leitura de diagnóstico das conversas — o que está esperando resposta.
paths:
  /conversations/{conversation_id}/messages:
    get:
      tags:
        - Conversas
      summary: Ler mensagens de uma conversa
      description: >-
        Do mais recente para o mais antigo, por cursor. A entrada é só o
        `conversation_id`.


        ### A janela recente


        **Sem `since`, a leitura cobre os últimos 30 dias.** Isso é decisão de
        produto, não limite técnico — medimos que a paginação profunda é barata
        e de custo constante, então o teto não existe para proteger o servidor.
        Ele existe para separar *ler a conversa* de *baixar o histórico
        inteiro*: para alcançar o que está além da janela, informe `since` e a
        intenção fica declarada na requisição.


        A resposta devolve em `window` a janela efetivamente aplicada, para você
        nunca precisar adivinhar.


        ### Mídia vem em dois passos


        A mensagem **nunca** traz URL nem caminho de armazenamento. Ela traz
        `media.media_id`; troque por um endereço temporário em `GET
        /v1/attachments/{media_id}`.


        <Warning>
          **Nem toda mensagem de mídia tem arquivo recuperável.** Quando `media.media_id` vier `null`, não chame o anexo — não há o que resolver. O bloco `media` nunca é omitido: se a mensagem é de mídia, ele existe, e `media_status` diz o que houve.
        </Warning>


        | `media_status` | O que significa | `media_id` |

        |---|---|---|

        | `available` | Arquivo registrado e recuperável | preenchido |

        | `unknown` | Mídia recebida antes do registro interno, ou cujo arquivo
        não foi guardado. É o caso da maior parte do histórico antigo | `null` |

        | `no_reference` | A mensagem não carrega nenhuma informação de mídia |
        `null` |


        Numa conversa com histórico longo, esperar que toda imagem resolva é a
        suposição errada — trate `media_id: null` como caso normal, não como
        erro.


        ### Formas especiais


        Reações **não** aparecem como mensagens próprias: elas vêm no campo
        `reactions` da mensagem reagida. Mensagens de sistema e não suportadas
        vêm com o tipo explícito e sem corpo — `text`, `media` e `raw` nulos.


        <Note>
          O campo **`raw` está fora de contrato**. Ele carrega a forma interna do conteúdo, útil para os tipos que os campos próprios não cobrem, e **pode mudar sem aviso** — inclusive entre versões sem nota de mudança. Não construa integração que dependa da forma dele.
        </Note>


        Esta leitura também não traz contagem de mensagens da conversa; veja a
        nota em `GET /v1/conversations`.
      operationId: lerMensagensDaConversa
      parameters:
        - name: conversation_id
          in: path
          required: true
          schema:
            type: string
        - name: since
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: Para ler além dos 30 dias recentes.
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 50
            maximum: 100
        - name: cursor
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Página de mensagens.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items:
                          type: object
                          properties:
                            message_id:
                              type: string
                            direction:
                              type: string
                              description: '`inbound` ou `outbound`.'
                            type:
                              type: string
                            status:
                              type:
                                - string
                                - 'null'
                            text:
                              type:
                                - string
                                - 'null'
                              description: >-
                                Texto ou legenda. `null` quando o tipo não
                                carrega texto — nunca um rótulo de interface.
                            media:
                              type:
                                - object
                                - 'null'
                              properties:
                                media_id:
                                  type:
                                    - string
                                    - 'null'
                                  description: >-
                                    Use em `GET /v1/attachments/{media_id}`.
                                    `null` em mensagem antiga sem referência.
                                media_status:
                                  type: string
                                  description: >-
                                    `available` (recuperável), `unknown`
                                    (histórico antigo, sem arquivo guardado) ou
                                    `no_reference` (sem informação de mídia).
                                mime_type:
                                  type:
                                    - string
                                    - 'null'
                                file_size:
                                  type:
                                    - integer
                                    - 'null'
                                filename:
                                  type:
                                    - string
                                    - 'null'
                            reactions:
                              type: array
                              items:
                                type: object
                              description: >-
                                Reações à ESTA mensagem. Reação não é item
                                próprio da linha do tempo.
                            sent_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                            delivered_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                            read_at:
                              type:
                                - string
                                - 'null'
                              format: date-time
                            failure_reason:
                              type:
                                - string
                                - 'null'
                            raw:
                              type:
                                - object
                                - 'null'
                              description: >-
                                **Fora de contrato.** Forma interna do conteúdo,
                                útil para tipos que os campos próprios não
                                cobrem. Pode mudar sem aviso.
                      next_cursor:
                        type:
                          - string
                          - 'null'
                      window:
                        type: object
                        properties:
                          recent_window_days:
                            type: integer
                          since:
                            type: string
                            format: date-time
                  timestamp:
                    type: string
                    format: date-time
              example:
                success: true
                data:
                  items:
                    - message_id: a1
                      direction: inbound
                      type: image
                      status: read
                      text: olha isto
                      media:
                        media_id: wamid.HBgN
                        media_status: available
                        mime_type: image/jpeg
                        file_size: 84213
                        filename: null
                      reactions: []
                      sent_at: '2026-09-13T02:44:51.602Z'
                      delivered_at: null
                      read_at: '2026-09-13T02:45:10.000Z'
                      failure_reason: null
                      raw:
                        mediaId: wamid.HBgN
                        caption: olha isto
                  next_cursor: null
                  window:
                    recent_window_days: 30
                    since: '2026-08-14T03:20:00.000Z'
                timestamp: '2026-09-13T03:20:00.000Z'
        '400':
          description: '`INVALID_PARAM` — limit must be an integer between 1 and 100.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErroDaApi'
              example:
                success: false
                statusCode: 400
                timestamp: '2026-09-13T03:20:00.000Z'
                path: /api/v1/conversations/{id}/messages
                method: GET
                message:
                  error: INVALID_PARAM
                  message: limit must be an integer between 1 and 100.
                errorId: ERR-MTUD0DBO-KKRMP8
        '401':
          description: '`UNAUTHORIZED` — Invalid or missing API key.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErroDaApi'
              example:
                success: false
                statusCode: 401
                timestamp: '2026-09-13T03:20:00.000Z'
                path: /api/v1/conversations
                method: GET
                message:
                  error: UNAUTHORIZED
                  message: Invalid or missing API key.
                errorId: ERR-MTUD0DBO-KKRMP8
        '404':
          description: '`CONVERSATION_NOT_FOUND` — Conversation not found.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErroDaApi'
              example:
                success: false
                statusCode: 404
                timestamp: '2026-09-13T03:20:00.000Z'
                path: /api/v1/conversations/{id}/messages
                method: GET
                message:
                  error: CONVERSATION_NOT_FOUND
                  message: Conversation not found.
                errorId: ERR-MTUD0DBO-KKRMP8
        '429':
          description: '`RATE_LIMITED` — Too many requests.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErroDaApi'
              example:
                success: false
                statusCode: 429
                timestamp: '2026-09-13T03:20:00.000Z'
                path: /api/v1/conversations
                method: GET
                message:
                  error: RATE_LIMITED
                  message: Too many requests.
                errorId: ERR-MTUD0DBO-KKRMP8
components:
  schemas:
    ErroDaApi:
      type: object
      description: >-
        Corpo de erro da API. `message` é um **objeto** com o código nomeado —
        não uma string.
      required:
        - success
        - statusCode
        - message
      properties:
        success:
          type: boolean
          description: Sempre `false`.
        statusCode:
          type: integer
        timestamp:
          type: string
          format: date-time
        path:
          type: string
          description: >-
            Caminho interno da requisição. Traz o prefixo `/api/v1` mesmo quando
            você chamou por `/v1`: o apelido é reescrito antes do roteamento.
        method:
          type: string
        message:
          type: object
          required:
            - error
            - message
          properties:
            error:
              type: string
              description: >-
                Código nomeado. É por ele que se trata o erro em código, nunca
                pelo texto.
            message:
              type: string
              description: Descrição em inglês, para leitura humana.
            details:
              type: object
              additionalProperties: true
              description: >-
                Contexto estruturado, presente nos códigos que o emitem —
                `CHANNEL_MISMATCH`, `NO_OPEN_CONVERSATION`,
                `RECIPIENT_NOT_ON_CHANNEL` e `UNSUPPORTED_CAPABILITY`.
        errorId:
          type: string
          description: Identificador do erro. Cite-o ao falar com o suporte.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Chave de API no cabeçalho `Authorization: Bearer SUA-CHAVE`.


        A API também aceita `x-api-key: SUA-CHAVE` e `Authorization: ApiKey
        SUA-CHAVE` — as três formas são equivalentes, inclusive para o limite de
        requisições.


        A chave dá acesso total à conta e é de servidor para servidor: não a use
        em navegador ou aplicativo móvel.

````