Lead Scoring

Sistema de pontuação de leads baseado em eventos. Cada regra define um tipo de evento (mensagem recebida, resposta, mudança de estágio, etc.) e quantos pontos adicionar ao score.

Como Funciona

O lead score é calculado automaticamente com base em regras de eventos. Cada regra define um event_type (ex: message_received, first_response, stage_changed) e ospoints a aplicar quando o evento ocorre. O score acumulado vai de 0 a 100.

Regras de Score

Somente administradores

Todas as rotas de /lead_score_rules — inclusive a listagem e o detalhe — exigem administrador da conta. Para qualquer outro usuário a resposta é 403 com { "error": "forbidden" }. Uma regra de outra conta ou inexistente retorna 404.

GET/api/v1/accounts/{account_id}/lead_score_rules

Lista todas as regras de lead scoring da conta, ordenadas por priority (maior primeiro) e, em empate, pela mais recente.

bash
curl -s "https://chat.seudominio.com/api/v1/accounts/1/lead_score_rules" \
  -H "api_access_token: YOUR_TOKEN" | jq .
200Lista de regras
json
[
  {
    "id": 3,
    "event_type": "first_response",
    "event_subtype": null,
    "points": 10,
    "enabled": true,
    "priority": 15,
    "cooldown_minutes": 0,
    "name": "First Response",
    "description": "Lead got first response",
    "conditions": {},
    "created_at": "2026-08-01T12:00:00.000Z",
    "updated_at": "2026-08-01T12:00:00.000Z"
  },
  {
    "id": 1,
    "event_type": "message_received",
    "event_subtype": null,
    "points": 5,
    "enabled": true,
    "priority": 10,
    "cooldown_minutes": 5,
    "name": "Message Received",
    "description": "Lead sent a message",
    "conditions": {},
    "created_at": "2026-08-01T12:00:00.000Z",
    "updated_at": "2026-08-01T12:00:00.000Z"
  }
]
POST/api/v1/accounts/{account_id}/lead_score_rules

Cria uma nova regra de scoring. O corpo pode vir direto no topo (como no exemplo) ou envolto em lead_score_rule.

Body

NomeTipoObrigatorioDescricao
event_typestringSimTipo de evento: message_received, message_sent, first_response, stage_changed, card_created, card_assigned, label_added, label_removed, conversation_opened, conversation_resolved, conversation_reopened, contact_profile_updated, contact_email_added, contact_phone_added, agent_assigned, agent_replied, custom_event
pointsintegerSimPontos a adicionar (positivo) ou remover (negativo) quando o evento ocorre. Faixa aceita: -100 a 100.
namestringNaoNome descritivo da regra
descriptionstringNaoDescrição detalhada
event_subtypestringNaoSubtipo do evento para filtros mais específicos
conditionsobjectNaoCondições adicionais para aplicar a regra
enabledbooleanNaoRegra ativa (padrão: true)
priorityintegerNaoPrioridade de execução (padrão: 0)
cooldown_minutesintegerNaoTempo mínimo entre aplicações da regra (padrão: 0; não pode ser negativo)
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/lead_score_rules" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "first_response",
    "points": 10,
    "name": "Primeira resposta rapida",
    "enabled": true
  }'
200Regra criada (mesmo objeto da listagem; esta rota responde 200, não 201)
json
{
  "id": 12,
  "event_type": "first_response",
  "event_subtype": null,
  "points": 10,
  "enabled": true,
  "priority": 0,
  "cooldown_minutes": 0,
  "name": "Primeira resposta rapida",
  "description": null,
  "conditions": {},
  "created_at": "2026-09-27T12:00:00.000Z",
  "updated_at": "2026-09-27T12:00:00.000Z"
}
422Validação falhou (event_type fora da lista, points fora de -100..100, cooldown negativo). O texto de message segue o idioma da conta; attributes lista os campos rejeitados.
json
{
  "message": "Points must be less than or equal to 100",
  "attributes": ["points"]
}
GET/api/v1/accounts/{account_id}/lead_score_rules/{id}

Retorna uma regra de scoring da conta.

bash
curl -s "https://chat.seudominio.com/api/v1/accounts/1/lead_score_rules/12" \
  -H "api_access_token: YOUR_TOKEN" | jq .
