Prospecção (API)

Contato + etiquetas + card no funil numa chamada só — o endpoint pensado para automações de captação (n8n, planilhas, scraping).

Quando usar

POST /v1/prospects substitui a sequência POST /v1/contactsPOST /v1/contacts/{id}/tagsPOST /v1/cards que uma automação de prospecção fazia em 2 a 4 chamadas. Numa chamada só ele:

  1. cria ou completa o contato (upsert por telefone, igual ao POST /v1/contacts);
  2. aplica etiquetas (por nome ou por id);
  3. grava a nota, se houver;
  4. cria o card na etapa pedida — ou decide que não deve criar, e diz por quê.

Use contacts + cards separados quando o fluxo já sabe que o contato existe (ex.: reagir a uma resposta) ou quando você precisa decidir a etapa depois de olhar dados que só a API tem. Use prospects quando o ponto de partida é uma lista externa (raspagem, planilha, CRM de terceiro) e a intenção é sempre a mesma: "cadastre e comece a prospecção".

Este endpoint nunca envia mensagem. Ele só cadastra e move o card — quem aborda o lead é o Maestro (automação), disparado pelo card entrando na etapa. Ver Etiquetas e o Maestro abaixo.

Contrato

curl -X POST https://www.scalacrm.com/api/v1/prospects \
  -H "Authorization: Bearer sk_live_…" \
  -H "Idempotency-Key: prospeccao-2026-09-16-0042" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "5551999998888",
    "stage_id": "9f8e…",
    "name": "Maria Silva",
    "tags": ["Lead frio", "Planilha setembro"],
    "note": "Encontrada na raspagem do site X",
    "check_whatsapp": true
  }'
campotipoobrigatóriotetoobservação
phonestringsim8–30 charsqualquer formato com DDI+DDD+número
stage_iduuidsimetapa onde o card nasce (GET /v1/pipelines)
namestringnão160
emailstringnão255
notestringnão2000vira nota no contato — só na criação; um retry (mesma Idempotency-Key) não duplica
tagsstring[]não20 itens, 40 chars cadapor nome — cria a etiqueta se ela ainda não existir
tag_idsuuid[]não20por id, se você já sabe qual é (GET /v1/tags)
source"import" | "manual" | "ads"nãosó na criação, e só quando não há sinal de anúncio (ver abaixo)
utmobjetonãoutm_source/medium/campaign/term/content, 120–200 chars cada
custom_fieldsobjetonãosó preenche chaves já criadas em Configurações → Preferências; chave desconhecida volta em ignored_fields
titlestringnão160texto do card; padrão é o nome do contato
value_centsnumbernão0–1.000.000.000valor estimado do card
check_whatsappbooleannãoconsulta se o número tem WhatsApp antes de decidir o card (ver abaixo)

tags e tag_ids podem ser usados juntos — o conjunto final é a união dos dois, sem duplicar.

Resposta

{
  "ok": true,
  "contact_id": "3f9a…",
  "created": true,
  "card_id": "8b1c…",
  "skipped": null,
  "whatsapp": "exists"
}
  • created: false significa que o telefone já existia — os campos vazios foram completados, os preenchidos ficaram como estavam (mesma regra do POST /v1/contacts).
  • card_id só vem preenchido quando um card foi criado (skipped: null) ou quando o contato já tinha um card ativo (skipped: "has_active_card") — nos outros dois casos, card_id é null.
  • whatsapp só aparece na resposta quando você mandou check_whatsapp: true.

Os 3 motivos de skipped

O contato (e as etiquetas, e a nota) são sempre gravados — o que muda é se o card é criado. skipped conta o primeiro motivo que se aplicar, nesta ordem de prioridade:

skippedmotivoo que acontece com o card
opt_outo contato pediu para parar (contact_optouts) ou tem a etiqueta "opt-out" — inclusive uma que esta própria chamada acabou de aplicarnenhum card é criado
no_whatsappcheck_whatsapp: true foi enviado e o número não tem WhatsAppnenhum card é criado
has_active_cardo contato já tem um card ativo em algum funilnão é movido — mover um card de "Reunião agendada" de volta para "Entrada" seria destrutivo; a resposta devolve o card_id do card existente, sem tocar nele
nullnenhum dos trêso card é criado normalmente, na etapa pedida

source não desliga a origem de anúncio

O source escolhe a origem só quando não há sinal de anúncio nenhum no que você mandou. Se o payload trouxer utm, click_ids ou lead_ads, o contato nasce como Anúncio (ads) e o source declarado é ignorado.

Isso é de propósito: é a origem ads que dispara os eventos de conversão para Meta e Google. Um {"click_ids": {"gclid": "…"}, "source": "import"} que nascesse import guardaria o gclid na ficha e nunca o mandaria de volta para o Google — o clique pago viraria um lead sem conversão, e nada na tela acusaria.

Na prática: use source para dizer de onde veio um lead sem rastreio (import para planilha, manual para cadastro a mão). Com rastreio, deixe o rastreio falar.

whatsapp: exists / missing / unknown

Com check_whatsapp: true, a resposta traz um dos três valores:

  • exists — o número tem WhatsApp confirmado.
  • missing — a consulta rodou e o número não tem WhatsApp.
  • unknown — não deu para consultar (conexão WhatsApp Lite não configurada na conta, falha na consulta, ou a resposta veio sem o número). Isso não é o mesmo que "não tem WhatsApp".

Só marque o número como morto quando vier missing; unknown significa que não deu para consultar. Um unknown tratado como morto apagaria um lead que pode estar perfeitamente vivo — é por isso que só missing vira skipped: "no_whatsapp"; unknown nunca bloqueia a criação do card.

⚠️ Use check_whatsapp para decidir, nunca para varrer a base. A consulta usa a sessão pareada do seu WhatsApp Lite — é o seu número perguntando ao WhatsApp se cada número existe. Checar listas grandes em alta velocidade é exatamente o comportamento que o WhatsApp associa a spam, e pode levar ao bloqueio do número. Mande a flag quando o resultado vai mudar o que você faz com aquele lead; jamais numa varredura de planilha.

Etiquetas e o Maestro

O gatilho Lead novo cadastrado do Maestro (Automações) é enfileirado no insert do contato — mas as condições da regra (etiqueta, origem, etc.) são avaliadas quando o job roda (a cada minuto), lendo as etiquetas do contato naquele momento, não as que existiam no instante do insert.

Na prática isso significa que etiquetar na mesma chamada funciona: se você manda tags: ["Lead frio"] junto com a criação do contato, e sua regra do Maestro tem a condição "etiqueta = Lead frio", a regra casa — porque quando o job avalia a condição (alguns segundos depois), a etiqueta já está gravada.

Quero saber quando o lead muda de etapa

Duas formas, conforme o que você precisa:

  • Webhook de saída card.stage_changed (Configurações → Integrações → Webhooks): dispara toda vez que um card muda de etapa — inclusive quando o card nasce por este endpoint e é movido depois pelo Maestro ou por um atendente. O payload traz card_id, contact_id, pipeline_id e from_stage/to_stage (cada um com id e nome).
  • Passo "Enviar webhook (POST)" do Maestro, no gatilho Lead entrou numa etapa do funil: se você já tem uma regra de automação reagindo à entrada numa etapa específica, acrescente um passo "Enviar webhook (POST)" nela — é a forma mais direta de notificar sua automação SEM assinar um webhook global.

Para reunião marcada, o webhook de saída é appointment.created (mesmo menu de Webhooks).

Veja também