Referência da API

Leads (Oportunidades)

Enviar leads para o funil comercial via API ou webhooks de entrada, com rastreabilidade de origem, canal, mídia e campanha.

Leads (Oportunidades)

Envie leads para o funil comercial do OctaBuild por dois caminhos:

CaminhoAutenticaçãoUso típico
POST /v1/oportunidadesAPI Key (Authorization: Bearer)Integrações servidor-a-servidor
POST /api/webhooks/inbound/{token}Token na URL + segredo opcionalTypebot, Zapier, n8n, landing pages, parceiros

Ambos criam a pessoa (lead), a oportunidade, o touchpoint de conversão e disparam a distribuição automática (roleta) numa única transação — a menos que a requisição peça o contrário (ver Distribuição abaixo).

O corpo da requisição segue um contrato fixo — as mesmas chaves para todas as fontes e todos os tenants, no nível raiz do JSON. Não há mapeamento de campos por webhook: a fonte deve enviar os nomes de campo documentados aqui.


Rastreabilidade

Todo lead carrega uma hierarquia de atribuição:

NívelO que respondeComportamento na API
OrigemQuem cadastrou (Corretor, Marketing, SDR, Correspondente, Gestor, Imobiliária Parceira)Nunca criada pela API. No webhook, vem do cadastro da fonte; na API v1, o campo origin aceita um slug existente — inválido/ausente cai em marketing.
CanalOnde foi captado (Instagram, Google, Site, OLX…)Nunca criado pela API. Resolvido por slug ou nome contra o catálogo do painel; desconhecido → fica vazio (o texto bruto é preservado no touchpoint).
MídiaComo foi captado (Mídia Paga, Mídia Orgânica)Nunca criada pela API. Mesma resolução do canal.
Campanha → Conjunto → AnúncioQual campanha/conjunto/anúncio trouxe o leadCriados automaticamente por nome (get-or-create). ad_id externo (Meta/Google) deduplica o anúncio.

Os catálogos de Origem, Canal e Mídia são gerenciados em Configurações → Comercial → Origens & Canais.


Distribuição

Por padrão todo lead novo entra nas roletas ativas, que sorteiam o responsável. Dois campos, aceitos pelos dois caminhos, mudam esse comportamento:

CampoTipoPadrãoEfeito
distribuirbooleantruefalse mantém o lead fora de toda roleta — ele é criado sem responsável e fica disponível para atribuição manual
sdr_iduuid—Atribui o lead direto a um usuário da organização, preenchendo SDR e responsável

Enviar sdr_id já dispensa a roleta: a atribuição explícita substitui o sorteio, mesmo com distribuir: true. Sem isso a roleta consumiria a vaga de um participante sem conseguir atribuir o lead.

O sdr_id é o id do usuário (o mesmo do painel), e ele precisa ser membro da organização — caso contrário a requisição é recusada com 400 e nada é gravado. Leads com distribuir: false e sem sdr_id ficam sem responsável até alguém assumi-los no painel.


Tags

Os dois caminhos aceitam tags com o código de cada tag. O código aparece ao lado do nome em Configurações → Comercial → Tags, com botão de copiar.

{ "nome": "Maria Silva", "telefone": "+5561999990000", "tags": ["investidor", "feirao-set"] }
RegraComportamento
IdentificadorO código, nunca o nome. Renomear a tag no painel não muda o código, então a integração continua marcando os leads
Tag inexistenteNunca criada pela API. O código volta em tags.ignoradas com motivo: "nao_encontrada" e o lead é cadastrado normalmente
Tag desativadaNão é aplicada; volta em tags.ignoradas com motivo: "inativa"
Lead que já existeCom permitir_alteracao: true, as tags enviadas somam às que o lead já tem — nenhuma é removida. Duplicado recusado (409) não recebe tag
LimiteAté 20 tags por requisição. Caixa e espaços são ignorados (" Investidor " = investidor)

A resposta traz o desfecho sempre que a requisição mandou tags:

"tags": {
  "aplicadas": ["investidor"],
  "ignoradas": [{ "codigo": "feirao-set", "motivo": "nao_encontrada" }]
}

No webhook, tags aceita lista JSON ou texto separado por vírgula ("investidor, feirao-set"), e pode ter um padrão por fonte em static_fields.tags.


Lead duplicado e permitir_alteracao

Telefone, e-mail e CPF são exclusivos entre oportunidades ativas da organização. Por padrão, reenviar um lead já cadastrado é recusado com 409 — nenhum dado do lead existente é alterado (a re-entrada fica registrada como conversão, contando no dashboard).

Envie permitir_alteracao: true (aceito pelos dois caminhos) para que a requisição atualize o lead existente em vez de ser recusada:

Comportamentopermitir_alteracao ausente/falsepermitir_alteracao: true
Resposta409 com duplicate_field e o número da oportunidade200 com updated: true e mensagem de sucesso
Dados do leadintactosatualizados incrementalmente
Conversãoregistradaregistrada

Atualização incremental significa: só os campos presentes na requisição são gravados (o valor enviado substitui o atual); campo ausente preserva o que já estava lá. O cônjuge enviado é criado/vinculado normalmente.

O que nunca muda nesse caminho: fase, status, responsável/SDR (o lead não é redistribuído nem troca de dono) e a atribuição de primeiro toque — origem, canal, mídia, campanha e ponto de captação só são preenchidos se estiverem vazios. A atribuição da nova entrada fica no touchpoint da conversão.

A exclusividade continua valendo: se o telefone, e-mail ou CPF enviado pertencer a outra oportunidade ativa, a atualização é abortada com 400 e a mensagem indica o número da oportunidade em conflito — nada é gravado.

{
  "success": true,
  "data": {
    "oportunidade_id": "550e8400-e29b-41d4-a716-446655440000",
    "numero": 169,
    "created": false,
    "updated": true,
    "duplicate_field": "telefone",
    "message": "Já existia a oportunidade #169 cadastrada com este telefone — dados atualizados com sucesso."
  }
}

No webhook, permitir_alteracao também aceita sim/não, 1/0, e pode virar padrão da fonte pelos campos fixos do cadastro do webhook.


Lead scoring e temperatura

Formulários de qualificação (landing page, quiz, calculadora) normalmente já calculam uma nota para o lead. Envie essa nota em score — aceito pelos dois caminhos — e o OctaBuild registra a pontuação e classifica o lead automaticamente.

A escala esperada é 0 a 100, inteiro. A faixa (temperatura) é derivada da nota:

NotaTemperatura
≥ 50🔥 Quente
20 a 49🌤 Morno
< 20❄️ Frio

A temperatura aparece como etiqueta na lista de oportunidades e no kanban, e serve de critério de ordenação para o time comercial priorizar o atendimento.

Sem score, o lead entra com a nota padrão 10 (frio) — o mesmo comportamento de antes desta funcionalidade, então integrações existentes não mudam.

A nota é registrada por entrada (touchpoint), e a pontuação da oportunidade é a soma das notas de todas as entradas. Um lead que preenche o formulário duas vezes com nota 40 termina com 80 — e sobe de morno para quente. Se a origem reenvia o mesmo lead com frequência, prefira distribuir: false ou trate o reenvio como atualização para não inflar a pontuação.

O corpo inteiro do formulário continua arquivado no lead, então as respostas que geraram a nota ficam disponíveis para auditoria mesmo que só a nota seja exibida na tela.

{
  "nome": "Maria Silva",
  "telefone": "+5561999990000",
  "score": 72
}

No webhook, score também aceita os nomes alternativos lead_score, pontuacao e nota, valor em texto ("72"), e decimal — que é arredondado. Valor negativo ou não numérico é ignorado e o lead cai no padrão 10.

Respostas de qualificação (probabilidade de conversão)