200Regra (mesmo objeto da listagem, sem wrapper)
json
{
  "id": 12,
  "event_type": "first_response",
  "event_subtype": null,
  "points": 10,
  "enabled": true,
  "priority": 0,
  "cooldown_minutes": 0,
  "name": "Primeira resposta rapida",
  "description": null,
  "conditions": {},
  "created_at": "2026-09-27T12:00:00.000Z",
  "updated_at": "2026-09-27T12:00:00.000Z"
}
PATCH/api/v1/accounts/{account_id}/lead_score_rules/{id}

Atualiza parcialmente uma regra. Aceita os mesmos campos da criação (no topo do corpo ou em lead_score_rule), com as mesmas validações. Responde 200 com a regra atualizada. PUT é aceito como alias.

DELETE/api/v1/accounts/{account_id}/lead_score_rules/{id}

Remove uma regra. Responde 200 com corpo vazio. O histórico de pontuação já gerado por ela é mantido, sem o vínculo com a regra.

POST/api/v1/accounts/{account_id}/lead_score_rules/create_defaults

Inicializa regras padrão de scoring para a conta e responde 200 com a lista completa de regras (mesmo formato da listagem).

Regras Padrão

Cria nove regras de evento, todas habilitadas: message_received (5 pontos), message_sent (2), first_response (10), conversation_opened (3), conversation_resolved (15), stage_changed (10), contact_email_added (8), contact_phone_added (8) e label_added (5). O cooldown é de 5 minutos para as duas regras de mensagem, 60 minutos para stage_changed e label_added, e zero para as demais.

A operação pode ser repetida: um event_type que já tenha qualquer regra na conta é pulado, e regras existentes não são alteradas.

Score do Card

PATCH/api/v1/accounts/{account_id}/pipeline_cards/{id}/update_qualification_checklist

Atualiza o checklist de qualificação do card (afeta o score).

Body

NomeTipoObrigatorioDescricao
qualification_checklistobjectSimObjeto onde cada chave é um criterion_id e o valor é um objeto com campos: id, name, checked (boolean), points (integer), required (boolean), category, notes
bash
curl -X PATCH "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards/5/update_qualification_checklist" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "qualification_checklist": {
      "budget_confirmed": {
        "id": "budget_confirmed",
        "name": "Orcamento confirmado",
        "checked": true,
        "points": 20,
        "required": true,
        "category": "qualification"
      },
      "decision_maker": {
        "id": "decision_maker",
        "name": "Decisor identificado",
        "checked": false,
        "points": 15,
        "required": false,
        "category": "qualification"
      }
    }
  }'
POST/api/v1/accounts/{account_id}/pipeline_cards/{id}/recalculate_score

Força o recálculo do lead score de um card (rota legacy). Síncrona: a resposta já traz o score recalculado.

bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards/5/recalculate_score" \
  -H "api_access_token: YOUR_TOKEN"
200Score recalculado (resposta direta, sem wrapper)
json
{
  "id": 5,
  "recalculated": true,
  "lead_score": 78,
  "lead_score_category": "hot",
  "qualification_score": 40,
  "lead_score_factors": {
    "conversation_activity": 20,
    "message_volume": 15,
    "time_in_pipeline": 15,
    "profile_completeness": 10,
    "stage_position": 8,
    "recent_activity": 10
  },
  "lead_score_updated_at": "2026-08-10T14:32:10.000Z",
  "updated_at": "2026-08-10T09:15:44.000Z",
  "card_updated_at": "2026-08-10T09:15:44.000Z"
}

Campos adicionados em 2026-08

Esta resposta ganhou id, lead_score_category, updated_at e card_updated_at. A mudança é aditiva: lead_score, qualification_score, lead_score_factors e lead_score_updated_at continuam com o mesmo nome e o mesmo significado.

Nesta rota, updated_at e card_updated_at trazem o mesmo valor: o do card. Repare que ele é mais antigo que lead_score_updated_at — recalcular o score grava direto nas colunas de score e não toca no updated_at do card. Um card_updated_at"parado" logo após um recálculo é o comportamento esperado, não um bug.

Override Manual

Para definir manualmente o lead score de um card use o endpoint dedicado de override. O campo lead_score não é aceito no PATCH do card — ele é calculado pelo motor de scoring e só pode ser sobrescrito por esta rota.

POST/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/lead_scores/override

Sobrescreve manualmente o lead score de um card.

Body

NomeTipoObrigatorioDescricao
scoreintegerSimScore manual a aplicar. Inteiro entre 0 e 100 — valor ausente ou fora da faixa retorna 422.
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline/cards/5/lead_scores/override" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "score": 85 }'
200Score sobrescrito
json
{ "lead_score": 85, "manual_override": true }
POST/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/lead_scores/recalculate

