Pular para o conteúdo

Anúncios (Listings)

Esta seção documenta os endpoints e configurações para gerenciamento de anúncios de imóveis.

Precisa expor imóveis filtrados para um parceiro/site externo, sem gerenciar uma API key por usuário e com destaque/slots? Use o Feed JSON por Canal — autenticado por Bearer token do próprio canal, respeita critérios salvos e expõe slots (destaque, super, etc.) por item.


Anúncios (listings) representam a oferta de um imóvel para venda ou aluguel. Um imóvel (property) pode ter múltiplos anúncios ativos simultaneamente.


O campo visibility controla se o anúncio aparece em buscas públicas e sites integrados.

ValorComportamento
publicAnúncio visível em buscas públicas, sites e portais integrados
privateAnúncio oculto de buscas públicas (visível apenas internamente)
  • public (padrão): Anúncio pronto para ser divulgado
  • private: Anúncio em preparação, exclusivo para clientes específicos, ou temporariamente suspenso
Janela do terminal
curl -X POST https://app.garagem.ai/api/v1/real-estate/properties \
-H "Authorization: Bearer sua_api_key" \
-H "Content-Type: application/json" \
-d '{
"property": {
"title": "Apartamento 2 quartos - Copacabana",
"type": "apartment",
"bedrooms": 2,
"bathrooms": 1,
"totalArea": "75"
},
"location": {
"neighborhood": "Copacabana",
"city": "Rio de Janeiro",
"state": "RJ"
},
"listings": [
{
"title": "Apartamento para alugar",
"type": "rental",
"price": "3500.00",
"currency": "BRL",
"stage": "active",
"visibility": "public"
}
]
}'
Janela do terminal
curl -X PATCH https://app.garagem.ai/api/v1/real-estate/listings/{id} \
-H "Authorization: Bearer sua_api_key" \
-H "Content-Type: application/json" \
-d '{
"visibility": "private"
}'

O campo priceVisibility controla se o preço é exibido publicamente.

ValorComportamento
publicPreço visível em todos os contextos
privatePreço oculto (exibe “Consulte” ou similar no site)
{
"price": "450000.00",
"priceVisibility": "private"
}

Nota: A visibilidade do preço em links de compartilhamento pode ser sobrescrita pela configuração sharingConfig.fieldVisibility.price do tenant. Veja Compartilhamento.


GET /api/v1/real-estate/listings

Parâmetros de Query:

ParâmetroTipoDescrição
pagenumberNúmero da página (default: 1)
pageSizenumberItens por página (default: 50, max: 100)
typestringFiltrar por tipo: rental ou sale
stagestringFiltrar por etapa do workflow
visibilitystringFiltrar por visibilidade: public ou private

Exemplo:

Janela do terminal
# Listar apenas anúncios públicos de aluguel
curl -X GET "https://app.garagem.ai/api/v1/real-estate/listings?type=rental&visibility=public" \
-H "Authorization: Bearer sua_api_key"
GET /api/v1/real-estate/listings/search

Endpoint de busca tenant-wide alimentado pelo mesmo índice Typesense da página /imoveis e da ferramenta MCP real-estate.search_listings. Diferente do GET /api/v1/real-estate/listings (que vai no Postgres), este expõe o conjunto completo de filtros ricos: visibilidade, mídia, geolocalização, áreas, faixas de preço, e um escape hatch raw para qualquer campo indexado.

A autenticação é a mesma do resto do /api/v1 (Authorization: Bearer <api_key>). O escopo (incluindo se anúncios privados aparecem) segue o RBAC do dono da chave — chaves de leitura ampla veem privados, chaves restritas veem só o que a UI permitiria àquele perfil.

Parâmetros de Query principais:

ParâmetroTipoDescrição
querystringTexto livre (endereço, código, título).
page / pageSizenumberPaginação (pageSize ≤ 100).
typeenumsale ou rental.
visibilityenumpublic ou private (omita para incluir os dois).
hasPhotosbooltrue = só com fotos; false = só sem fotos.
minPhotosnumberMínimo de fotos (photoCount:>=N).
hasVirtualTourboolSó anúncios com tour virtual.
hasVideoboolSó anúncios com vídeo.
bedroomsnumberMínimo de quartos.
minArea / maxAreanumberFaixa de área em m².
budgetnumberPreço máximo (BRL).
propertyTypesstring[]IDs ou rótulos de tipos (auto-resolvidos).
locationsstring[]Bairros, ruas ou cidades de interesse.
neighborhood / city / statestringFiltro exato de localização.
latitude / longitude / radiusKmnumberBusca geográfica por raio.
filterstringEscape hatch raw do Typesense (ver abaixo).
includeNetworksboolIncluir rede de parceiros (default true).