A ficha do lead tem um painel Qualificação com seis perguntas que somam até 10 pontos; a soma × 10 é a probabilidade de conversão. Duas dessas respostas podem chegar direto do formulário, e o painel já abre pontuado:

CampoNome alternativo (webhook)Valores aceitosPontos
tipo_rendasituacao_trabalhoformal · informal · mista — ou o rótulo do formulário ("Renda Formal", "Renda Informal", "Renda Mista")Formal 1 · Informal 0 · Mista 2
faixa_rendarenda_faixaate_2500 · 2501_3500 · 3501_4500 · acima_4500 — ou o rótulo ("Abaixo de R$2.500/mês", "R$2.501 a R$3.500/mês", "R$3.501 a R$4.500/mês", "Acima de R$4.500/mês")0 · 1 · 2 · 3

O rótulo é lido pelo sentido, não por igualdade exata: variações como "Até R$ 2.500", "Entre 3500 e 4500" ou "CLT" também são reconhecidas. Valor que não se reconhece fica em branco (o lead é criado normalmente e o corpo segue arquivado). Com permitir_alteracao: true, a resposta nova substitui a anterior; numa reentrada sem essa flag, só preenche o que estava vazio.

Esta pontuação é independente de score: score define a temperatura (quente/morno/frio), e as respostas definem a probabilidade de conversão do painel.

{
  "nome": "Maria Silva",
  "whatsapp": "+5561999990000",
  "situacao_trabalho": "Renda Formal",
  "renda_faixa": "Abaixo de R$2.500/mês"
}

POST /v1/oportunidades

Cria (ou detecta duplicidade de) uma oportunidade. Requer API Key.

Body

CampoTipoObrigatórioDescrição
nomestringSimNome do lead
telefonestringNãoTelefone (normalizado para E.164 BR)
emailstringNãoE-mail válido
empreendimento_iduuidNãoEmpreendimento de interesse
unidade_iduuidNãoUnidade de interesse
observacoesstringNãoTexto livre
documentostringNãoCPF (somente dígitos ou formatado)
data_nascimentostringNãoData YYYY-MM-DD
estado_civilstringNãoEstado civil (ex.: casado)
profissaostringNãoProfissão
renda_mensalnumberNãoRenda mensal
tem_fgtsbooleanNãoPossui FGTS
tem_dependentebooleanNãoPossui dependentes
tipo_rendastringNãoTipo de renda: formal, informal, mista ou o rótulo do formulário — ver Respostas de qualificação
faixa_rendastringNãoFaixa de renda: ate_2500, 2501_3500, 3501_4500, acima_4500 ou o rótulo do formulário
rgstringNãoRG
cepstringNãoCEP do endereço
logradourostringNãoLogradouro
numerostringNãoNúmero
complementostringNãoComplemento
bairrostringNãoBairro
cidadestringNãoCidade
ufstringNãoUF (2 letras)
conjugeobjetoNãoDados do cônjuge (leads casados) — ver abaixo
utm_sourcestringNãoUTM de origem
utm_mediumstringNãoUTM de mídia
utm_campaignstringNãoUTM de campanha
utm_contentstringNãoUTM de conteúdo
utm_termstringNãoUTM de termo
ad_idstringNãoId externo do anúncio (Meta/Google) — deduplica o anúncio na árvore
form_idstringNãoId externo do formulário
referrer_urlstringNãoURL de referência
landing_urlstringNãoURL da landing page
originstringNãoSlug de uma Origem existente (ex.: marketing). Inválido → marketing
channelstringNãoSlug ou nome de um Canal existente (ex.: instagram). Fallback: utm_source
media_typestringNãoSlug ou nome de uma Mídia existente (ex.: midia_paga)
campaign_namestringNãoNome da campanha (get-or-create). Fallback: utm_campaign
ad_set_namestringNãoNome do conjunto de anúncios (get-or-create, dentro da campanha)
ad_namestringNãoNome do anúncio (get-or-create)
capture_pointstringNãoNome de um Ponto de Captação existente (nunca criado pela API)
capture_locationstringNãoLocal de captação em texto livre (endereço)
capture_latnumberNãoLatitude (-90 a 90)
capture_lngnumberNãoLongitude (-180 a 180)
scorenumberNãoNota do formulário de qualificação, inteiro ≥ 0 (escala 0–100). Define a temperatura do lead. Padrão 10 — ver Lead scoring abaixo
distribuirbooleanNãoEnvia o lead para as roletas ativas. Padrão true; false = sem roleta
sdr_iduuidNãoUsuário atribuído como SDR/responsável — dispensa a roleta
permitir_alteracaobooleanNãoPadrão false. true atualiza o lead já cadastrado em vez de recusar com 409
tagsstring[]NãoCódigos das tags a aplicar (máx. 20). Desconhecida/inativa é ignorada sem recusar o lead — ver Tags

