Base URL: https://api.webzy.com.br/api/v1
Autenticação

Todas as requisições exigem um token no header Authorization:

GET https://api.webzy.com.br/api/v1/products

# Headers obrigatórios:
Authorization: Bearer SEU_TOKEN_AQUI
Accept: application/json

Headers de Rate Limit (incluídos em todas as respostas):

X-RateLimit-LimitLimite máximo de requisições por minuto
X-RateLimit-RemainingRequisições restantes na janela atual
Retry-AfterSegundos até poder tentar novamente (só quando excede o limite)

Verificar token:

GET https://api.webzy.com.br/api/v1/me

# Retorna informações do token e do tenant associado
Formato das Respostas

Sucesso (registro único):

{
  "success": true,
  "message": "Success",
  "data": {
    "id": 1,
    "title": "..."
  }
}

Erro:

{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "title": ["The title field is required."]
  }
}
Preço Promocional

Disponível em Imóveis, Veículos e Produtos. O campo promotional_price representa o preço com desconto. Quando preenchido e estritamente menor que price, o site exibe o formato "De ~~R$ X~~ por R$ Y" com o percentual de desconto.

Regras de validação:

  • promotional_price é opcional — envie null (ou omita) para não ter promoção.
  • Quando preenchido, deve ser ≥ 0.01 e estritamente menor que price.
  • Em PUT parcial, se price não for enviado no payload, o valor armazenado no banco é usado como referência.

Resposta com promoção ativa (GET):

{
  "id": 42,
  "title": "Apartamento 3 quartos - Centro",
  "price": 450000,
  "promotional_price": 399000,
  "promotion": {
    "active": true,
    "percentage": 11,
    "price_from": 450000,
    "price_to": 399000
  },
  // ...demais campos
}
// Quando não há promoção: "promotional_price": null e "promotion": null

Filtrar somente itens em promoção:

GET https://api.webzy.com.br/api/v1/imoveis?on_sale=1
GET https://api.webzy.com.br/api/v1/vehicles?on_sale=1
GET https://api.webzy.com.br/api/v1/products?on_sale=1

Ordenar por preço promocional:

GET https://api.webzy.com.br/api/v1/products?sort_by=promotional_price&sort_dir=asc
Imóveis
GET /imoveis/options Valores aceitos para campos dropdown (ver Opções)
GET /imoveis Listar imóveis
GET /imoveis/{id} Detalhe de um imóvel
POST /imoveis Criar imóvel (requer permissão CRUD)
PUT /imoveis/{id} Atualizar imóvel (requer permissão CRUD)
DELETE /imoveis/{id} Excluir imóvel (requer permissão CRUD)

Filtros de listagem:

statusdraft, published, sold, rented
typevenda, aluguel, temporada
property_typeTipo de propriedade (casa, apartamento, etc.)
cityFiltro por cidade (busca parcial)
featuredtrue ou false
price_min / price_maxFaixa de preço (compara com price)
on_sale1 retorna apenas imóveis em promoção (promotional_price ativo)
bedrooms_minQuartos mínimos
category_idFiltrar por categoria

Exemplo - criar imóvel:

POST https://api.webzy.com.br/api/v1/imoveis
Content-Type: application/json
Authorization: Bearer SEU_TOKEN

{
  "title": "Apartamento 3 quartos - Centro",
  "type": "venda",
  "property_type": "apartamento",
  "status": "published",
  "price": 450000,
  "promotional_price": 399000,    // opcional; deve ser menor que price
  "bedrooms": 3,
  "bathrooms": 2,
  "area_total": 120.5,
  "features": ["piscina", "churrasqueira", "elevador"],
  "city": "São Paulo",
  "state": "SP",
  "category_ids": [1, 5]
}
// Campos dropdown (type, property_type, features) aceitam apenas
// valores retornados pelo endpoint GET /imoveis/options
Veículos
GET/vehicles/optionsValores aceitos para campos dropdown (ver Opções)
GET/vehiclesListar veículos
GET/vehicles/{id}Detalhe
POST/vehiclesCriar (CRUD)
PUT/vehicles/{id}Atualizar (CRUD)
DELETE/vehicles/{id}Excluir (CRUD)

Filtros de listagem:

