Documentação de referência · v1.0

API do Portal ImoFlow

Como consumir dados de imóveis, empreendimentos e corretores da sua conta ImoFlow, e enviar leads capturados no seu site direto para o CRM.

BASE_URL https://so-mansoes.imoflow.app.br/api/portal

§1 Como a identificação da conta funciona

A API identifica automaticamente qual imobiliária está fazendo a chamada pelo domínio usado na requisição — o subdomínio gratuito já atribuído à sua conta (ex.: so-mansoes.imoflow.app.br). Use exatamente essa base em todas as chamadas.

!
Limitação atual: não existe hoje um mecanismo de chave de API (API key) para estes endpoints — a identificação é feita inteiramente pelo domínio da chamada. Trate a base URL como configuração sensível, e prefira fazer chamadas de escrita (leads) a partir do seu próprio backend, não direto do navegador do visitante.

Formato de resposta — atenção

Nem todo endpoint responde em JSON. Vários endpoints de escrita alternam entre texto puro e JSON dependendo do resultado — cada endpoint abaixo indica o formato exato de cada resposta possível. Corpos de erro também variam: {"message": "..."}, string solta, ou {"erro": "..."} — não generalize entre endpoints.

Autenticação

Leitura (GET) e a maioria dos POSTs de lead: nenhuma — identificação só pelo domínio. O correspondente bancário usa um fluxo próprio de token + código de acesso + sessão temporária.

§2 Erros comuns a todos os endpoints

Antes de qualquer lógica específica, toda requisição passa por uma verificação de conta que pode retornar:

StatusCorpoQuando ocorre
400{"message":"Host não encontrado"}Requisição sem header Host
402{"message":"...suspenso...","code":"SITE_SUSPENDED","logoUrl":string|null}Assinatura da conta irregular. Trate este código — pode ocorrer mesmo com a integração correta, se a fatura atrasar.
404{"message":"Imobiliária/Cliente não encontrado para o domínio"}Domínio não corresponde a nenhuma conta — geralmente erro de configuração da base URL
500{"message":"Erro ao buscar cliente"}Erro interno ao identificar a conta

§3 Configurações do Portal

Base: /configuracoesPortal. Dados visuais e institucionais da imobiliária.

GET/configuracoesPortalConfiguração geral
CampoTipoDescrição
nomePortalstringNome exibido do portal
sloganstringSlogan da imobiliária
logo{filename,url}Logo principal
favicon{filename,url}Favicon
corPrimaria / corSecundariastring (hex)Cores principais
paletaobjectPaleta completa: {nome, base, customizada, tons:{t50..t900}}
mapeamentoobjectMapeamento de cores por área da UI
celular01 / celular02stringTelefones de contato
googleTagManagerID / facebookPixelIDstringIDs de tracking
enderecoPrincipalobject{cep,rua,numero,complemento,bairro,cidade,estado}
palavrasChave / descricaostringMeta tags SEO
ogTitulo / ogDescricao / ogImagemUrlstringOpen Graph
whatsappPortalobjectConfig do botão flutuante de WhatsApp
linkFacebook / linkInstagramstringRedes sociais
formularioContatoobject{modelo:'A'|'B', titulo, textoBotaoCTA, textoBotao, corBotao, emailObrigatorio, formularioAberto}
modeloBuscaHome'A'|'B'|'C'|'D'Layout da busca da home
textoBotaoBuscastringTexto do botão de busca
iconeBotaoBuscaobject{mostrar, posicao}

Erros

404 {message:'Configuração não encontrada para este tenant'} · 500 {message:'Erro no servidor'}

GET/configuracoesPortal/sobrePágina Sobre

Resposta 200: nomePortal, sobre (texto livre), enderecoPrincipal, diasAtendimento[], horarioAtendimento ({inicio,fim}).

Erros

404 {message:'Configurações não encontradas para este tenant'} · 500 {message:'Erro no servidor'}

GET/configuracoesPortal/home-pageBlocos da home

Resposta 200: secoesHome[] — cada seção com chave, visivel, ordem, titulo, subtitulo, conteudo, imagem, cards[], botoes[]; e unidades[] — filiais com endereço e contato próprios.

Erros

404 {message:'Configurações da home page não encontradas'} · 500 {message:'Erro no servidor'}

GET/configuracoesPortal/politicaPolítica de privacidade