Objeto conjuge

Quando o lead é casado, envie os dados do cônjuge — o OctaBuild cria (ou reusa, por CPF e depois telefone) o cadastro da pessoa e a vincula à oportunidade como conjuge:

CampoTipoObrigatórioDescrição
conjuge.nomestringSim (dentro do objeto)Nome do cônjuge
conjuge.telefonestringNãoTelefone
conjuge.emailstringNãoE-mail
conjuge.documentostringNãoCPF
conjuge.rgstringNãoRG
conjuge.data_nascimentostringNãoData YYYY-MM-DD
conjuge.profissaostringNãoProfissão

Request

curl -X POST "https://api.octabuild.ai/v1/oportunidades" \
  -H "Authorization: Bearer ea_live_sua_chave_aqui" \
  -H "Content-Type: application/json" \
  -d '{
    "nome": "Maria Silva",
    "telefone": "+5561999990000",
    "email": "maria@email.com",
    "channel": "instagram",
    "media_type": "midia_paga",
    "campaign_name": "Lançamento Jardins",
    "ad_set_name": "Publico frio DF",
    "ad_name": "Video 30s",
    "utm_source": "instagram",
    "utm_medium": "paid_social",
    "utm_campaign": "lancamento-jardins",
    "documento": "123.456.789-00",
    "estado_civil": "casado",
    "renda_mensal": 8500,
    "cep": "71900-000",
    "logradouro": "Rua das Palmeiras",
    "numero": "120",
    "bairro": "Águas Claras",
    "cidade": "Brasília",
    "uf": "DF",
    "conjuge": {
      "nome": "João Silva",
      "telefone": "+5561988880000",
      "documento": "987.654.321-00"
    },
    "tags": ["investidor", "feirao-set"]
  }'

Response — 201 Created (ou 200 se já existia em modo merge)

{
  "success": true,
  "data": {
    "oportunidade_id": "550e8400-e29b-41d4-a716-446655440000",
    "numero": 42,
    "created": true,
    "tags": {
      "aplicadas": ["investidor", "feirao-set"],
      "ignoradas": []
    }
  }
}

Response — 409 Conflict (duplicado)

Telefone, e-mail ou CPF já usados em oportunidade ativa bloqueiam o cadastro (nada é gravado). Para atualizar o lead existente em vez de receber o erro, envie permitir_alteracao: true (ver Lead duplicado acima):

{
  "success": false,
  "error": {
    "code": "DUPLICATE_TELEFONE",
    "message": "Já existe uma oportunidade ativa com este telefone (#42)."
  }
}

Códigos possíveis: DUPLICATE_TELEFONE, DUPLICATE_EMAIL, DUPLICATE_CPF, VALIDATION_ERROR (400), RATE_LIMITED (429).


POST /api/webhooks/inbound/{token}

Webhook de entrada para fontes low-code (Typebot, Zapier, n8n, landing pages). Crie a fonte em Configurações → Integrações → Webhooks — a URL com o token é exibida na criação.

  • Origem e Canal dos leads desta fonte são definidos no cadastro do webhook (não no corpo).
  • Se a fonte tiver segredo, envie o header x-webhook-secret.
  • Rate limit: 120 requisições/minuto por fonte.