Exemplo — anúncios públicos com pelo menos 5 fotos em São Paulo:

Janela do terminal
curl -X GET "https://app.garagem.ai/api/v1/real-estate/listings/search?city=S%C3%A3o%20Paulo&visibility=public&minPhotos=5&pageSize=20" \
-H "Authorization: Bearer sua_api_key"

Exemplo — escape hatch raw para campos não tipados:

Janela do terminal
# "Apartamentos com parceria, condomínio < R$ 800 e piscina"
curl -X GET "https://app.garagem.ai/api/v1/real-estate/listings/search" \
--data-urlencode "type=sale" \
--data-urlencode 'filter=hasPartnership:=true && condoFee:<800 && propertyFeatures:=[piscina]' \
-G \
-H "Authorization: Bearer sua_api_key"

Campos indexados acessíveis via filter incluem também hasPartnership, isExclusive, hasActiveExclusivity, occupancyStatus, condition, slaStatus, hasIntegrationError, propertyFeatures, buildingAmenities, condoFee, propertyTax, listingScore, qualityScore, viewsCount, leadsCount, providerName, hasProviderSync, createdAt / updatedAt / publishedAt (epoch seconds), entre outros. O filtro do tenant + RBAC são &&-prefixados internamente, então filter nunca quebra o isolamento — uma string malformada gera 400 do Typesense, sem vazamento.

CampoValoresExemplo de filter
marketTypeprimary, secondarymarketType:=primary
constructionStatustexto livre / código CRMconstructionStatus:=plant
hasAvailableUnitsbooleanhasAvailableUnits:=true
Janela do terminal
# Lançamentos com unidades disponíveis em São Paulo
curl -G "https://app.garagem.ai/api/v1/real-estate/listings/search" \
--data-urlencode "city=São Paulo" \
--data-urlencode "filter=marketType:=primary && hasAvailableUnits:=true" \
-H "Authorization: Bearer sua_api_key"

Sites públicos e feeds por canal expõem os mesmos campos no documento Typesense — veja Sites API — Mercado primário.

Resposta (resumida):

{
"items": [
{
"id": "...",
"listingCode": "AP-001",
"title": "Apartamento 2 quartos",
"price": 3500,
"location": {
"neighborhood": "Pinheiros",
"city": "São Paulo",
"...": "..."
},
"features": { "area": 65, "rooms": 2, "bathrooms": 1, "garageSpots": 1 },
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-08-22T14:12:33.000Z",
"publishedAt": "2024-01-20T09:00:00.000Z",
"isNetworkListing": false
}
],
"total": 142,
"page": 1,
"pageSize": 20
}

Quando usar /listings vs /listings/search: use /listings (Postgres) quando precisar de leitura consistente em tempo real e do shape completo da row (campos JSONB, contatos, comissões). Use /listings/search (Typesense) para filtros ricos, busca textual, paginação eficiente e geolocalização — a indexação roda em segundos após mudanças.

GET /api/v1/real-estate/listings/{id}

Resposta:

{
"id": "uuid-do-anuncio",
"title": "Apartamento 2 quartos para alugar",
"type": "rental",
"price": "3500.00",
"priceVisibility": "public",
"visibility": "public",
"stage": "active",
"status": null,
"listingCode": "AP-001",
"propertyId": "uuid-da-propriedade",
"isPrimaryMarket": "false",
"typologyId": null,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
DELETE /api/v1/real-estate/listings/{id}

Para buscas avançadas em sites públicos, use o endpoint de busca que respeita automaticamente a visibilidade.

📖 Documentação completa: Veja Sites API - Busca de Imóveis para detalhes técnicos completos.

POST /api/sites/{siteId}/search

Filtros automáticos aplicados:

  • visibility:=public - Apenas anúncios públicos
  • stage:=active - Apenas anúncios em etapa ativa (configurável)
  • Listing Criteria do Site - Filtros configurados no painel do site

Exemplo:

Janela do terminal
curl -X POST https://app.garagem.ai/api/sites/{siteId}/search \
-H "Content-Type: application/json" \
-d '{
"q": "apartamento copacabana",
"query_by": "title,description,neighborhood",
"filter_by": "type:=rental && price:<=4000",
"per_page": 12
}'

📖 Veja Exemplos Práticos para mais detalhes sobre busca.


