Listings por Canal (Feed JSON)
Endpoint público, por canal, para sistemas externos consumirem seus imóveis filtrados em JSON. Autenticado por Bearer token gerado no próprio canal.
É o complemento simétrico dos Webhooks de Canais (Inbound): o mesmo pathToken que recebe leads agora também entrega imóveis.
Quando usar: quando um parceiro, landing page ou sistema externo precisa listar seus imóveis respeitando critérios que você definiu uma única vez no Garagem — sem precisar gerenciar uma API key por usuário, e sem expor a sua base inteira.
Ativação
Seção intitulada “Ativação”- Acesse Configurações → Canais e selecione o canal (ex.: o canal “API”).
- Vá em Recebimento → Saída de Imóveis (API) e ligue o toggle.
- Copie o Bearer token (mostrado apenas no momento da geração — guarde em local seguro).
- Copie a URL do endpoint.
Canais que já têm
capabilities.outboundListings = trueexpõem essa seção. O canal “API” padrão vem pronto.
Endpoint
Seção intitulada “Endpoint”GET https://app.garagem.ai/api/webhooks/channels/{pathToken}/listingsPOST https://app.garagem.ai/api/webhooks/channels/{pathToken}/listingspathToken— o mesmo token do webhook de leads do canal (ex.:chnl_2xxxxxxxxxxxxxxxxxxxxxxx).
Autenticação
Seção intitulada “Autenticação”Authorization: Bearer <TOKEN>- O token é gerado uma única vez. Para trocar, use Rotacionar na UI — isso invalida o anterior.
- Na UI, o token aparece mascarado como
••••••••••••abcd. O valor completo só é exibido logo após gerar/rotacionar.
Parâmetros
Seção intitulada “Parâmetros”O endpoint usa o mesmo motor de busca do site público (Typesense), respeitando os critérios base do canal (configurados em Exportação → Critérios Base).
GET (querystring)
Seção intitulada “GET (querystring)”| Parâmetro | Tipo | Descrição |
|---|---|---|
q | string | Texto livre (default: * = todos). Usa fullAddress, searchText, title, neighborhood, city.... |
page | number | Página (1-indexed). |
perPage | number | Itens por página (máx. 100, default ~12). |
sort | string | Ex.: price:asc, updatedAt:desc. |
query_by | string | Override do query_by do Typesense. |
filter_by | string | Filtros adicionais (combinados com os critérios base por AND). |
slot | string(s) | Filtrar por slot do canal. Aceita <slug>, <slug1>,<slug2> ou none (itens sem slot). |
facet_by | string | Campos para facetamento. |
POST (JSON body)
Seção intitulada “POST (JSON body)”Aceita qualquer campo do ClientSearchParams do @garagem/site-search:
{ "q": "*", "page": 1, "per_page": 20, "sort_by": "updatedAt:desc", "filter_by": "type:=rental && bedrooms:>=2", "slots": ["destaque_venda", "destaque_locacao"]}slots: string[]— equivalente ao?slot=no GET.
Slots (destaque / padrão / …)
Seção intitulada “Slots (destaque / padrão / …)”O canal usa os mesmos slots (publicationTypes) do resto do sistema: você os define em Exportação → Slots de Publicação com o slug e os critérios que quiser — incluindo filtros por tipo de anúncio (sale, rental, seasonal), preço, bairro etc.
Auto-provisionamento via integrações externas (Vista)
Seção intitulada “Auto-provisionamento via integrações externas (Vista)”Tenants com integração de provedor que marca imóveis como destaque (por exemplo, os campos DestaqueWeb e SuperDestaqueWeb do Vista) têm o canal “API” provisionado automaticamente:
- Na primeira sincronização que traga esses flags, o canal API é criado com
capabilities.outboundListings = true. - São semeados três slots:
super_destaque,destaqueestandard— já com critério padrãostage = <estágio ativo do tenant>(apenas imóveis no estágio ativo são considerados). - Os imóveis com flag de destaque são atribuídos automaticamente como
override_type: includeno slot correspondente. - Nenhuma configuração manual é necessária; parceiros podem consultar imediatamente
?slot=destaquee?slot=super_destaque.
Visibilidade é sempre aplicada globalmente (
visibility:=public && stage:=activeno filtro base), então imóveis privados nunca aparecem — mesmo que tenham sido marcados como destaque no provedor de origem.
Exemplos de configuração que tenants costumam usar:
- Slot
destaque_venda→criteria.type = "sale",totalSlots = 5 - Slot
destaque_locacao→criteria.type = "rental",totalSlots = 10 - Slot
standard→ semcriteria, pega o resto.
Cada item da resposta ganha o campo calculado:
"slot": "<slug>" | null(ou null se o listing passou nos critérios base mas não foi atribuído a nenhum slot).
Discovery de slots
Seção intitulada “Discovery de slots”Liste os slots configurados do canal para construir filtros dinâmicos:
GET /api/webhooks/channels/{pathToken}/listings/slotsAuthorization: Bearer <TOKEN>Resposta:
{ "channelId": "uuid-do-canal", "slots": [ { "slug": "destaque_venda", "totalSlots": 5, "usedSlots": 3 }, { "slug": "destaque_locacao", "totalSlots": 10, "usedSlots": 7 }, { "slug": "standard", "totalSlots": 0, "usedSlots": 0 } ]}Resposta
Seção intitulada “Resposta”Mesmo shape sanitizado do endpoint de site público (Typesense), com slot injetado em cada document:
{ "found": 127, "page": 1, "search_time_ms": 4, "hits": [ { "document": { "id": "uuid-do-listing", "title": "Apartamento 2 quartos - Pinheiros", "title_en": "2-bedroom apartment - Pinheiros", "description_en": "Bright unit near the subway...", "title_es": "", "description_es": "", "type": "rental", "price": 3500, "currency": "BRL", "bedrooms": 2, "bathrooms": 1, "usableArea": 68, "neighborhood": "Pinheiros", "city": "São Paulo", "state": "SP", "mediaUrls": ["https://cdn.fndn.ai/..."], "slot": "destaque_locacao", "updatedAt": 1713800000 }, "highlights": [], "text_match": 0 } ], "facet_counts": []}Campos sensíveis (contatos, números exatos de endereço, coordenadas precisas) são automaticamente removidos/mascarados — mesma lógica de sanitização do site público.
Copy por idioma: o documento é o mesmo do Sites API — busca, incluindo
title_en,description_en,title_esedescription_es. Resolva título/descrição no cliente com fallback para português — veja Título e descrição por idioma.
Mercado primário no documento
Seção intitulada “Mercado primário no documento”Hits de lançamento incluem os mesmos campos Typesense da Sites API (isPrimaryMarket, marketType, typologyId, constructionStatus, expectedDelivery, availableUnits, hasAvailableUnits, etc.) — veja Campos de mercado primário na busca.
Em exportações de canal no formato canônico Babelfish, lançamentos com tipologia também podem trazer um bloco extensions.garagem:
{ "extensions": { "garagem": { "isPrimaryMarket": true, "typologyId": "typology-uuid", "typology": { "name": "Tipo A - 2 Dormitórios", "code": "TIP-A", "description": "...", "bedrooms": 2, "bathrooms": 2, "suites": 1, "totalArea": 68, "privateArea": 62, "garageSpots": 1, "basePrice": 650000, "pricePerSqm": 9500, "features": {}, "files": [], "totalUnits": 40, "expectedDelivery": "Dezembro 2026", "constructionStatus": "structure" } } }}
extensions.garagemespelha a tipologia no feed de saída; preferência de intake écanonical.primaryMarketem integrações Babelfish. Quartos e área no nível raiz do listing continuam refletindo a tipologia quandoisPrimaryMarketé verdadeiro.
Exemplos
Seção intitulada “Exemplos”Listar tudo (respeitando critérios do canal)
Seção intitulada “Listar tudo (respeitando critérios do canal)”curl -H "Authorization: Bearer <TOKEN>" \ "https://app.garagem.ai/api/webhooks/channels/chnl_seu_token/listings?page=1&perPage=20"Só imóveis em destaque (locação)
Seção intitulada “Só imóveis em destaque (locação)”curl -H "Authorization: Bearer <TOKEN>" \ "https://app.garagem.ai/api/webhooks/channels/chnl_seu_token/listings?slot=destaque_locacao&perPage=50"Múltiplos slots
Seção intitulada “Múltiplos slots”curl -H "Authorization: Bearer <TOKEN>" \ "https://app.garagem.ai/api/webhooks/channels/chnl_seu_token/listings?slot=destaque_venda,destaque_locacao"Itens SEM slot atribuído
Seção intitulada “Itens SEM slot atribuído”curl -H "Authorization: Bearer <TOKEN>" \ "https://app.garagem.ai/api/webhooks/channels/chnl_seu_token/listings?slot=none"POST com filtros combinados
Seção intitulada “POST com filtros combinados”curl -X POST \ -H "Authorization: Bearer <TOKEN>" \ -H "Content-Type: application/json" \ -d '{ "q": "*", "page": 1, "per_page": 20, "sort_by": "price:asc", "filter_by": "type:=sale && bedrooms:>=3", "slots": ["destaque_venda"] }' \ "https://app.garagem.ai/api/webhooks/channels/chnl_seu_token/listings"Discovery
Seção intitulada “Discovery”curl -H "Authorization: Bearer <TOKEN>" \ "https://app.garagem.ai/api/webhooks/channels/chnl_seu_token/listings/slots"Códigos de Erro
Seção intitulada “Códigos de Erro”| Status | Code | Significado |
|---|---|---|
| 401 | missing_bearer | Header Authorization: Bearer ausente ou mal formado. |
| 401 | invalid_bearer | Token não confere com o hash armazenado. Pode ter sido rotacionado. |
| 404 | endpoint_not_found | pathToken inválido ou canal sem saída de imóveis habilitada. |
| 400 | invalid_body | Body JSON inválido no POST. |
| 503 | search_config_incomplete | Infra de busca indisponível (coleção Typesense faltando). |
| 503 | search_key_missing | Configuração de Typesense ausente no servidor. |
| 500 | search_failed | Erro inesperado no Typesense. |
Segurança e Limites
Seção intitulada “Segurança e Limites”- Sanitização automática: mesmo conjunto de campos sensíveis removidos pelo site público (contatos, números de endereço, coordenadas mascaradas em ~100 m).
- Visibilidade: o filtro base aplica
visibility:=public && stage:=active— imóveis privados não vazam pelo endpoint, mesmo sem filtro explícito. - Cache:
Cache-Control: private, no-store— a resposta depende do token e do tenant, não é cacheada pelo CDN. - Rate limit: aplicado no endpoint (reusa
channelInboundEndpoint.rateLimits). - Logs: toda requisição gera log estruturado (
tenantId,channelInstanceId,found,durationMs) — útil pra auditoria.
REST vs Canal — quando usar cada um?
Seção intitulada “REST vs Canal — quando usar cada um?”GET /api/v1/real-estate/listings | /api/webhooks/channels/{pathToken}/listings | |
|---|---|---|
| Auth | API key do usuário (Bearer) | Bearer token do canal |
| Critérios | Definidos na query string | Salvos no canal (UI) |
| Slots/Destaque | Não | Sim (mesmo modelo dos portais) |
| Escopo | RBAC do usuário (tudo que ele pode ver) | Só imóveis que batem os critérios do canal |
| Ideal para | Automação interna, scripts do tenant | Sites parceiros, landing pages, agregadores |
Ver também: 05 - Anúncios (API interna por usuário) e 08 - Webhooks e Eventos (inbound de leads).