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
categoria—Busca parcial (ignora caixa)
all—Se 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/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

§11 Área do cliente (imóveis de interesse)

Endpoints para montar, no seu site, a página em que o cliente final vê os imóveis e empreendimentos que o corretor enviou para ele e responde a cada um (descartar, reativar, marcar interesse). Na ImoFlow essa página é /cliente/{id}.

TELA/cliente/:idVisão geral: o que a página faz

O :id da URL é o ID do cliente (pessoa) no CRM da ImoFlow. A página funciona assim:

  1. Ao abrir /cliente/:id, faz uma chamada GET /pessoas/:id. Ela devolve o nome do cliente e três listas: De interesse, Recomendados e Descartados (cada uma com imóveis e empreendimentos).
  2. Se quiser mostrar os dados do corretor responsável, use o idResponsavelAtendimento retornado em GET /corretores/:id.
  3. Mostra "Olá, {nome}" e as três abas, com um card por item.
  4. Cada botão do card chama um PATCH, conforme a tabela abaixo.
AbaBotãoChamadaO item vai para
De interesseDescartarPATCH /pessoas/:id/descartar-interesseDescartados
RecomendadosTenho interessePATCH /pessoas/:id/marcar-interesseDe interesse
RecomendadosDescartarPATCH /pessoas/:id/descartar-recomendadoDescartados
DescartadosReativarPATCH /pessoas/:id/reativar-interesseDe interesse
!
Segurança: não há senha nem token neste fluxo. O id do cliente é o único identificador, então quem tem o link acessa a página e pode executar as ações. Gere os links só para o próprio cliente e não os exponha em páginas públicas.

Dica: mova o card de aba assim que o cliente clica, sem esperar a resposta, e desfaça o movimento se o PATCH falhar (é o que a ImoFlow faz).

GET/pessoas/:idDados da página do cliente

id — ObjectId do cliente (pessoa). Sem query params.

Resposta 200

{
  "nome": "Fulano de Tal",
  "idResponsavelAtendimento": "ObjectId do corretor" | null,
  "perfilInteresse": {
    "id_imovel": [ /* imóveis DE INTERESSE */ ],
    "enviadosDetalhados": [ /* imóveis RECOMENDADOS */ ],
    "descartadosDetalhados": [ /* imóveis DESCARTADOS */ ]
  },
  "empreendimentos": {
    "interesse": [ /* empreendimentos de interesse */ ],
    "recomendados": [ /* empreendimentos recomendados */ ],
    "descartados": [ /* empreendimentos descartados */ ]
  }
}

Como cada lista é formada

ListaRegra
De interesseUnião dos itens de interesse de todos os atendimentos em andamento do cliente (sem nenhum em andamento, usa o mais recente)
DescartadosItens que o cliente (ou o corretor) descartou
RecomendadosItens enviados ao cliente que ainda não estão em interesse nem descartados

Um item aparece em uma lista só. Imóveis não encontrados e empreendimentos ocultos não são retornados.

Estrutura de cada imóvel

!
Estrutura mais enxuta que a de §5 Imóveis: não vêm status, statusTag, seo_data, plantas, vídeos nem tour.
CampoTipoDescrição
_idstringID do imóvel (use no imovelId dos PATCH)
sobreobjectfinalidade, tipo do imóvel, categoria, referência etc.
valoresobjectvalores de venda/aluguel e condições
localizacaoobjectendereço (cidade, bairro, estado etc.)
caracteristicasobjectquartos, suites, banheiros, salas, vagas, imovelAreaTotal, imovelAreaUtil, imovelAreaComum, etiquetas
midias.imagensarray (máx. 10){filename,url,ordem}. Se vier vazio, use uma imagem padrão sua.

Estrutura de cada empreendimento

CampoDescrição
_idID do empreendimento (use no condominioId dos PATCH)
nome, refEmpreendimento, categoria, categoriaImovel, tipoIdentificação e classificação
imagens, seo_dataMídias e SEO
rua, bairro, cidade, estadoEndereço
dormitorios, suites, vagas, varanda, deposito, areaMinima, areaMaximaCaracterísticas das unidades
andares, blocos, apartamentoPorAndar, idadeImovel, fechado, unidadesDados do empreendimento
valorMinimo, valorMaximo, visivelValoresFaixa de valores. Só exiba se visivelValores for true.

Erros

400 string JSON "ID de pessoa inválido" · 404 string JSON "Pessoa não encontrada" · 500 {message:'Erro ao obter perfil de interesse'}

