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.
📖 Visão Geral
Seção intitulada “📖 Visão Geral”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.
🔍 Visibilidade do Anúncio
Seção intitulada “🔍 Visibilidade do Anúncio”O campo visibility controla se o anúncio aparece em buscas públicas e sites integrados.
Valores Disponíveis
Seção intitulada “Valores Disponíveis”| Valor | Comportamento |
|---|---|
public | Anúncio visível em buscas públicas, sites e portais integrados |
private | Anúncio oculto de buscas públicas (visível apenas internamente) |
Quando Usar
Seção intitulada “Quando Usar”public(padrão): Anúncio pronto para ser divulgadoprivate: Anúncio em preparação, exclusivo para clientes específicos, ou temporariamente suspenso
Exemplo de Criação com Visibilidade
Seção intitulada “Exemplo de Criação com Visibilidade”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" } ] }'Alterar Visibilidade
Seção intitulada “Alterar Visibilidade”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" }'💰 Visibilidade do Preço
Seção intitulada “💰 Visibilidade do Preço”O campo priceVisibility controla se o preço é exibido publicamente.
Valores Disponíveis
Seção intitulada “Valores Disponíveis”| Valor | Comportamento |
|---|---|
public | Preço visível em todos os contextos |
private | Preço oculto (exibe “Consulte” ou similar no site) |
Exemplo
Seção intitulada “Exemplo”{ "price": "450000.00", "priceVisibility": "private"}Nota: A visibilidade do preço em links de compartilhamento pode ser sobrescrita pela configuração
sharingConfig.fieldVisibility.pricedo tenant. Veja Compartilhamento.
📊 Endpoints
Seção intitulada “📊 Endpoints”Listar Anúncios
Seção intitulada “Listar Anúncios”GET /api/v1/real-estate/listingsParâmetros de Query:
| Parâmetro | Tipo | Descrição |
|---|---|---|
page | number | Número da página (default: 1) |
pageSize | number | Itens por página (default: 50, max: 100) |
type | string | Filtrar por tipo: rental ou sale |
stage | string | Filtrar por etapa do workflow |
visibility | string | Filtrar por visibilidade: public ou private |
Exemplo:
# Listar apenas anúncios públicos de aluguelcurl -X GET "https://app.garagem.ai/api/v1/real-estate/listings?type=rental&visibility=public" \ -H "Authorization: Bearer sua_api_key"Buscar Anúncios (Typesense)
Seção intitulada “Buscar Anúncios (Typesense)”GET /api/v1/real-estate/listings/searchEndpoint 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âmetro | Tipo | Descrição |
|---|---|---|
query | string | Texto livre (endereço, código, título). |
page / pageSize | number | Paginação (pageSize ≤ 100). |
type | enum | sale ou rental. |
visibility | enum | public ou private (omita para incluir os dois). |
hasPhotos | bool | true = só com fotos; false = só sem fotos. |
minPhotos | number | Mínimo de fotos (photoCount:>=N). |
hasVirtualTour | bool | Só anúncios com tour virtual. |
hasVideo | bool | Só anúncios com vídeo. |
bedrooms | number | Mínimo de quartos. |
minArea / maxArea | number | Faixa de área em m². |
budget | number | Preço máximo (BRL). |
propertyTypes | string[] | IDs ou rótulos de tipos (auto-resolvidos). |
locations | string[] | Bairros, ruas ou cidades de interesse. |
neighborhood / city / state | string | Filtro exato de localização. |
latitude / longitude / radiusKm | number | Busca geográfica por raio. |
filter | string | Escape hatch raw do Typesense (ver abaixo). |
includeNetworks | bool | Incluir rede de parceiros (default true). |
Exemplo — anúncios públicos com pelo menos 5 fotos em São Paulo:
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:
# "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.
Filtros de mercado primário (Typesense)
Seção intitulada “Filtros de mercado primário (Typesense)”| Campo | Valores | Exemplo de filter |
|---|---|---|
marketType | primary, secondary | marketType:=primary |
constructionStatus | texto livre / código CRM | constructionStatus:=plant |
hasAvailableUnits | boolean | hasAvailableUnits:=true |
# Lançamentos com unidades disponíveis em São Paulocurl -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
/listingsvs/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.
Buscar Anúncio por ID
Seção intitulada “Buscar Anúncio por ID”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"}Deletar Anúncio
Seção intitulada “Deletar Anúncio”DELETE /api/v1/real-estate/listings/{id}🔎 Busca com Typesense
Seção intitulada “🔎 Busca com Typesense”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.
Endpoint de Busca (Sites)
Seção intitulada “Endpoint de Busca (Sites)”POST /api/sites/{siteId}/searchFiltros automáticos aplicados:
visibility:=public- Apenas anúncios públicosstage:=active- Apenas anúncios em etapa ativa (configurável)- Listing Criteria do Site - Filtros configurados no painel do site
Exemplo:
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.
📋 Campos do Anúncio
Seção intitulada “📋 Campos do Anúncio”Campos Principais
Seção intitulada “Campos Principais”| Campo | Tipo | Descrição |
|---|---|---|
id | uuid | Identificador único |
title | string | Título do anúncio |
description | string | Descrição detalhada |
type | enum | rental ou sale |
price | decimal | Preço do anúncio |
priceVisibility | enum | public ou private |
visibility | enum | public ou private |
stage | string | Etapa do workflow (ex: active, closed) |
status | string | Sub-status dentro da etapa |
listingCode | string | Código de referência (auto-gerado se vazio) |
propertyId | uuid | ID da propriedade associada |
isPrimaryMarket | string | "true" ou "false" — mercado primário (lançamento) vs revenda |
typologyId | uuid | Tipologia vinculada (opcional; lançamentos podem ser só com flag) |
translations | object | Traduções opcionais de título/descrição (en, es) — veja abaixo |
Mercado primário (lançamento)
Seção intitulada “Mercado primário (lançamento)”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" } ]}| Campo | Tipo | Descrição |
|---|---|---|
isPrimaryMarket | "true" | "false" | Default "false". Armazenado como texto no banco. |
typologyId | uuid | FK 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.
Traduções (en / es)
Seção intitulada “Traduções (en / es)”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 locale | Tipo | Descrição |
|---|---|---|
title | string | Título traduzido (opcional) |
description | string | Descrição traduzida (opcional) |
source | "manual" | "ai" | Integrações devem usar "manual". "ai" é preenchido pelo CRM quando a tradução automática está habilitada. |
translatedAt | string (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:
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.).
Campos Específicos por Tipo
Seção intitulada “Campos Específicos por Tipo”Aluguel (rental)
Seção intitulada “Aluguel (rental)”{ "typeSpecificData": { "deposit": 7000, "iptu": 200, "condominiumFee": 500, "rentalPeriod": "12 meses", "furnished": true }}Venda (sale)
Seção intitulada “Venda (sale)”{ "typeSpecificData": { "downPayment": 90000, "financingAllowed": true, "iptu": 500, "condominiumFee": 800 }}Critérios de Aceitação
Seção intitulada “Critérios de Aceitação”{ "acceptanceCriteria": { "minIncome": 10500, "requiresGuarantor": true, "petAllowed": true, "smokingAllowed": false, "maxOccupants": 3 }}🔗 Relacionamentos
Seção intitulada “🔗 Relacionamentos”Visibilidade vs Compartilhamento
Seção intitulada “Visibilidade vs Compartilhamento”| Conceito | Descriçã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.
📚 Mais Informações
Seção intitulada “📚 Mais Informações”- Sites API - Endpoints públicos para WordPress e sites externos
- Exemplos Práticos - Casos de uso com código
- Compartilhamento - Links de compartilhamento
- Campos Customizados - Campos customizados em listings