Body (contrato fixo)

Além dos campos de atribuição (utm_*, ad_id, form_id, referrer_url, landing_url, campaign_name, ad_set_name, ad_name — mesmos significados da API v1), o webhook aceita campos de qualificação:

CampoTipoObrigatórioDescrição
nomestringUm entre nome/telefone/emailNome do lead
telefonestring↑Telefone
emailstring↑E-mail
documentostringNãoCPF (somente dígitos ou formatado)
data_nascimentostringNãoData YYYY-MM-DD
estado_civilstringNãoEstado civil
profissaostringNãoProfissão
renda_mensalstring/numberNãoRenda mensal
tem_fgtsstring/booleanNãoAceita sim/não, true/false, 1/0
tem_dependentestring/booleanNãoIdem
tipo_rendastringNãoTambém aceito como situacao_trabalho. Valor canônico ou rótulo ("Renda Formal")
faixa_rendastringNãoTambém aceito como renda_faixa. Valor canônico ou rótulo ("Abaixo de R$2.500/mês")
rgstringNãoRG
cepstringNãoCEP do endereço
logradourostringNãoLogradouro
numerostringNãoNúmero
complementostringNãoComplemento
bairrostringNãoBairro
cidadestringNãoCidade
ufstringNãoUF (2 letras)
empreendimento_iduuidNãoEmpreendimento de interesse
unidade_iduuidNãoUnidade de interesse
observacoesstringNãoTexto livre
conjuge_nomestringNãoNome do cônjuge — presente, ativa o vínculo do cônjuge
conjuge_telefonestringNãoTelefone do cônjuge
conjuge_emailstringNãoE-mail do cônjuge
conjuge_documentostringNãoCPF do cônjuge
conjuge_rgstringNãoRG do cônjuge
conjuge_data_nascimentostringNãoData YYYY-MM-DD
conjuge_profissaostringNãoProfissão do cônjuge
scorestring/numberNãoNota do formulário de qualificação (escala 0–100). Aliases aceitos: lead_score, pontuacao, nota. Padrão 10 — ver Lead scoring abaixo
distribuirstring/booleanNãoEnvia o lead para as roletas ativas. Padrão true; aceita sim/não, true/false, 1/0
sdr_iduuidNãoUsuário atribuído como SDR/responsável — dispensa a roleta
permitir_alteracaostring/booleanNãoPadrão false. true atualiza o lead já cadastrado em vez de recusar com 409
tagsstring[]/stringNãoCódigos das tags — lista JSON ou texto separado por vírgula. Ver Tags

No webhook os dados do cônjuge são chaves planas com prefixo conjuge_ (o contrato é raso). Na API v1, use o objeto aninhado conjuge.

O corpo inteiro da requisição é arquivado no lead para auditoria (payload do touchpoint), então campos extras não são perdidos — apenas não são estruturados.

Request

curl -X POST "https://app.octabuild.ai/api/webhooks/inbound/wh_seu_token_aqui" \
  -H "Content-Type: application/json" \
  -H "x-webhook-secret: whsec_seu_segredo" \
  -d '{
    "nome": "Maria Silva",
    "telefone": "+5561999990000",
    "email": "maria@email.com",
    "utm_source": "instagram",
    "utm_campaign": "lancamento-jardins",
    "campaign_name": "Lançamento Jardins"
  }'

Response

201 (criado) / 200 (fundido ou atualizado) com { success, data: { oportunidade_id, numero, created, updated } }, ou:

StatusMotivo
400JSON inválido, payload sem nome/telefone/email, sdr_id que não é usuário da organização, ou identificador em conflito com outra oportunidade na atualização
401Segredo inválido
404Token inexistente ou fonte inativa
409Lead duplicado (error, duplicate_field, oportunidade_numero) — evitável com permitir_alteracao: true
429Rate limit excedido

On this page