statusdraft, published, sold
conditionnovo, usado
brandMarca (ex: Toyota, Honda)
vehicle_typeTipo (carro, moto, caminhão, etc.)
fuel_typeCombustível (flex, gasolina, diesel, elétrico)
transmissionCâmbio (manual, automático)
featuredtrue ou false
price_min / price_maxFaixa de preço (compara com price)
on_sale1 retorna apenas veículos em promoção (promotional_price ativo)
year_min / year_maxFaixa de ano
category_idFiltrar por categoria

Exemplo - criar veículo:

POST https://api.webzy.com.br/api/v1/vehicles
Content-Type: application/json

{
  "title": "Honda Civic EXL 2024",
  "status": "published",
  "price": 145000,
  "promotional_price": 129900,   // opcional; deve ser menor que price
  "condition": "usado",
  "brand": "honda",
  "vehicle_type": "carro",
  "model": "Civic",
  "year_manufacture": 2024,
  "year_model": 2024,
  "mileage": 15000,
  "fuel_type": "flex",
  "transmission": "automatico",
  "color": "branco",
  "features": ["ar_condicionado", "airbag", "camera_re"],
  "category_ids": [3]
}
// Campos dropdown (brand, vehicle_type, fuel_type, transmission,
// color, condition, features) aceitam apenas valores (keys)
// retornados pelo endpoint GET /vehicles/options
Produtos
GET/productsListar produtos
GET/products/{id}Detalhe
POST/productsCriar (CRUD)
PUT/products/{id}Atualizar (CRUD)
DELETE/products/{id}Excluir (CRUD)

Filtros de listagem:

statusdraft, published, archived
stock_statusin_stock, out_of_stock, on_backorder
featuredtrue ou false
price_min / price_maxFaixa de preço (compara com price)
on_sale1 retorna apenas produtos em promoção (promotional_price ativo)
skuFiltrar por SKU exato
category_idFiltrar por categoria

Exemplo - criar produto:

POST https://api.webzy.com.br/api/v1/products
Content-Type: application/json

{
  "title": "Camiseta Polo Premium",
  "status": "published",
  "price": 129.90,
  "promotional_price": 89.90,    // opcional; deve ser menor que price
  "sku": "POLO-001",
  "stock": 50,
  "stock_status": "in_stock",
  "summary": "Camiseta polo em algodão premium",
  "category_ids": [2, 7]
}
Blog / Notícias
GET/blog-postsListar posts
GET/blog-posts/{id}Detalhe
POST/blog-postsCriar (CRUD)
PUT/blog-posts/{id}Atualizar (CRUD)
DELETE/blog-posts/{id}Excluir (CRUD)

Filtros de listagem:

statusdraft, published, archived
featuredtrue ou false
category_idFiltrar por categoria

Exemplo - criar post:

POST https://api.webzy.com.br/api/v1/blog-posts
Content-Type: application/json

{
  "title": "Como escolher o melhor imóvel",
  "status": "published",
  "excerpt": "Dicas essenciais para sua compra",
  "content": "<p>Conteúdo HTML do post...</p>",
  "category_ids": [4]
}
Categorias Somente leitura
GET/categoriesListar categorias
GET/categories/{id}Detalhe (inclui subcategorias)

Filtros:

node_typeTipo: blog, product, imovel, vehicle, etc.
roots_onlytrue para retornar só categorias raiz (sem parent)
with_childrentrue para incluir subcategorias
# Categorias raiz de produtos com subcategorias
GET https://api.webzy.com.br/api/v1/categories?node_type=product&roots_only=true&with_children=true
Outros Endpoints Somente leitura
FAQ
GET/faqListar — filtros: status, category_id, search
GET/faq/{id}Detalhe
Portfólio
GET/portfolioListar — filtros: status, featured, category_id, search
GET/portfolio/{id}Detalhe
Equipe
GET/teamListar — filtros: status, department, search
GET/team/{id}Detalhe
Depoimentos
GET/testimonialsListar — filtros: status, featured, rating_min, search
GET/testimonials/{id}Detalhe
Newsletter
GET/newsletterListar inscritos — filtros: status, source, search
POST/newsletter/subscribeInscrever e-mail
POST https://api.webzy.com.br/api/v1/newsletter/subscribe
Content-Type: application/json

{
  "email": "cliente@email.com",
  "name": "João Silva"
}
Galeria de Imagens CRUD

Os 4 models CRUD (imóveis, veículos, produtos, blog) possuem endpoints de galeria de imagens. Requer permissão CRUD.

