Contatos (API)

Criar, consultar, filtrar e corrigir contatos — e aplicar etiquetas.

Listar e filtrar

curl "https://www.scalacrm.com/api/v1/contacts?origin=ads&created_after=2026-08-01T00:00:00Z" \
  -H "Authorization: Bearer sk_live_…"
filtroexemplo
phone5551999998888 (aceita com ou sem o nono dígito)
emailmaria@empresa.com
searchmaria — busca em nome, e-mail e (com ≥4 dígitos) telefone
originads, organic, import, manual, api
tag_idsó contatos com a etiqueta
company_id / owner_user_idpor empresa ou responsável
created_after / created_beforedata ISO
updated_afterdata ISO — "o que mudou desde a última sincronização"
qualifiedtrue — só os marcados como qualificados
limit / cursorver paginação

origin=ads é mais esperto do que parece. Ele considera lead de anúncio quem tem source='ads' ou referral de anúncio gravado — porque lead de Lead Ads às vezes chega com o referral e sem o source. É a mesma régua do filtro "De anúncio" da tela de Contatos, então API e CRM nunca discordam sobre o mesmo lead.

Consultar um contato

curl https://www.scalacrm.com/api/v1/contacts/3f9a… \
  -H "Authorization: Bearer sk_live_…"

Vem com todos os números do contato e o card ativo no funil — que é o que a automação precisa para decidir entre criar e mover, sem uma segunda chamada.

{
  "ok": true,
  "contact": { "id": "3f9a…", "name": "Maria", "wa_id": "5551999998888", "source": "ads", … },
  "identities": [{ "wa_id": "5551999998888", "is_primary": true }],
  "active_card": { "id": "8b1c…", "stage_id": "7c2b…", "stage_name": "Em conversa" }
}

Criar

curl -X POST https://www.scalacrm.com/api/v1/contacts \
  -H "Authorization: Bearer sk_live_…" \
  -H "Idempotency-Key: form-2026-08-05-0042" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "5551999998888",
    "name": "Maria Silva",
    "email": "maria@empresa.com",
    "utm": { "utm_source": "google", "utm_campaign": "institucional" }
  }'

Resposta: { "ok": true, "contact_id": "3f9a…", "created": true }.

created: false significa que o telefone já existia — os campos vazios foram completados, os preenchidos ficaram como estavam.

Não cria card no funil. É diferente do endpoint antigo, que criava por padrão. Aqui os dois recursos são independentes: para colocar o lead no funil, chame POST /v1/cards escolhendo a etapa. Nada acontece que você não tenha pedido.

Lead de anúncio (Lead Ads, click IDs, campos do formulário)

O POST /v1/contacts aceita os mesmos blocos de atribuição do endpoint antigo:

{
  "phone": "5551999998888",
  "name": "Maria Silva",
  "utm": { "utm_source": "meta", "utm_medium": "conjunto-x", "utm_campaign": "captacao" },
  "lead_ads": {
    "leadgen_id": "1234567890",
    "form_id": "111",
    "ad_id": "222",
    "ad_name": "Criativo A",
    "campaign_name": "Captação agosto"
  },
  "click_ids": { "fbclid": "IwAR…" },
  "note": "Lead do Facebook Lead Ads",
  "custom_fields": { "leads_por_dia": "10 a 20" }
}
  • lead_ads.leadgen_id é o identificador mais forte para a Meta atribuir a conversão de volta ao formulário (Conversion Leads) — sempre envie quando o lead vier de Lead Ads.
  • click_ids aceita fbclid, gclid, gbraid e wbraid, sempre crus (a plataforma monta o formato final no envio da conversão).
  • Com utm, lead_ads ou click_ids presentes, o contato nasce com origem Anúncio — é o que dispara os eventos de conversão configurados na conta.
  • note vira uma nota no contato, só na criação (o retry da automação não duplica).
  • custom_fields só preenche chaves já criadas em Configurações → Preferências; chave desconhecida volta em ignored_fields, nunca é descartada calada.
  • tag_ids aplica etiquetas já na criação (liste-as com GET /v1/tags); idempotente — repetir não duplica.

Corrigir

curl -X PATCH https://www.scalacrm.com/api/v1/contacts/3f9a… \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Maria Silva Souza", "custom_fields": { "cnpj": "12345678000190" } }'

Campos personalizados só aceitam chaves já criadas em Configurações → Preferências. Chave desconhecida volta em ignored_fields — a API não inventa campo, e também não descarta calada.

O PATCH também corrige atribuição (utm e click_ids) — aqui a semântica é sobrescrever (é correção explícita; null limpa), diferente do POST, que só completa o que está vazio.

Qualificar o lead

curl -X PATCH https://www.scalacrm.com/api/v1/contacts/3f9a… \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "qualified": true }'

É o mesmo efeito do botão "Qualificar" da tela: marca o lead no CRM e dispara o evento QualifiedLead para as plataformas de anúncio configuradas na conta — com o mesmo dedupe (1 evento por contato, para sempre; repetir a chamada não reenvia). Opcional: qualified_value_cents manda um valor junto; sem ele, vale o valor do card ativo no funil.

Efeito externo real. Esse evento alimenta a otimização das campanhas do cliente na Meta/Google. Só qualifique por automação quando o critério for confiável — qualificar todo mundo ensina o algoritmo errado.

Etiquetas

# quais existem na conta
curl https://www.scalacrm.com/api/v1/tags -H "Authorization: Bearer sk_live_…"

# etiquetar
curl -X POST https://www.scalacrm.com/api/v1/contacts/3f9a…/tags \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "tag_id": "5d3e…" }'

# desetiquetar
curl -X DELETE "https://www.scalacrm.com/api/v1/contacts/3f9a…/tags?tag_id=5d3e…" \
  -H "Authorization: Bearer sk_live_…"

As duas operações são idempotentes: etiquetar quem já está etiquetado (ou remover quem já não está) devolve sucesso.

Para criar uma etiqueta nova, POST /v1/tags com { "name": "Cliente VIP" }. Nome repetido devolve a existente em vez de duplicar.

Veja também