Resposta 200: politicaPrivacidade (texto/HTML), nomePortal, logo.

Erros

404 {message:'Política de privacidade não encontrada'} · 500 {message:'Erro no servidor'}

GET/configuracoesPortal/headerCabeçalho

Resposta 200: logo, menuHeaderCompleto, celular01, celular02, menuHeader ({cor,opacidade,corTexto,tamanhoDaFonte}), linkFacebook, linkInstagram, paleta, mapeamento.

Erros

404 {message:'Configurações do header não encontradas'} · 500 {message:'Erro no servidor'}

GET/configuracoesPortal/categorias-imoveisCategorias exibidas

Resposta 200: {"tipos": string[], "finalidades": string[]}

!
Foi observado que este endpoint tende a retornar sempre arrays vazios, independente dos imóveis cadastrados. Valide com uma chamada real antes de depender dele.

Erros

500 {message:'Erro no servidor'} (sem 404 — sempre 200 com arrays, mesmo vazios)

§4 Imobiliária

Base: /imobiliariaPortal.

GET/imobiliariaPortal

Resposta 200: {"baseUrl": string} — apenas este campo.

Erros

404 {message:'Imobiliária não encontrada'} · 500 {message:'Erro no servidor'}

GET/imobiliariaPortal/codigo-portal

Resposta 200: {"codigoPortal": string}

Erros

404 {message:'Imobiliária não encontrada'} · 500 {message:'Erro no servidor'}

§5 Imóveis

Base: /imoveis, /cidades, /bairros. O grupo mais importante do catálogo.

i
Campos de valor (valorVenda, valorAluguel, valorTemporada, valorCondominio, valorIptu) e de localização (cep, rua, numero, complemento, bairro, cidade, estado, andar) só aparecem se a respectiva flag de visibilidade estiver true. Se false ou ausente, o campo é omitido do JSON — trate sempre como opcional (imovel.valores?.valorVenda). localizacao.id_condominio é a única exceção, sempre presente.
GET/imoveisBusca principal

O endpoint central do catálogo — todos os filtros da busca do site devem passar por aqui.

Query params

ParamTipoDescrição
page / limitnumberPaginação. Se ambos inválidos, retorna tudo sem paginar
sortFieldstringDefault _id. Se começar com valores., ordena pelo valor mais relevante (venda > aluguel > temporada)
sortOrder'asc'|'desc'Default desc
finalidadestringMatch exato (ignora acento/caixa): Venda, Aluguel, Temporada
minVenda / maxVendanumberFaixa de preço de venda
minAluguel / maxAluguelnumberFaixa de aluguel — também aplica a Temporada
minArea / maxAreanumberFaixa de área total (m²)
tipoImovelsstring (CSV)Lista de tipos, ex. Apartamento,Casa
tipoImovelstringFiltro único (sobrescreve tipoImovels se ambos enviados)
quartos / suites / salas / banheiros / vagasstringNúmero exato ou "N+". vagas também aceita "Indiferente"
condicoesPagamentostringUm único valor
statusstring (CSV)Ex. Disponível,Reservado
categoriastring ou arrayCategoria(s)
cidades / bairros / estadosstring (CSV)Busca por substring; item pode ser "nome" ou "nome||estado"
cidade / bairrostringVersões legadas, match exato
condominio_nomestring (CSV)Filtra por nome de condomínio
locationOr"tipo:valor,..."Filtro combinado (cidade:, bairro:, estado:, condominio:). Substitui os filtros de localização acima quando presente
querystring (CSV)Busca textual livre — ignorado se filtros de localização estiverem presentes
allPropertiesqualquerNão usar — remove o filtro de "publicado no portal"
maisAcessadosqualquerModo especial: 6 mais acessados. Resposta é array puro
destaquequalquerModo especial: apenas destaques. Resposta é array puro

Resposta 200 (modo normal)

{
  "totalImoveis": 42,
  "imoveis": [ /* ver estrutura do imóvel abaixo */ ]
}

Estrutura de cada item em imoveis[]

Mesma estrutura em todos os endpoints de listagem desta seção.