Substitua {model} por: imoveis, vehicles, products ou blog-posts

GET/{model}/{id}/imagesListar imagens da entidade
POST/{model}/{id}/imagesUpload de imagens (multipart/form-data). Aceita ?mode=replace para substituir a galeria.
POST/{model}/{id}/images/{imageId}/coverDefinir imagem como capa
POST/{model}/{id}/images/reorderReordenar imagens
PUT/{model}/{id}/images/{imageId}Atualizar alt/caption
DELETE/{model}/{id}/images/{imageId}Excluir uma imagem
DELETE/{model}/{id}/imagesExcluir todas as imagens da entidade
Upload de Imagens

Envie via multipart/form-data. Formatos aceitos: jpg, jpeg, png, gif, webp, svg.

# Upload de imagens para um imóvel
POST https://api.webzy.com.br/api/v1/imoveis/1/images
Content-Type: multipart/form-data
Authorization: Bearer SEU_TOKEN

# Body (form-data):
files[]: (arquivo binário - foto1.jpg)
files[]: (arquivo binário - foto2.jpg)

Exemplos em código:

PHP (cURL)

$ch = curl_init('https://api.webzy.com.br/api/v1/imoveis/1/images');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer TOKEN']);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
    'files[0]' => new CURLFile('/caminho/foto.jpg'),
    'files[1]' => new CURLFile('/caminho/foto2.jpg'),
]);

Python (requests)

import requests
files = [
    ('files[]', open('foto.jpg', 'rb')),
    ('files[]', open('foto2.jpg', 'rb')),
]
r = requests.post('https://api.webzy.com.br/api/v1/imoveis/1/images',
    headers={'Authorization': 'Bearer TOKEN'},
    files=files)

JavaScript (fetch)

const form = new FormData();
form.append('files[]', fileInput1);
form.append('files[]', fileInput2);
fetch('https://api.webzy.com.br/api/v1/imoveis/1/images', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer TOKEN' },
    body: form
});

Resposta do upload:

{
  "success": true,
  "message": "2 image(s) uploaded successfully",
  "data": [
    {
      "id": 42,
      "filename": "foto_1707040123_abc123.jpg",
      "original_name": "foto.jpg",
      "is_cover": true,
      "order": 0,
      "mime_type": "image/jpeg",
      "size": 245678,
      "width": 2000,
      "height": 1500,
      "urls": {
        "original": "https://...",
        "thumb": "https://..._thumb.jpg",
        "small": "https://..._small.jpg",
        "medium": "https://..._medium.jpg",
        "large": "https://..._large.jpg"
      }
    }
  ]
}

Definir imagem capa
POST https://api.webzy.com.br/api/v1/imoveis/1/images/42/cover
Authorization: Bearer SEU_TOKEN
Reordenar imagens
POST https://api.webzy.com.br/api/v1/imoveis/1/images/reorder
Content-Type: application/json
Authorization: Bearer SEU_TOKEN

{
  "ids": [5, 3, 1, 4]  // nova ordem desejada
}
Atualizar alt/caption
PUT https://api.webzy.com.br/api/v1/imoveis/1/images/42
Content-Type: application/json
Authorization: Bearer SEU_TOKEN

{
  "alt": "Vista da sala de estar",
  "caption": "Ampla sala com piso em porcelanato"
}
Excluir uma imagem
DELETE https://api.webzy.com.br/api/v1/imoveis/1/images/42
Authorization: Bearer SEU_TOKEN
Excluir todas as imagens

Remove todas as imagens da entidade (originais e variantes) do storage e do banco. Útil para "zerar" a galeria antes de outra operação.

DELETE https://api.webzy.com.br/api/v1/imoveis/1/images
Authorization: Bearer SEU_TOKEN

Substituir toda a galeria (mode=replace)

Fluxo típico de integrações do tipo gateway: o sistema externo re-envia todas as imagens do cadastro a cada mudança. Sem esse parâmetro, cada upload seria acumulado e as fotos iriam duplicar. Com mode=replace, o Webzy sobe as imagens novas primeiro e só então remove as antigas — se qualquer upload falhar, o rollback é automático e a galeria anterior permanece intacta.

# Substitui toda a galeria pela lista enviada
POST https://api.webzy.com.br/api/v1/imoveis/1/images?mode=replace
Content-Type: multipart/form-data
Authorization: Bearer SEU_TOKEN

