> ## 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.

# Anomalias de conversa

> Numa chamada, as contagens por balde e as piores conversas de cada um. É diagnóstico — responde "o que está errado agora", não "quais são minhas conversas". Não há paginação, e o número de itens tem teto.

**A janela tem teto superior, e é ele que faz o balde ser anomalia.** Só entram conversas cujo último recebimento está entre `threshold_hours` atrás e o teto da janela de atendimento do canal. Sem esse teto, o critério selecionaria o arquivo inteiro em vez da fila viva.

O teto é a janela de atendimento do próprio canal — no WhatsApp, 24 horas. Canais que não têm janela de atendimento usam **24 horas como padrão fixo**, que é o período natural de uma varredura diária. Você nunca precisa adivinhar qual valor valeu: a resposta devolve `window.ceiling_hours_by_channel` com o teto aplicado a cada canal.

**O resultado vale por alguns minutos, não é tempo real.** A resposta é servida de um cache curto por empresa e balde, então uma conversa que acabou de entrar na fila pode não aparecer na chamada seguinte. Este recurso foi feito para **varredura periódica** — uma passada por dia é o uso previsto, e o limite de requisições reflete isso. Para acompanhar a fila em tempo real, use a caixa de entrada.

**Dois baldes só respondem se você pedir.** `unassigned` e `automation_only` ficam de fora por padrão: em boa parte das operações, conversa sem atendente é o estado normal, e ligá-los sem querer produz um relatório em que tudo aparece como problema.

### Os quatro baldes

| Balde | O que é |
|---|---|
| `unanswered` | O contato falou e **nada saiu depois** — nem atendente, nem automação. |
| `unassigned` | Sem atendente responsável. Opcional. |
| `automation_only` | Houve resposta, mas **nenhuma de uma pessoa**. Opcional. |
| `never_engaged` | Nunca recebeu mensagem do contato. Só contagem, nunca lista. |

<Note>
  **Mensagem enviada pela sua própria integração conta como automação** em `automation_only`. Do nosso lado não há como distinguir um atendente clicando no seu CRM de um disparo agendado, e tratá-la como resposta humana esconderia conversas que ninguém de fato atendeu. Respostas pelo painel da WizeBot e pelo WhatsApp do próprio celular contam como humanas.
</Note>



## OpenAPI