CampoTipoDescrição
_idstringID do imóvel
sobreobject{finalidade:string[], tipoImovel, categoria, refImovel}
caracteristicasobjectquartos, suites, salas, banheiros, vagas, áreas, título/descrição, e opcionalmente etiquetas:[{name,color}]
statusstringDisponível, Vendido, Locado, Reservado, Indisponível
statusTagobject | null{label, bg, fg} — etiqueta visual pronta
valoresobjectVer nota de campos condicionais acima
localizacaoobjectVer nota de campos condicionais acima
midias.imagens / plantasarray (máx. 10){filename,url,ordem}, já filtradas por visibilidade
midias.tour / videosarray (máx. 10){url}
cardCorretor.exibirCardCorretorboolean
seo_dataobject{seo_title?, seo_description?, seo_keywords?, seo_canonical?}
condominioAreaMinima / Maximanumber | ausenteSó presentes se o imóvel pertencer a um condomínio

Exemplo

curl "https://so-mansoes.imoflow.app.br/api/portal/imoveis?finalidade=Venda&minVenda=300000&maxVenda=800000&quartos=3%2B&page=1&limit=12"

Erros

500 texto puro "Erro no servidor" (sem JSON)

GET/imoveis/opcoesOpções de filtro
{
  "opcoesItensImovel": [{"imoflow":"...","olx":"...","chaves":"...","categoria":"..."}],
  "opcoesProximidades": ["..."],
  "opcoesCondicoesPagamento": ["..."]
}

Erros

500 {message:'Erro no servidor'}

GET/imoveis/:refImovelDetalhe do imóvel

refImovel aceita a referência do imóvel, com fallback para slug de SEO se não encontrar por referência.

Mesma estrutura da listagem principal (GET /imoveis), com diferenças: mídias sem limite de 10; inclui restrito.id_responsavel e updatedAt.

i
Cada chamada incrementa o contador interno de acessos do imóvel (não afeta a resposta).

Erros

404 {message:'Imóvel não encontrado'} · 500 texto puro "Erro no servidor"

GET/imoveis/finalidade/:finalidadeListagem por finalidade

Mesmos query params de GET /imoveis (exceto finalidade/modos especiais). Rota: Venda, Aluguel ou Temporada. Finalidade inexistente retorna lista vazia, sem erro.

Erros

500 texto puro "Erro no servidor"

GET/imoveis/tipoImovel/:tipoImovelListagem por tipo

Aceita múltiplos tipos combinados na URL, separados por +, , ou espaço (URL-encoded). Ex.: /imoveis/tipoImovel/Apartamento%2CCasa.

Erros

500 texto puro "Erro no servidor"

GET/imoveis/finalidade/:finalidade/tipoImovel/:tipoImovelListagem combinada

Mesmas regras dos dois endpoints anteriores, combinadas.

Erros

500 texto puro "Erro no servidor"

GET/imoveis/por-finalidade/:finalidadeAgrupamento simplificado

Versão sem os filtros avançados de GET /imoveis. Query params: page (default 1), limit (default 12).

Erros

500 texto puro "Erro no servidor"

GET/imoveis/sugestoesAutocomplete de busca

Query param q (termo de busca — retorna [] se vazio), mais os filtros de faixa/característica de GET /imoveis para refinar.

[
  { "tipo": "refImovel", "valor": "AB1234" },
  { "tipo": "cidade", "valor": "São Paulo - SP", "count": 87 },
  { "tipo": "bairro", "valor": "Vila Mariana (São Paulo)", "count": 12 },
  { "tipo": "rua", "valor": "Rua Exemplo, Vila Mariana (São Paulo)", "count": 3 },
  { "tipo": "condominio", "categoria": "Alto Padrão", "valor": "Edifício Exemplo" }
]

Erros

500 {message:'Erro ao buscar sugestões'}

GET/imoveis/semelhantes/:refImovelImóveis semelhantes

Mesmo bairro/categoria/tipo/finalidade, faixa de preço ±25%. Query: page (default 1), limit (default e máximo 20).

Erros

404 {message:'Imóvel base não encontrado'} · 500 texto puro "Erro ao buscar imóveis semelhantes"

GET/imoveis/corretor-do-imovel/:refImovelCorretor responsável
{
  "nome": "string",
  "telefone": "string | null",
  "email": "string",
  "foto": { "url": "string" },
  "creci": "string | null",
  "titulo": "Corretor Responsável",
  "textoWhatsApp": "string | null"
}

telefone, creci e textoWhatsApp vêm null se o corretor ocultou esses dados no card do portal.