Exemplo

curl "https://so-mansoes.imoflow.app.br/api/portal/pessoas/ID_DO_CLIENTE"
PATCH/pessoas/:id/descartar-interesseDescartar item de interesse

Cliente decide que não quer mais um item que estava em "De interesse".

Botão na tela: aba De interesse → Descartar

Body (JSON): envie um dos dois campos: {"imovelId": "ObjectId"} para imóvel ou {"condominioId": "ObjectId"} para empreendimento. Se enviar os dois, vale o imovelId.

Resultado: o item sai do interesse de todos os atendimentos do cliente e passa para Descartados. O descarte fica registrado.

Resposta 200: {"message": "Ação registrada com sucesso."}

Erros

400 string JSON "ID de pessoa inválido" ou "Informe o imóvel ou o empreendimento." · 404 string JSON "Pessoa não encontrada" · 500 texto puro Não foi possível concluir a ação.

Exemplo

curl -X PATCH "https://so-mansoes.imoflow.app.br/api/portal/pessoas/ID_DO_CLIENTE/descartar-interesse" \
  -H "Content-Type: application/json" \
  -d '{"imovelId":"ID_DO_IMOVEL"}'
PATCH/pessoas/:id/reativar-interesseReativar item descartado

Cliente se arrependeu e quer voltar a considerar um item descartado.

Botão na tela: aba Descartados → Reativar

Body (JSON): envie um dos dois campos: {"imovelId": "ObjectId"} para imóvel ou {"condominioId": "ObjectId"} para empreendimento. Se enviar os dois, vale o imovelId.

Resultado: o item sai de Descartados e volta para De interesse, no atendimento em andamento mais recente (se o cliente não tiver nenhum atendimento, um novo é criado).

Resposta 200: {"message": "Ação registrada com sucesso."}

Erros

400 string JSON "ID de pessoa inválido" ou "Informe o imóvel ou o empreendimento." · 404 string JSON "Pessoa não encontrada" · 500 texto puro Não foi possível concluir a ação.

Exemplo

curl -X PATCH "https://so-mansoes.imoflow.app.br/api/portal/pessoas/ID_DO_CLIENTE/reativar-interesse" \
  -H "Content-Type: application/json" \
  -d '{"imovelId":"ID_DO_IMOVEL"}'
PATCH/pessoas/:id/marcar-interesseMarcar interesse em recomendado

Cliente demonstra interesse em um item que o corretor recomendou.

Botão na tela: aba Recomendados → Tenho interesse

Body (JSON): envie um dos dois campos: {"imovelId": "ObjectId"} para imóvel ou {"condominioId": "ObjectId"} para empreendimento. Se enviar os dois, vale o imovelId.

Resultado: o item passa para De interesse no atendimento em andamento mais recente (criado se não existir). A ação fica registrada no histórico do atendimento e o corretor responsável é avisado.

Resposta 200: {"message": "Ação registrada com sucesso."}

Erros

400 string JSON "ID de pessoa inválido" ou "Informe o imóvel ou o empreendimento." · 404 string JSON "Pessoa não encontrada" · 500 texto puro Não foi possível concluir a ação.

Exemplo

curl -X PATCH "https://so-mansoes.imoflow.app.br/api/portal/pessoas/ID_DO_CLIENTE/marcar-interesse" \
  -H "Content-Type: application/json" \
  -d '{"imovelId":"ID_DO_IMOVEL"}'
PATCH/pessoas/:id/descartar-recomendadoDescartar item recomendado

Cliente recusa um item recomendado sem ter marcado interesse antes.

Botão na tela: aba Recomendados → Descartar

Body (JSON): envie um dos dois campos: {"imovelId": "ObjectId"} para imóvel ou {"condominioId": "ObjectId"} para empreendimento. Se enviar os dois, vale o imovelId.

Resultado: o item passa para Descartados e deixa de aparecer em Recomendados.

Resposta 200: {"message": "Ação registrada com sucesso."}

Erros

400 string JSON "ID de pessoa inválido" ou "Informe o imóvel ou o empreendimento." · 404 string JSON "Pessoa não encontrada" · 500 texto puro Não foi possível concluir a ação.

Exemplo

curl -X PATCH "https://so-mansoes.imoflow.app.br/api/portal/pessoas/ID_DO_CLIENTE/descartar-recomendado" \
  -H "Content-Type: application/json" \
  -d '{"imovelId":"ID_DO_IMOVEL"}'

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.