````yaml /openapi.json get /conversations/anomalies
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/anomalies:
    get:
      tags:
        - Conversas
      summary: Anomalias de conversa
      description: >-
        Numa chamada, as contagens por balde e as piores conversas de cada um. É
        diagnóstico — responde "o que está errado agora", não "quais são minhas
        conversas". Não há paginação, e o número de itens tem teto.


        **A janela tem teto superior, e é ele que faz o balde ser anomalia.** Só
        entram conversas cujo último recebimento está entre `threshold_hours`
        atrás e o teto da janela de atendimento do canal. Sem esse teto, o
        critério selecionaria o arquivo inteiro em vez da fila viva.


        O teto é a janela de atendimento do próprio canal — no WhatsApp, 24
        horas. Canais que não têm janela de atendimento usam **24 horas como
        padrão fixo**, que é o período natural de uma varredura diária. Você
        nunca precisa adivinhar qual valor valeu: a resposta devolve
        `window.ceiling_hours_by_channel` com o teto aplicado a cada canal.


        **O resultado vale por alguns minutos, não é tempo real.** A resposta é
        servida de um cache curto por empresa e balde, então uma conversa que
        acabou de entrar na fila pode não aparecer na chamada seguinte. Este
        recurso foi feito para **varredura periódica** — uma passada por dia é o
        uso previsto, e o limite de requisições reflete isso. Para acompanhar a
        fila em tempo real, use a caixa de entrada.


        **Dois baldes só respondem se você pedir.** `unassigned` e
        `automation_only` ficam de fora por padrão: em boa parte das operações,
        conversa sem atendente é o estado normal, e ligá-los sem querer produz
        um relatório em que tudo aparece como problema.


        ### Os quatro baldes


        | Balde | O que é |

        |---|---|

        | `unanswered` | O contato falou e **nada saiu depois** — nem atendente,
        nem automação. |

        | `unassigned` | Sem atendente responsável. Opcional. |

        | `automation_only` | Houve resposta, mas **nenhuma de uma pessoa**.
        Opcional. |

        | `never_engaged` | Nunca recebeu mensagem do contato. Só contagem,
        nunca lista. |


        <Note>
          **Mensagem enviada pela sua própria integração conta como automação** em `automation_only`. Do nosso lado não há como distinguir um atendente clicando no seu CRM de um disparo agendado, e tratá-la como resposta humana esconderia conversas que ninguém de fato atendeu. Respostas pelo painel da WizeBot e pelo WhatsApp do próprio celular contam como humanas.
        </Note>
      operationId: anomaliasDeConversa
      parameters:
        - name: buckets
          in: query
          required: false
          schema:
            type: string
          description: >-
            Baldes adicionais, separados por vírgula: `unassigned`,
            `automation_only`. `unanswered` e `never_engaged` vêm sempre, peça
            ou não.
          example: unassigned,automation_only
        - name: threshold_hours
          in: query
          required: false
          schema:
            type: integer
            default: 4
            minimum: 1
            maximum: 24
          description: >-
            Há quantas horas o recebimento precisa estar sem resposta para
            entrar.
          example: 4
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 20
            maximum: 100
          description: Quantas conversas trazer por balde. Teto de 100.
      responses:
        '200':
          description: Contagens e as piores conversas de cada balde.
          content:
            application/json:
              schema:
                type: object
                required:
                  - success
                  - data
                  - timestamp
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      window:
                        type: object
                        properties:
                          threshold_hours:
                            type: integer
                          ceiling_hours_by_channel:
                            type: object
                            additionalProperties:
                              type: integer
                            description: >-
                              Teto da janela por canal, para você entender por
                              que uma conversa entrou ou não.
                      buckets:
                        type: object
                        additionalProperties:
                          type: object
                          properties:
                            count:
                              type: integer
                              description: >-
                                Total no balde — pode ser maior que o número de
                                itens devolvidos.
                            items:
                              type: array
                              items:
                                type: object
                                properties:
                                  conversation_id:
                                    type: string
                                  contact_id:
                                    type: string
                                  channel:
                                    type: string
                                    description: Canal da conversa.
                                  channel_account_id:
                                    type:
                                      - string
                                      - 'null'
                                  last_inbound_at:
                                    type:
                                      - string
                                      - 'null'
                                    format: date-time
                                  last_message_at:
                                    type:
                                      - string
                                      - 'null'
                                    format: date-time
                                  waiting_hours:
                                    type:
                                      - number
                                      - 'null'
                                    description: Horas desde a última mensagem recebida.
                                  assigned:
                                    type: boolean
                                  unread_count:
                                    type: integer
                              description: >-
                                As piores primeiro. Ausente em `never_engaged`,
                                que é só contagem.
                  timestamp:
                    type: string
                    format: date-time
              example:
                success: true
                data:
                  window:
                    threshold_hours: 4
                    ceiling_hours_by_channel:
                      whatsapp: 24
                      sms: 24
                      telegram: 24
                      webchat: 24
                  buckets:
                    unanswered:
                      count: 7
                      items:
                        - conversation_id: 6e0a32b9-4237-4753-a2f2-e392313bf457
                          contact_id: 03309ad5-3949-4abd-b688-5a52a08b9ec7
                          channel: whatsapp
                          channel_account_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                          last_inbound_at: '2026-09-12T02:30:31.382Z'
                          last_message_at: '2026-09-12T02:30:31.382Z'
                          waiting_hours: 19.8
                          assigned: false
                          unread_count: 1
                    never_engaged:
                      count: 3
                timestamp: '2026-09-12T19:15:20.453Z'
        '400':
          description: >-
            `INVALID_BUCKET` — Unknown bucket(s): foo. Valid buckets:
            unanswered, unassigned, automation_only, never_engaged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErroDaApi'
              example:
                success: false
                statusCode: 400
                timestamp: '2026-09-12T19:15:20.453Z'
                path: /api/v1/conversations/anomalies
                method: GET
                message:
                  error: INVALID_BUCKET
                  message: >-
                    Unknown bucket(s): foo. Valid buckets: unanswered,
                    unassigned, automation_only, never_engaged.
                  details:
                    valid_buckets:
                      - unanswered
                      - unassigned
                      - automation_only
                      - never_engaged
                    opt_in:
                      - unassigned
                      - automation_only
                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-12T19:15:20.453Z'
                path: /api/v1/conversations/anomalies
                method: GET
                message:
                  error: UNAUTHORIZED
                  message: Invalid or missing API key.
                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-12T19:15:20.453Z'
                path: /api/v1/conversations/anomalies
                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.

````