!
Se o responsável cadastrado não existir mais no sistema, a resposta é 200 {"message": "Sem corretor responsável"} — não é 404. Verifique a presença de nome para confirmar sucesso.

Erros

404 {message:'Imóvel sem corretor'} (imóvel não existe OU sem responsável — mesma mensagem) · 500 texto puro "Erro no servidor"

GET/imoveis/imagem/:refImovelLista de imagens

Lista crua (inclui imagens não visíveis, sem limite de quantidade): [{filename, url, ordem, visivel?}].

Erros

404 string JSON "Imagens não encontradas" · 500 texto puro "Erro no servidor"

GET/imoveis/imagem/:refImovel/:filenameArquivo de imagem

Resposta 200: binário (Content-Type: image/jpeg sempre, mesmo se o arquivo original for outro formato).

Erros

404 string JSON "Imagens não encontradas", "Imagem não encontrada" ou "Imagem não encontrada no servidor" · 500 texto puro "Erro no servidor"

GET/cidadesLista simples de cidades

Resposta 200: {"cidades": ["São Paulo", "Campinas"]} (não filtra por publicado, ordenado alfabeticamente).

Erros

500 texto puro "Erro no servidor"

GET/cidades/detalhesCidades com contagem e imagens

Resposta 200: {"cidades": [{"nome":"São Paulo","quantidade":34,"imagens":["url1","url2"]}]} — até 12 imagens por cidade, apenas imóveis publicados.

Erros

500 {message:'Erro ao buscar cidades'}

GET/bairrosLista simples de bairros

Query opcional cidade (filtro exato). Resposta 200: {"bairros": ["Centro", "Vila Mariana"]}.

Erros

500 texto puro "Erro no servidor"

GET/bairros/detalhesBairros com contagem e imagens

Query opcional cidade. Apenas imóveis publicados, até 12 imagens por bairro.

Erros

500 {message:'Erro ao buscar bairros'}

§6 Empreendimentos e Condomínios

Base: /empreendimentos, /condominio.

GET/empreendimentos/categorias

Resposta 200: array de strings, ex. ["Alto Padrão", "Popular"].

Erros

500 texto puro "Erro no servidor"

GET/empreendimentos
ParamDefaultDescrição
page1Página
limit6Itens por página
categoriaBusca parcial (ignora caixa)
allSe presente, inclui condomínios não marcados para o header do portal padrão

Resposta 200: {condominios:[...], total, page, limit, totalPages}. Cada condomínio: _id, nome, categoria, imagens[], tipo (Vertical/Horizontal/Misto), andares, blocos, apartamentoPorAndar, idadeImovel, areaMinima/areaMaxima, fechado, rua/bairro/cidade/estado, dormitorios/suites ({min,max}), vagas/varanda/deposito, unidades, imoveisCount.

Erros

500 texto puro "Erro no servidor"

GET/condominio/:identifierDetalhe do empreendimento

identifier aceita ID do condomínio ou o nome (comparado ignorando acentos/caixa/espaços). Por ID, retorna mesmo se oculto do portal; por nome, só visíveis.

!
Comportamento não usual: se não encontrado, a resposta é 200 com corpo null — não é 404. Cheque explicitamente se o corpo é null.

Resposta 200 (encontrado): documento completo — nome, areaTerreno, areaMinima/areaMaxima, fechado, tipo, categoria, enderecoCompleto, endereço detalhado, andares/blocos/apartamentoPorAndar/idadeImovel, tituloCondominio/descricaoCondominio, caracteristicas[], imagens[]/plantas[] (filtradas por visibilidade), tour[]/videos[], padrao, tipoImovel, incorporadora/construtora, informacoesComplementares, visivelNoHeader, dormitorios/suites/vagas/varanda/deposito, unidades, valorMinimo/valorMaximo, enderecoStand.

Erros

500 texto puro "Erro no servidor"

GET/condominio/imagens/:identifier

Mesmo identifier dual acima. Resposta 200: array de imagens visíveis {filename, url, ordem}.

Erros

404 {message:"Imagens do condomínio não encontradas."} · 500 texto puro "Erro no servidor"

GET/condominio/possui-imoveis/:identifier

Resposta 200 (sempre): {"possuiImoveis": boolean}false também se identifier não for encontrado.

Erros

500 texto puro "Erro no servidor"

GET/condominio/imoveis/:identifier