CampoTipoDescrição
iduuidIdentificador único
titlestringTítulo do anúncio
descriptionstringDescrição detalhada
typeenumrental ou sale
pricedecimalPreço do anúncio
priceVisibilityenumpublic ou private
visibilityenumpublic ou private
stagestringEtapa do workflow (ex: active, closed)
statusstringSub-status dentro da etapa
listingCodestringCódigo de referência (auto-gerado se vazio)
propertyIduuidID da propriedade associada
isPrimaryMarketstring"true" ou "false" — mercado primário (lançamento) vs revenda
typologyIduuidTipologia vinculada (opcional; lançamentos podem ser só com flag)
translationsobjectTraduções opcionais de título/descrição (en, es) — veja abaixo

Em revenda, quartos, área e preço vêm do imóvel (property). Em lançamento, as características comerciais vêm da tipologia; o anúncio carrega isPrimaryMarket: "true" e, quando aplicável, typologyId.

Gravar via REST — inclua nos objetos listings[] de POST/PATCH /api/v1/real-estate/properties:

{
"listings": [
{
"title": "Tipo A — 2 dormitórios",
"type": "sale",
"price": "650000.00",
"isPrimaryMarket": "true",
"typologyId": "uuid-da-tipologia"
}
]
}
CampoTipoDescrição
isPrimaryMarket"true" | "false"Default "false". Armazenado como texto no banco.
typologyIduuidFK para a tipologia do empreendimento. Opcional em integrações que só marcam lançamento (ex.: Vista).

Não há CRUD REST público de tipologias/unidades — crie no CRM ou importe via provedor. Para ler tipologias, unidades e empreendimento em sites, use a Sites API.

O português fica sempre em title e description. Inglês e espanhol vão no objeto translations (JSONB), indexados na busca pública como title_en, description_en, title_es e description_es. Veja Sites API — Título e descrição por idioma para consumir esses campos em sites e feeds.

Habilitar idiomas: Configurações → Estrutura → Tipos → idiomas do anúncio (sempre inclui pt-BR; en e es são opt-in).

Formato:

{
"translations": {
"en": {
"title": "2-bedroom apartment in Copacabana",
"description": "Fully renovated with ocean view...",
"source": "manual",
"translatedAt": "2026-08-19T12:00:00.000Z"
},
"es": {
"title": "Apartamento de 2 dormitorios en Copacabana",
"description": "Totalmente reformado con vista al mar...",
"source": "manual"
}
}
}
Campo por localeTipoDescrição
titlestringTítulo traduzido (opcional)
descriptionstringDescrição traduzida (opcional)
source"manual" | "ai"Integrações devem usar "manual". "ai" é preenchido pelo CRM quando a tradução automática está habilitada.
translatedAtstring (ISO 8601)Opcional; timestamp da última atualização da tradução

Não existe endpoint REST público para tradução automática por IA. Parceiros enviam copy pronta com source: "manual".

Como gravar: use POST ou PATCH /api/v1/real-estate/properties com listings[] contendo translations. O PATCH de anúncio isolado (PATCH /api/v1/real-estate/listings/{id}) não aceita translations — atualize via property + listing aninhado.

Exemplo — adicionar tradução em inglês a um listing existente:

Janela do terminal
curl -X PATCH "https://app.garagem.ai/api/v1/real-estate/properties/{propertyId}" \
-H "Authorization: Bearer sua_api_key" \
-H "Content-Type: application/json" \
-d '{
"listings": [
{
"id": "uuid-do-listing",
"translations": {
"en": {
"title": "2-bedroom apartment for rent",
"description": "Excellent renovated apartment...",
"source": "manual"
}
}
}
]
}'

Após salvar, os campos aparecem na busca pública em segundos (title_en, description_en, etc.).

{
"typeSpecificData": {
"deposit": 7000,
"iptu": 200,
"condominiumFee": 500,
"rentalPeriod": "12 meses",
"furnished": true
}
}
{
"typeSpecificData": {
"downPayment": 90000,
"financingAllowed": true,
"iptu": 500,
"condominiumFee": 800
}
}
{
"acceptanceCriteria": {
"minIncome": 10500,
"requiresGuarantor": true,
"petAllowed": true,
"smokingAllowed": false,
"maxOccupants": 3
}
}

ConceitoDescrição
Visibility (Anúncio)Controla se o anúncio aparece em buscas públicas
Field Visibility (Tenant)Controla quais campos são exibidos em links compartilhados

Um anúncio private ainda pode ser compartilhado via link direto. A configuração sharingConfig.fieldVisibility controla quais informações são exibidas no link.

📖 Veja Compartilhamento para configurar visibilidade de campos em links.