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


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
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)
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

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"
    }
  }'

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
  }
}

Response — 409 Conflict (duplicado)

Telefone, e-mail ou CPF já usados em oportunidade ativa bloqueiam o cadastro (nada é gravado):

{
  "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
telefonestringTelefone
emailstringE-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
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
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

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) com { success, data: { oportunidade_id, numero, created } }, ou:

StatusMotivo
400JSON inválido, payload sem nome/telefone/email, ou sdr_id que não é usuário da organização
401Segredo inválido
404Token inexistente ou fonte inativa
409Lead duplicado (error, duplicate_field, oportunidade_numero)
429Rate limit excedido

On this page