Imóveis publicados vinculados ao condomínio: sobre, valores, seo_data, características selecionadas, midias.imagens/plantas (filtradas), localizacao, e condominioAreaMinima/Maxima (se o condomínio for encontrado).

!
Recomenda-se validar previamente com GET /condominio/possui-imoveis/:identifier antes de consultar aqui — o comportamento quando identifier não resolve não é garantido.

Erros

500 texto puro "Erro no servidor"

§7 Corretores e Opções

GET/corretores
[{ "nome": "string", "telefone": "string", "whatsapp": true, "email": "string", "creci": "string", "foto": {"url":"string"} }]

Erros

500 string JSON "Erro ao buscar corretores" (sem chave)

GET/corretores/:id

id — ObjectId do corretor (não aceita nome/slug). Resposta 200: {"nome","telefone","whatsapp","creci"}sem email nem foto.

Erros

400 string JSON "ID de usuário inválido" · 404 string JSON "Corretor não encontrado" · 500 string JSON "Erro ao buscar corretor"

GET/imovel-opcoesOpções de tipo/categoria com contagem
{
  "opcoes": [{"tipoImovel":"Apartamento","categorias":["Alto Padrão","Popular"]}],
  "categorias": ["Alto Padrão", "Popular"],
  "counts": [{"tipoImovel":"Apartamento","categoria":"Alto Padrão","count":12}]
}

Erros

500 — status 500 mas corpo {"opcoes":[],"categorias":[],"error":"Erro no servidor"}. Verifique sempre o status HTTP.

§8 Captação de Leads

Base: /salvar-lead*, /send-*, /simular-financiamento. Todos POST.

!
Nos três endpoints principais abaixo (salvar-lead/:refImovel, salvar-lead-geral, salvar-lead-condominio), a resposta de sucesso muda de formato: novo atendimento criado → 200 texto puro Lead salvo com sucesso.; lead vinculado a atendimento já existente → 200 JSON {"message": "Lead vinculado a atendimento já existente!"}. Trate as duas formas como sucesso.
POST/salvar-lead/:refImovelLead a partir de um imóvel
CampoTipoDescrição
nomestringobrigatório*Nome do lead
telefonestringobrigatórioValidado e convertido para formato BR
emailstringopcionalTambém usado para identificar lead existente
mensagemstringopcionalMensagem livre
finalidadestringopcionalSe ausente/incompatível, usa a finalidade do imóvel
!
*nome é obrigatório na prática, mas omiti-lo hoje gera 500 genérico em vez de 400. Sempre envie preenchido.

Erros

400 string JSON "Telefone inválido: {telefone}" ou "Telefone é obrigatório" · 404 texto puro Imóvel não encontrado. · 500 texto puro Etapa inicial não encontrada. ou Erro inesperado ao salvar lead.

Efeito no CRM

Cria/atualiza a Pessoa (dedup por telefone/e-mail), cria ou reaproveita Atendimento vinculando o imóvel, gera perfil de interesse com recomendações, distribui para um corretor.

Exemplo

curl -X POST "https://so-mansoes.imoflow.app.br/api/portal/salvar-lead/AB1234" \
  -H "Content-Type: application/json" \
  -d '{"nome":"João Silva","telefone":"11987654321","email":"joao@exemplo.com","mensagem":"Tenho interesse neste imóvel","finalidade":"Venda"}'
POST/salvar-lead-geralLead genérico

Body: nome (obrigatório na prática), telefone (obrigatório, validado), mensagem (opcional), finalidade (opcional, texto livre). Não aceita email — dedup só por telefone.

Erros

Mesmos códigos de POST /salvar-lead/:refImovel, sem o caso de imóvel não encontrado.

Efeito no CRM

Cria/atualiza Pessoa, cria/reaproveita Atendimento (sem imóvel vinculado), gera nota de atividade, distribui para corretor. Não gera perfil de interesse detalhado.

POST/salvar-lead-condominio/:condominioIdLead de empreendimento

condominioId — ObjectId do condomínio. Body: nome (obrigatório na prática), telefone (obrigatório, validado), email (opcional), url (opcional, só compõe o texto da nota interna), mensagem (opcional).

Erros

Mesmos de POST /salvar-lead/:refImovel, mais 404 texto puro Condomínio não encontrado.

Efeito no CRM

Cria/atualiza Pessoa, cria/reaproveita Atendimento com finalidade fixa Venda e vínculo ao empreendimento, gera perfil de interesse por região, distribui para corretor.