Recalcula o score do card (rota canônica do namespace pipeline). Difere da rota legacy em cards com override manual — veja o aviso abaixo.

200Score recalculado (resposta direta, sem wrapper)
json
{
  "recalculated": true,
  "lead_score": 78,
  "lead_score_factors": {
    "conversation_activity": 20,
    "message_volume": 15,
    "time_in_pipeline": 15,
    "profile_completeness": 10,
    "stage_position": 8,
    "recent_activity": 10
  },
  "lead_score_category": "hot",
  "updated_at": "2026-08-10T14:32:10.000Z",
  "lead_score_updated_at": "2026-08-10T14:32:10.000Z",
  "card_updated_at": "2026-08-10T09:15:44.000Z"
}

As duas rotas de recálculo NÃO têm o mesmo efeito

Esta documentação afirmava que as duas rotas eram equivalentes. Elas divergem exatamente onde importa, e o campo recalculated existe para você distinguir "recalculei e deu isto" de "não recalculei":

  • Card com override manual — a rota canônica devolve recalculated: false e preserva o score fixado. A rota legacy /recalculate_score sobrescreve o override: ela trata a chamada como uma ação manual do usuário, que pode desfazer o valor que ele mesmo fixou.
  • Conta com Lead Score por regras ativo — nesse modo o score é acumulado pelas regras de evento, e nenhuma das duas rotas o sobrescreve com o cálculo heurístico. As duas devolvem recalculated: false e o score atual.

Em todos os casos os campos de score na resposta trazem o valor vigente — o que muda é se ele acabou de ser recalculado.

updated_at não significa a mesma coisa nas duas rotas

Nesta rota canônica, updated_at sempre carregou o timestamp do cálculo do score, não o do card. O nome ficou como estava para não quebrar quem já consome esse campo, e os dois timestamps ganharam nome próprio:

  • lead_score_updated_at — quando o score foi calculado. Nesta rota é idêntico a updated_at.
  • card_updated_at — quando o card foi atualizado. Existe nas duas rotas de recálculo, com o mesmo significado. Normalmente é mais antigo que lead_score_updated_at: o recálculo grava direto nas colunas de score e não toca no updated_at do card.

Na rota legacy /pipeline_cards/{id}/recalculate_score, updated_at carrega o timestamp do card. Se você chama as duas rotas, leia card_updated_at e lead_score_updated_at — são os únicos campos que significam a mesma coisa em ambas.

GET/api/v1/accounts/{account_id}/pipeline/lead_scores/distribution

Distribuição de scores dos cards visíveis ao usuário (categorias hot/warm/cold).

200Distribuição de scores (resposta direta, sem wrapper data)
json
{
  "hot": 8,
  "warm": 18,
  "cold": 16,
  "total": 42,
  "average": 52.3
}

Logs de Score

GET/api/v1/accounts/{account_id}/lead_score/logs

Histórico de mudanças de score.

GET/api/v1/accounts/{account_id}/lead_score/logs/{id}

Detalhes de uma mudança de score.

Relatórios de Lead Score

GET/api/v1/accounts/{account_id}/lead_score/reports/dashboard

Dashboard de lead scoring.

GET/api/v1/accounts/{account_id}/lead_score/reports/distribution

Distribuição detalhada de scores.

GET/api/v1/accounts/{account_id}/lead_score/reports/trends

Tendências de scoring ao longo do tempo.

GET/api/v1/accounts/{account_id}/lead_score/reports/top_leads

Ranking dos leads com maior score.

GET/api/v1/accounts/{account_id}/lead_score/reports/category_changes

Histórico de mudanças de categoria (frio, morno, quente).

POST/api/v1/accounts/{account_id}/lead_score/reports/bulk_recalculate

Reconstrói o score de todos os cards da conta a partir do histórico de pontuação. Assíncrono: responde 202 e o resultado chega por notificação.

O recálculo em massa reconstrói do histórico — e só age quando existe histórico

Este endpoint refaz o score de cada card reproduzindo o histórico de pontuação por regras (os registros que você lê em /lead_score/logs), na ordem em que aconteceu.

  • Conta sem Lead Score por regras — o score vem do cálculo heurístico, que não gera histórico. Nesse caso o job não altera nada e a notificação explica o motivo: reconstruir a partir de um histórico vazio zeraria a base inteira.
  • Card sem nenhum registro de pontuação— fica como está. Sem histórico não há o que reconstruir, e zero não é o mesmo que "recalculei e deu zero".
  • Card com override manual — nunca entra no lote.