# Body (form-data):
files[]: (foto1.jpg)
files[]: (foto2.jpg)
files[]: (foto3.jpg)

# Resposta:
# {
#   "success": true,
#   "message": "Gallery replaced with 3 image(s)",
#   "data": [ ... ]
# }
Comportamento automático:
  • Em modo append (padrão) as imagens são adicionadas à galeria existente.
  • Em modo replace o upload é atômico do ponto de vista do cliente — ou toda a galeria é trocada, ou nada muda. Não é possível ficar com uma galeria vazia por falha parcial.
  • A primeira imagem enviada é definida como capa automaticamente (quando a entidade ainda não tem capa).
  • A imagem capa recebe variantes em todos os tamanhos (thumb, small, medium, large).
  • Imagens não-capa recebem apenas thumbnail (economia de armazenamento).
  • Ao excluir a capa individualmente, a próxima imagem é promovida automaticamente.
  • Funciona com armazenamento local e MinIO/S3 — transparente para o consumidor da API.
Campos com Opções (Dropdowns)

Alguns campos de Veículos e Imóveis aceitam apenas valores pré-definidos. Para saber quais valores são aceitos, consulte o endpoint /options de cada entidade:

GET https://api.webzy.com.br/api/v1/vehicles/options
GET https://api.webzy.com.br/api/v1/imoveis/options

Exemplo de resposta (veículos):

{
  "success": true,
  "data": {
    "condition": { "novo": "Novo", "usado": "Usado" },
    "vehicle_type": { "carro": "Carro", "moto": "Moto", ... },
    "brand": { "volkswagen": "Volkswagen", "fiat": "Fiat", ... },
    "fuel_type": { "flex": "Flex", "gasolina": "Gasolina", ... },
    "transmission": { "manual": "Manual", "automatico": "Automático", ... },
    "color": { "branco": "Branco", "preto": "Preto", ... },
    "features": { "ar_condicionado": "Ar Condicionado", ... },
    "status": { "draft": "Rascunho", "published": "Publicado", ... }
  }
}
Importante: Ao criar ou atualizar, envie sempre a chave (key) do objeto, nunca o label. Por exemplo, para marca "Volkswagen" envie "brand": "volkswagen", e para features envie "features": ["ar_condicionado", "airbag"].

Campos dropdown por entidade:

EntidadeCampos
Veículos condition, vehicle_type, brand, fuel_type, transmission, color, features
Imóveis type, property_type, features

As opções disponíveis podem variar por tenant. O administrador pode adicionar opções customizadas nas configurações do módulo no painel. Valores enviados fora das opções disponíveis serão rejeitados com erro 422.

Limites de Cadastro

A API respeita os limites de cadastro configurados no painel (Configurações > Limites). Ao tentar criar um registro quando o limite foi atingido, a API retorna:

# HTTP 403
{
  "success": false,
  "message": "Registration limit reached for this module"
}

Módulos com limite:

MóduloEndpointLimite padrão
ImóveisPOST /imoveis500
VeículosPOST /vehicles500
ProdutosPOST /products500
BlogPOST /blog-posts100

Limite 0 = ilimitado. Os limites podem ser ajustados pelo administrador no painel.

Códigos de Erro
CódigoSignificadoQuando ocorre
401Não autenticadoToken ausente, inválido, inativo ou expirado
403Acesso negadoToken sem permissão para este recurso/ação, ou limite de cadastros atingido
404Não encontradoRecurso ou endpoint não existe
409ConflitoE-mail já inscrito na newsletter
422Validação falhouDados enviados com erros (campos obrigatórios, formato inválido)
429Muitas requisiçõesRate limit excedido — aguarde Retry-After segundos
Vinculando Categorias

Para vincular registros a categorias ao criar ou atualizar, envie o campo category_ids com um array de IDs:

# No create ou update de qualquer CRUD model
{
  "title": "Meu produto",
  "category_ids": [1, 5, 12]  // substitui todas as categorias
}
  • Enviar category_ids substitui todas as categorias do registro (sync).
  • Enviar [] (array vazio) remove todas as categorias.
  • Não enviar o campo mantém as categorias atuais (só no update).
  • Os IDs devem ser de categorias que pertencem ao mesmo tenant do token.