POST/salvar-lead-campanhaLead de campanha/landing

Diferente dos três anteriores: validação completa de campos e resposta sempre em JSON.

Body (todos obrigatórios): nome, telefone, origem (ex. facebook), nome_campanha, finalidade, categoria, tipo_imovel.

Sucesso (chave mensagem, não message): {"mensagem": "Lead e atendimento criados com sucesso."} ou {"mensagem": "Lead vinculado a atendimento já existente!"}.

Erros (JSON, chave erro)

400 {erro:'Campos obrigatórios: nome, telefone, origem, nome_campanha, finalidade, categoria e tipo_imovel.'} · 400 telefone inválido/obrigatório · 500 várias mensagens de erro interno

POST/salvar-lead-chatLead vindo de chat

Body: nome (obrigatório), telefone (obrigatório, validado), rendaFamiliar (opcional), valorEntrada (opcional).

Sucesso: {"mensagem": "Lead e atendimento criados com sucesso."}.

i
Sempre cria um novo Atendimento — não verifica atendimentos em andamento como os endpoints de lead anteriores.

Erros (JSON, chave erro)

400 {erro:'Nome e telefone são obrigatórios.'} · telefone inválido · 500

POST/send-emailContato por e-mail

Body: nome, email, assunto, mensagem — nenhum validado. Sucesso: texto puro E-mails enviados com sucesso.

i
Envia e-mail para a imobiliária + confirmação ao remetente. Não grava no CRM.

Erros

404 texto puro Configurações não encontradas. · 500 texto puro Erro ao enviar e-mails.

POST/send-imovel-emailContato sobre imóvel por e-mail

Body: nome, celular, email, tipoImovel, negocio, valor, descricao, url. Apenas e-mail, sem gravação no CRM.

Erros

404 texto puro Configurações não encontradas. · 500 texto puro Erro ao enviar e-mails.

POST/send-email-pessoa/:refImovelContato direcionado

refImovel só usado como texto no e-mail (não valida existência). Body: nome, email, assunto, url, finalidade (opcional).

Erros

404 texto puro Configurações não encontradas. · 500 texto puro Erro ao enviar email para pessoa

POST/send-email-imobiliaria/:refImovelContato direcionado à imobiliária

refImovel aqui é validado. Body: nome, telefone, email, mensagem, url, finalidade.

Erros

404 texto puro Configurações não encontradas. ou Imóvel não encontrado. (mesmo status) · 500 texto puro Erro ao enviar email para admin

POST/sendWebsiteEmail

Body: nome, email, mensagem.

!
Envia para um e-mail fixo da própria ImoFlow, não da imobiliária — provavelmente não relevante para sua integração. Confirme com o time ImoFlow antes de usar.

Erros

404 texto puro Configurações não encontradas. · 500 texto puro (mensagem variável)

POST/simular-financiamento

Body: dados pessoais/endereço, telefone (obrigatório, validado), whatsapp (boolean, default false), email, rendaMensal, fgts, valorImovelPretendido.

!
Envie rendaMensal sempre como string, mesmo vazia.

Sucesso: {"mensagem": "Simulação criada com sucesso."}.

Erros

400 {erro:'Telefone inválido: ...'} / {erro:'Telefone é obrigatório'} · 500 texto puro Etapa inicial não encontrada. ou {erro:'Erro ao criar simulação de financiamento.'}

POST/salvar-lead-quinto-andar
!
Comportamento único: não usa identificação por domínio e não grava no CRM da ImoFlow — grava numa planilha de integração específica. Não inclua na sua integração a menos que orientado pelo time ImoFlow.

Body (todos obrigatórios): nome, telefone (sem validação de formato), tipo (Apartamento/Casa/Kitnet), finalidade (Venda/Aluguel), cep, endereco, numero.

Sucesso: {"message": "Lead salvo com sucesso."}.

Erros

500 {"message": "..."} — inclusive campo faltante retorna 500, não 400

POST/visitsRegistro de visita/pageview

Body: url (obrigatório), device (obrigatório).

// 201
{ "message": "Visita registrada com sucesso", "visit": { "ip": "...", "device": "...", "url": "...", "localizacao": {"pais":"...","estado":"...","cidade":"...","latitude":0,"longitude":0}, "createdAt": "2026-08-18T12:00:00.000Z" } }

localizacao pode vir ausente se a geolocalização do IP falhar. Registros expiram automaticamente em 90 dias.

Erros

400 {error:'URL e device são obrigatórios.'} · 500 {error:'Erro ao registrar visita'}

§9 Correspondente Bancário

Base: /correspondente. Fluxo completo de acesso a uma proposta em análise, via link com token.

i
Fluxo ponta a ponta: (1) o correspondente recebe um link com token + código de 6 dígitos por canais separados · (2) GET :token/validate confirma que o link ainda é válido · (3) POST :token/auth com o código de 6 dígitos devolve um token de sessão (JWT, 4h) · (4) esse token, em Authorization: Bearer, dá acesso à proposta.
GET/correspondente/:token/validate

Resposta 200: {"isValid": true, "isExpired": false, "expiresAt": "2026-08-20T12:00:00.000Z"}

Erros

404 {isValid:false, message:'Link inválido ou já utilizado.'} · 410 {isValid:false, isExpired:true, message:'Link expirado.'}

POST/correspondente/:token/auth

Body: {"accessCode": "123456"}

Resposta 200: {"success": true, "sessionToken": "eyJ..."} — JWT válido por 4 horas, enviar como Authorization: Bearer {sessionToken} nas chamadas seguintes.

Erros

401 {success:false, message:'Código de acesso inválido ou link expirado.'}

GET/correspondente/proposta

Requer Authorization: Bearer {sessionToken}. Resposta 200: documento completo da proposta — imóvel, compradores, fiadores, vendedores (dados pessoais/cônjuge quando aplicável), responsável interno.

Erros

404 {message:'Proposta não encontrada.'} · 500 {message:'Erro ao buscar proposta.'}

GET/correspondente/proposta/historico

Resposta 200: array do histórico, mais recente primeiro — status, alteracao, comentario, updatedBy.nome, createdAt.

Erros

404 {message:'Histórico da proposta não encontrada.'} · 500 {message:'Erro ao buscar histórico da proposta.'}

POST/correspondente/update

Body: {"status": "string", "comentario": "string"}. Resposta 200: {"success": true, "message": "Proposta atualizada com sucesso."}. Atualiza a proposta e registra no histórico.

Erros

500 {message:'Erro ao atualizar proposta.'}

§10 Outros

GET/atendimentos/:id
!
Apesar do nome, a resposta não traz os dados do atendimento — só o perfil de interesse recalculado da pessoa vinculada.
{ "perfilInteresse": { /* preferências + */ "recomendados": [{"_id":"...","refImovel":"...","compatibilidade":87}], "recomendadosDetalhados": [ /* imóveis completos */ ] } }

Erros

404 string JSON "Atendimento não encontrado" · 500 {message:'Erro ao obter e atualizar atendimento', error:'...'}

GET/landing-page/historico

Query (opcionais): limit (default 100, máx. 500), url, origem, nome_campanha (filtros exatos), search (busca textual).

Resposta 200: array de {url, query, ip, dispositivo, localizacao?, createdAt, updatedAt}.

Erros

500 texto puro Erro ao listar acessos

POST/landing-page/historico

Body: url (obrigatório), dispositivo (obrigatório: desktop/mobile/unknown), query (objeto livre, opcional).

Resposta 201: {"message": "Acesso registrado com sucesso"}.

Erros

400 {message:'URL e dispositivo são obrigatórios.'} · 500 {message:'Erro ao registrar acesso'}

DEL/landing-page/historico/:id

Resposta 200: {"message": "Registro de acesso removido com sucesso"}.

Erros

404 string JSON "Registro de acesso não encontrado" · 500 texto puro Erro ao remover acesso


Apêndice — Notas de Integração

  • Nenhum endpoint tem rate limit ou proteção anti-spam ativa hoje. Recomendamos que os POSTs de lead sejam feitos a partir do backend do seu site, não diretamente do navegador do visitante.
  • Formatos de resposta são inconsistentes entre endpoints (JSON vs. texto puro, {message} vs. string solta vs. {erro}/{mensagem}) — cada seção especifica o formato exato; não generalize.
  • CORS está liberado para qualquer origem — chamadas diretas do navegador funcionam sem configuração adicional.
  • Em caso de dúvida ou comportamento diferente do documentado, contate o time ImoFlow — este documento reflete o sistema em 18/08/2026 e pode receber correções.