Pular para o conteúdo principal

API REST

Versão: 1.0
Última atualização: 2025
Base URL (produção): https://ljvelasearomas.com.br
Base URL (local): http://localhost:3000


Sumário​

  1. Visão Geral
  2. Autenticação
  3. Convenções de Resposta
  4. Auth — Conta e Sessão
  5. Produtos (público)
  6. Categorias (público)
  7. Pedidos (cliente autenticado)
  8. Pagamentos
  9. Frete
  10. Cupons
  11. Usuário — Área Logada
  12. Newsletter
  13. Contato
  14. Admin
  15. API v1 — Integração Programática
  16. Webhook Inbound — Estoque

1. Visão Geral​

A API da LJ Velas & Aromas é uma API REST construída com Next.js App Router. Todas as rotas retornam JSON e aceitam corpos no formato application/json, salvo quando indicado multipart.

Ambiente e Base URL​

AmbienteBase URL
Produçãohttps://ljvelasearomas.com.br
Desenvolvimentohttp://localhost:3000

Todos os endpoints descritos neste documento são prefixados com /api/ (ex.: POST /api/auth/login).

Formato das Respostas​

Todas as respostas usam o Content-Type application/json; charset=utf-8.

Paginação Padrão​

Endpoints que retornam listas paginadas incluem o objeto pagination na resposta:

{
"data": [ ... ],
"pagination": {
"page": 1,
"limit": 20,
"total": 143,
"totalPages": 8
}
}

Os parâmetros de controle são enviados via query string:

ParâmetroTipoPadrãoMáximoDescrição
pageinteger1—Número da página
limitinteger20100Itens por página

Códigos de Status HTTP Utilizados​

CódigoSignificado
200Sucesso
201Recurso criado com sucesso
204Sucesso sem corpo de resposta
400Requisição inválida (corpo malformado, validação)
401Não autenticado (sem credenciais ou token inválido)
403Acesso negado (autenticado, mas sem permissão)
404Recurso não encontrado
409Conflito (ex.: slug ou e-mail já existente)
422Entidade não processável (validação semântica)
429Muitas requisições (rate limit atingido)
500Erro interno do servidor

2. Autenticação​

A API oferece três mecanismos de autenticação dependendo do contexto.

Utilizado pelas rotas da loja (/api/auth/, /api/orders/, /api/user/, /api/payments/) e pelo painel Admin (/api/admin/).

Após um POST /api/auth/login bem-sucedido, um cookie HttpOnly chamado token é definido automaticamente pelo servidor. O browser envia este cookie em todas as requisições subsequentes para o mesmo domínio.

Cookie: token=<JWT>

Propriedades:
HttpOnly: true (inacessível por JS)
Secure: true (somente em produção)
SameSite: Lax
MaxAge: 604800 (7 dias)
Domain: .ljvelasearomas.com.br (produção)

O token JWT contém: { userId, email, role }.

Nota: A resposta do POST /api/auth/login também devolve o token JWT no campo token do corpo JSON. Clientes SPA podem armazená-lo manualmente se necessário; clientes web browser utilizam o cookie automaticamente.

2.2 API Key Bearer (API v1 + Webhook Inbound)​

Utilizado pelos endpoints /api/v1/ e /api/webhooks/stock.

Authorization: Bearer lvk_live_<token>

A chave é gerada pelo painel Admin (/api/admin/api-keys) e cada chave possui escopos que limitam as operações permitidas. O hash SHA-256 da chave é armazenado no banco; o valor bruto é exibido uma única vez na criação.

2.3 Rate Limiting em Login​

O endpoint POST /api/auth/login aplica rate limiting por IP para proteção contra ataques de força bruta:

LimiteJanelaHeader de Resposta
10 tentativas15 minutosRetry-After, X-RateLimit-Limit, X-RateLimit-Remaining

Ao exceder o limite, a resposta será 429 Too Many Requests com a mensagem "Muitas tentativas. Tente novamente em X minutos.".


3. Convenções de Resposta​

Resposta de Sucesso​

// Recurso único
{
"id": "clx1234abcd",
"name": "Vela de Lavanda 200g",
"price": 39.90
}

// Coleção paginada
{
"data": [ { ... }, { ... } ],
"pagination": {
"page": 1,
"limit": 20,
"total": 48,
"totalPages": 3
}
}

Resposta de Erro​

Todos os erros seguem o formato:

{
"error": "Descrição legível do erro"
}

// Erro de validação com detalhes
{
"error": "Payload inválido",
"details": {
"fieldErrors": { "email": ["Email inválido"] },
"formErrors": []
}
}

4. Auth — Conta e Sessão​

POST /api/auth/register​

Cria uma nova conta de cliente.

Autenticação: Nenhuma

Body:

CampoTipoObrigatórioDescrição
namestring✅Nome completo
emailstring✅E-mail válido
passwordstring✅Senha do usuário

Exemplo de request:

{
"name": "Maria Silva",
"email": "maria@email.com",
"password": "MinhaSenh@123"
}

Resposta 201 Created:

{
"user": {
"id": "clx1a2b3c4d",
"name": "Maria Silva",
"email": "maria@email.com",
"role": "CUSTOMER"
}
}

Erros:

CódigoMotivo
400Campos inválidos ou ausentes
409E-mail já cadastrado
500Erro interno

Exemplo cURL:

curl -X POST https://ljvelasearomas.com.br/api/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"Maria Silva","email":"maria@email.com","password":"MinhaSenh@123"}'

POST /api/auth/login​

Autentica o usuário. Define o cookie token (JWT) e retorna os dados do usuário.

Autenticação: Nenhuma (rate limited: 10 req / 15 min por IP)

Body:

CampoTipoObrigatórioDescrição
emailstring✅E-mail
passwordstring✅Senha

Resposta 200 OK:

{
"user": {
"id": "clx1a2b3c4d",
"name": "Maria Silva",
"email": "maria@email.com",
"phone": null,
"role": "CUSTOMER"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

O cookie HttpOnly token é definido automaticamente na resposta.

Headers de resposta em rate limit (429):

HeaderValor
Retry-AfterSegundos até liberar
X-RateLimit-Limit10
X-RateLimit-Remaining0

Erros:

CódigoMotivo
400Campos inválidos
401Email ou senha inválidos
403Conta suspensa
429Rate limit atingido
500Erro interno

POST /api/auth/logout​

Encerra a sessão limpando o cookie token.

Autenticação: Cookie JWT (opcional — o cookie é removido independente de ser válido)

Body: Nenhum

Resposta 200 OK:

{
"message": "Logout realizado com sucesso"
}

GET /api/auth/me​

Retorna os dados do usuário autenticado pela sessão atual.

Autenticação: Cookie JWT ✅

Resposta 200 OK:

{
"id": "clx1a2b3c4d",
"name": "Maria Silva",
"email": "maria@email.com",
"phone": null,
"role": "CUSTOMER",
"createdAt": "2024-03-15T10:30:00.000Z"
}

Erros:

CódigoMotivo
401Não autenticado

PATCH /api/auth/me/password​

Altera a senha do usuário autenticado.

Autenticação: Cookie JWT ✅

Body:

CampoTipoObrigatórioDescrição
currentPasswordstring✅Senha atual
newPasswordstring✅Nova senha

Resposta 200 OK:

{
"message": "Senha alterada com sucesso"
}

Erros:

CódigoMotivo
400Campos ausentes ou nova senha inválida
401Não autenticado ou senha atual incorreta

5. Produtos (público)​

GET /api/products​

Lista produtos ativos com filtros, ordenação e paginação.

Autenticação: Nenhuma

Query Params:

ParâmetroTipoPadrãoDescrição
pageinteger1Número da página
limitinteger20Itens por página (máx. 100)
searchstring—Busca por nome ou descrição
categorystring—Slug da categoria
featuredboolean—Somente produtos em destaque (true)
sortstringnewestprice_asc, price_desc, newest, popular
minPricenumber—Preço mínimo (R$)
maxPricenumber—Preço máximo (R$)
inStockboolean—Somente produtos com estoque (true)

Resposta 200 OK:

{
"data": [
{
"id": "clx1a2b3c4d",
"name": "Vela de Lavanda 200g",
"slug": "vela-lavanda-200g",
"price": 39.90,
"comparePrice": 49.90,
"stock": 25,
"featured": true,
"category": {
"id": "clxcat001",
"name": "Velas Aromáticas",
"slug": "velas-aromaticas"
},
"images": [
{
"url": "https://cdn.ljvelasearomas.com.br/vela-lavanda-200g-01.jpg",
"alt": "Vela de Lavanda 200g",
"isPrimary": true
}
],
"reviewCount": 12,
"averageRating": 4.8
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 48,
"totalPages": 3
}
}

Exemplo cURL:

curl "https://ljvelasearomas.com.br/api/products?category=velas-aromaticas&sort=price_asc&inStock=true&page=1&limit=12"

GET /api/products/[slug]​

Retorna os detalhes completos de um produto pelo slug.

Autenticação: Nenhuma

Path Params:

ParâmetroTipoDescrição
slugstringSlug do produto

Resposta 200 OK:

{
"id": "clx1a2b3c4d",
"name": "Vela de Lavanda 200g",
"slug": "vela-lavanda-200g",
"description": "Vela artesanal com aroma de lavanda...",
"price": 39.90,
"comparePrice": 49.90,
"stock": 25,
"sku": "VEL-LAV-200",
"weight": 0.3,
"featured": true,
"active": true,
"category": {
"id": "clxcat001",
"name": "Velas Aromáticas",
"slug": "velas-aromaticas"
},
"images": [
{
"id": "clximg001",
"url": "https://cdn.ljvelasearomas.com.br/vela-lavanda-200g-01.jpg",
"alt": "Vela de Lavanda 200g",
"isPrimary": true,
"order": 0
}
],
"variants": [
{
"id": "clxvar001",
"price": 39.90,
"stock": 10,
"sku": "VEL-LAV-200-ROXO",
"values": [
{ "variantType": "Cor", "value": "Roxo" }
]
}
],
"reviews": [
{
"id": "clxrev001",
"rating": 5,
"title": "Produto incrível!",
"body": "Aroma suave e duradouro.",
"author": "Maria S.",
"createdAt": "2024-04-10T08:00:00.000Z"
}
],
"reviewCount": 12,
"averageRating": 4.8,
"createdAt": "2024-01-20T12:00:00.000Z"
}

Erros:

CódigoMotivo
404Produto não encontrado ou inativo

GET /api/products/search​

Busca produtos com highlight do termo pesquisado no nome e descrição.

Autenticação: Nenhuma

Query Params:

ParâmetroTipoObrigatórioDescrição
qstring✅Termo de busca
pageinteger—Página (padrão 1)
limitinteger—Limite (padrão 20)

Resposta 200 OK:

{
"data": [
{
"id": "clx1a2b3c4d",
"name": "Vela de <mark>Lavanda</mark> 200g",
"slug": "vela-lavanda-200g",
"price": 39.90,
"highlight": "aroma de <mark>lavanda</mark> pura..."
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 3,
"totalPages": 1
},
"query": "lavanda"
}

GET /api/products/[slug]/reviews​

Lista as avaliações aprovadas de um produto.

Autenticação: Nenhuma

Resposta 200 OK:

{
"data": [
{
"id": "clxrev001",
"rating": 5,
"title": "Produto incrível!",
"body": "Aroma suave e duradouro. Vou comprar novamente.",
"author": "Maria S.",
"createdAt": "2024-04-10T08:00:00.000Z"
}
],
"summary": {
"average": 4.8,
"total": 12,
"distribution": {
"5": 9, "4": 2, "3": 1, "2": 0, "1": 0
}
}
}

POST /api/products/[slug]/reviews​

Envia uma avaliação para um produto. Requer autenticação.

Autenticação: Cookie JWT ✅ (role: CUSTOMER)

Body:

CampoTipoObrigatórioDescrição
ratinginteger✅Nota de 1 a 5
titlestring—Título da avaliação
bodystring✅Texto da avaliação

Nota: A review é criada com status: pending e precisa ser aprovada por um administrador antes de aparecer publicamente.

Resposta 201 Created:

{
"id": "clxrev099",
"rating": 5,
"title": "Adorei!",
"body": "Entregou mais do que esperava.",
"status": "pending",
"createdAt": "2025-01-10T15:30:00.000Z"
}

Erros:

CódigoMotivo
400Campos inválidos ou rating fora do intervalo
401Não autenticado
404Produto não encontrado

6. Categorias (público)​

GET /api/categories​

Lista todas as categorias ativas com a contagem de produtos.

Autenticação: Nenhuma

Resposta 200 OK:

[
{
"id": "clxcat001",
"name": "Velas Aromáticas",
"slug": "velas-aromaticas",
"description": "Velas artesanais com fragrâncias naturais",
"image": "https://cdn.ljvelasearomas.com.br/cat-velas.jpg",
"active": true,
"productCount": 24
},
{
"id": "clxcat002",
"name": "Difusores",
"slug": "difusores",
"description": "Difusores de ambiente e aromatizadores",
"image": "https://cdn.ljvelasearomas.com.br/cat-difusores.jpg",
"active": true,
"productCount": 11
}
]

7. Pedidos (cliente autenticado)​

POST /api/orders​

Cria um novo pedido. Os itens podem ser enviados pelo cliente; o servidor sempre re-valida os preços contra o banco de dados, ignorando os preços enviados. O estoque é decrementado atomicamente dentro de uma transação.

Autenticação: Cookie JWT ✅ (role: CUSTOMER)

Body:

CampoTipoObrigatórioDescrição
addressIdstring✅ID do endereço de entrega (deve pertencer ao usuário)
cartItemsarray—Itens do pedido. Se omitido, usa o carrinho salvo no BD
cartItems[].productIdstring✅ID do produto
cartItems[].quantityinteger✅Quantidade (mínimo 1)
cartItems[].pricenumber✅Preço sugerido (ignorado — servidor usa preço do banco)
notesstring—Observações do pedido
couponIdstring—ID do cupom de desconto (re-validado no servidor)

⚠️ Re-validação de preço: O campo price enviado em cada item é ignorado pelo servidor. O preço final é sempre buscado no banco de dados para prevenir adulteração. Frete grátis é aplicado automaticamente para pedidos com subtotal ≥ R$ 150,00.

Exemplo de request:

{
"addressId": "clxaddr001",
"cartItems": [
{ "productId": "clx1a2b3c4d", "quantity": 2, "price": 39.90 },
{ "productId": "clx5e6f7g8h", "quantity": 1, "price": 89.90 }
],
"notes": "Presente — favor embalar para presente.",
"couponId": "clxcoupon01"
}

Resposta 201 Created:

{
"id": "clxord001",
"orderNumber": "VEL-20250110-0042",
"userId": "clx1a2b3c4d",
"addressId": "clxaddr001",
"subtotal": 169.70,
"shipping": 0.00,
"discount": 16.97,
"total": 152.73,
"status": "PENDING",
"notes": "Presente — favor embalar para presente.",
"items": [
{
"id": "clxitem001",
"productId": "clx1a2b3c4d",
"quantity": 2,
"price": 39.90,
"total": 79.80,
"productNameSnapshot": "Vela de Lavanda 200g"
}
],
"address": {
"street": "Rua das Flores",
"number": "123",
"city": "São Paulo",
"state": "SP",
"zipCode": "01310100"
},
"createdAt": "2025-01-10T15:30:00.000Z"
}

Erros:

CódigoMotivo
400Carrinho vazio, estoque insuficiente, produto inativo
401Não autenticado
404Endereço não encontrado ou não pertence ao usuário
500Erro interno

GET /api/orders​

Lista todos os pedidos do cliente autenticado, do mais recente ao mais antigo.

Autenticação: Cookie JWT ✅

Resposta 200 OK:

[
{
"id": "clxord001",
"orderNumber": "VEL-20250110-0042",
"status": "PROCESSING",
"total": 152.73,
"createdAt": "2025-01-10T15:30:00.000Z",
"items": [
{
"productId": "clx1a2b3c4d",
"quantity": 2,
"price": 39.90,
"product": {
"name": "Vela de Lavanda 200g",
"images": [{ "url": "...", "isPrimary": true }]
}
}
],
"payment": { "method": "PIX", "status": "PAID" },
"address": { "street": "Rua das Flores", "city": "São Paulo", "state": "SP" }
}
]

GET /api/orders/[id]​

Retorna o detalhe de um pedido específico. Verifica se o pedido pertence ao usuário autenticado.

Autenticação: Cookie JWT ✅

Path Params:

ParâmetroTipoDescrição
idstringID do pedido

Resposta 200 OK: Mesmo formato da listagem, com dados completos.

Erros:

CódigoMotivo
401Não autenticado
404Pedido não encontrado ou não pertence ao usuário

8. Pagamentos​

POST /api/payments/pix​

Gera um QR Code PIX via MercadoPago para o pagamento de um pedido. Implementa idempotência: se um QR válido (não expirado) já existir para o pedido, ele é retornado sem criar uma nova transação.

Autenticação: Cookie JWT ✅

Body:

CampoTipoObrigatórioDescrição
orderIdstring✅ID do pedido

Resposta 200 OK:

{
"qrCode": "iVBORw0KGgoAAAANSUhEUgAA...",
"qrCodeText": "00020126580014BR.GOV.BCB.PIX0136...",
"expiresAt": "2025-01-10T16:00:00.000Z",
"amount": 152.73
}
CampoDescrição
qrCodeImagem do QR Code em Base64 (PNG)
qrCodeTextCódigo Copia e Cola do PIX (string longa)
expiresAtExpiração do QR (30 minutos a partir da criação)
amountValor total do pedido

Erros:

CódigoMotivo
400Pedido já pago
401Não autenticado
404Pedido não encontrado
500Erro na integração com MercadoPago

POST /api/payments/mercadopago/card​

Processa pagamento com cartão de crédito via MP Brick (tokenização client-side).

Autenticação: Cookie JWT ✅

Body:

CampoTipoObrigatórioDescrição
orderIdstring✅ID do pedido
tokenstring✅Token do cartão gerado pelo MP Brick
paymentMethodIdstring✅Método (ex.: visa, master)
installmentsinteger✅Número de parcelas
issuerIdstring✅ID do banco emissor

Resposta 200 OK:

{
"status": "approved",
"paymentId": "12345678901",
"orderId": "clxord001",
"installments": 3,
"lastFourDigits": "1234"
}

Erros:

CódigoMotivo
400Token inválido, pedido já pago
401Não autenticado
404Pedido não encontrado
422Pagamento rejeitado pela operadora
500Erro na integração com MercadoPago

POST /api/payments/mercadopago/webhook​

Recebe notificações automáticas do MercadoPago (IPN/Webhooks). Valida a assinatura HMAC antes de processar.

Autenticação: Assinatura HMAC (header x-signature verificado pelo servidor)

Body: Payload padrão do MercadoPago (não manipulado diretamente pelo cliente).

Resposta 200 OK: { "received": true }

Nota: Este endpoint deve ser configurado no painel do MercadoPago como URL de notificação. O servidor verifica a assinatura HMAC em x-signature antes de processar qualquer evento.


POST /api/payments/stripe​

Cria um PaymentIntent no Stripe para iniciar o fluxo de pagamento.

Autenticação: Cookie JWT ✅

Body:

CampoTipoObrigatórioDescrição
orderIdstring✅ID do pedido

Resposta 200 OK:

{
"clientSecret": "pi_3Pq7vX2eZvKYlo2C0l3qfXWJ_secret_...",
"paymentIntentId": "pi_3Pq7vX2eZvKYlo2C0l3qfXWJ",
"amount": 15273,
"currency": "brl"
}

POST /api/payments/stripe/webhook​

Recebe eventos do Stripe (ex.: payment_intent.succeeded). Verifica a assinatura via stripe-signature.

Autenticação: Assinatura Stripe (header stripe-signature)

Body: Raw body do Stripe (não deve passar por JSON parse intermediário).

Resposta 200 OK: { "received": true }


Fluxo Completo de Pagamento​

1. Cliente cria pedido POST /api/orders → orderId
2a. PIX:
Cliente solicita QR POST /api/payments/pix → qrCode + qrCodeText
Cliente paga via app bancário
MercadoPago notifica POST /api/payments/mercadopago/webhook
Servidor atualiza order.status → PAID
2b. Cartão (MercadoPago Brick):
MP Brick tokeniza o cartão (client-side) → token
Cliente envia token POST /api/payments/mercadopago/card → aprovado/rejeitado
2c. Stripe:
Cliente solicita PaymentIntent POST /api/payments/stripe → clientSecret
Stripe Elements confirma (client-side)
Stripe notifica POST /api/payments/stripe/webhook
Servidor atualiza order.status → PAID

9. Frete​

GET /api/shipping/calculate​

Calcula opções de frete para um CEP e subtotal. Tenta cotação em tempo real nas transportadoras integradas (Melhor Envio / Correios / Superfrete); em caso de falha, aplica tarifas estáticas configuradas no admin.

Autenticação: Nenhuma

Query Params:

ParâmetroTipoObrigatórioDescrição
cepstring✅CEP de destino (8 dígitos, com ou sem -)
subtotalnumber✅Subtotal do pedido em R$
weightnumber—Peso total em kg (padrão: 0.3)

Resposta 200 OK — fonte API:

{
"cep": "01310100",
"state": "SP",
"city": "São Paulo",
"options": [
{
"id": "melhor-envio-sedex",
"name": "SEDEX",
"price": 18.50,
"estimatedDays": 2,
"free": false
},
{
"id": "melhor-envio-pac",
"name": "PAC",
"price": 0,
"estimatedDays": 7,
"free": true
}
],
"qualifiesForFree": true,
"freeShippingThreshold": 150.00,
"remaining": 0,
"source": "api"
}

Resposta 200 OK — fonte tarifas estáticas:

{
"cep": "20040020",
"state": "RJ",
"city": "Rio de Janeiro",
"options": [
{
"id": "static-rj-001",
"name": "Entrega Padrão",
"price": 15.90,
"estimatedDays": 5,
"free": false
}
],
"qualifiesForFree": false,
"freeShippingThreshold": 150.00,
"remaining": 30.00,
"source": "static"
}
CampoDescrição
options[].freetrue se o frete for grátis (subtotal ≥ R$ 150)
qualifiesForFreeSe o subtotal já atinge o mínimo para frete grátis
remainingQuanto falta para obter frete grátis (R$)
source"api" (transportadora em tempo real) ou "static"

Erros:

CódigoMotivo
400CEP com formato inválido
422CEP não encontrado na base ViaCEP

Exemplo cURL:

curl "https://ljvelasearomas.com.br/api/shipping/calculate?cep=01310-100&subtotal=89.90"

10. Cupons​

POST /api/coupons/validate​

Valida um código de cupom antes de aplicá-lo ao pedido. Verifica: existência, status ativo, data de expiração, limite de usos e valor mínimo de pedido.

Autenticação: Nenhuma

Body:

CampoTipoObrigatórioDescrição
codestring✅Código do cupom (case-insensitive)
subtotalnumber✅Subtotal do pedido em R$

Exemplo de request:

{
"code": "LAVANDA10",
"subtotal": 150.00
}

Resposta 200 OK — cupom válido:

{
"valid": true,
"coupon": {
"id": "clxcoupon01",
"code": "LAVANDA10",
"type": "PERCENT",
"value": 10,
"discount": 15.00
}
}

Resposta 200 OK — cupom inválido:

{
"valid": false,
"error": "Cupom expirado"
}
CampoDescrição
coupon.typePERCENT (percentual) ou FIXED (valor fixo)
coupon.valuePercentual (ex.: 10 = 10%) ou valor em R$
coupon.discountValor do desconto calculado em R$ para o subtotal

Erros possíveis no campo error:

MensagemMotivo
Cupom não encontradoCódigo inexistente
Cupom inativoCupom desativado pelo admin
Cupom expiradoData de expiração ultrapassada
Limite de usos atingidousedCount >= maxUses
Pedido abaixo do valor mínimoSubtotal < minOrderValue

11. Usuário — Área Logada​

Endereços​

GET /api/user/addresses​

Lista todos os endereços cadastrados pelo usuário.

Autenticação: Cookie JWT ✅

Resposta 200 OK:

[
{
"id": "clxaddr001",
"label": "Casa",
"street": "Rua das Flores",
"number": "123",
"complement": "Apto 4B",
"district": "Jardim Paulista",
"city": "São Paulo",
"state": "SP",
"zipCode": "01310100",
"isDefault": true
}
]

POST /api/user/addresses​

Cria um novo endereço.

Autenticação: Cookie JWT ✅

Body:

CampoTipoObrigatórioDescrição
labelstring✅Rótulo (ex.: "Casa", "Trabalho")
streetstring✅Logradouro
numberstring✅Número
complementstring—Complemento
districtstring✅Bairro
citystring✅Cidade
statestring✅UF (2 letras, ex.: SP)
zipCodestring✅CEP (somente números)

Resposta 201 Created: Objeto do endereço criado.


PATCH /api/user/addresses/[id]​

Atualiza um endereço existente. Todos os campos são opcionais.

Autenticação: Cookie JWT ✅

Resposta 200 OK: Objeto do endereço atualizado.

Erros:

CódigoMotivo
404Endereço não encontrado ou não pertence ao usuário

DELETE /api/user/addresses/[id]​

Remove um endereço.

Autenticação: Cookie JWT ✅

Resposta 200 OK: { "message": "Endereço removido" }


Lista de Favoritos (Wishlist)​

GET /api/user/wishlist​

Lista os produtos favoritados pelo usuário, incluindo dados do produto.

Autenticação: Cookie JWT ✅

Resposta 200 OK:

[
{
"id": "clxwish001",
"productId": "clx1a2b3c4d",
"addedAt": "2025-01-05T10:00:00.000Z",
"product": {
"id": "clx1a2b3c4d",
"name": "Vela de Lavanda 200g",
"slug": "vela-lavanda-200g",
"price": 39.90,
"stock": 25,
"images": [{ "url": "...", "isPrimary": true }]
}
}
]

POST /api/user/wishlist​

Adiciona um produto à lista de favoritos.

Autenticação: Cookie JWT ✅

Body:

CampoTipoObrigatórioDescrição
productIdstring✅ID do produto

Resposta 201 Created: Objeto do favorito criado.

Erros:

CódigoMotivo
404Produto não encontrado
409Produto já está na wishlist

DELETE /api/user/wishlist/[productId]​

Remove um produto da lista de favoritos.

Autenticação: Cookie JWT ✅

Resposta 200 OK: { "message": "Removido dos favoritos" }


Notificações​

GET /api/user/notifications​

Lista as notificações do usuário (ex.: atualização de status de pedido).

Autenticação: Cookie JWT ✅

Resposta 200 OK:

[
{
"id": "clxnotif001",
"type": "ORDER_STATUS",
"title": "Seu pedido foi enviado!",
"body": "Pedido #VEL-20250110-0042 saiu para entrega.",
"read": false,
"link": "/minha-conta/pedidos/clxord001",
"createdAt": "2025-01-11T09:00:00.000Z"
}
]

12. Newsletter​

POST /api/newsletter/subscribe​

Inscreve um e-mail na newsletter.

Autenticação: Nenhuma

Body:

CampoTipoObrigatórioDescrição
emailstring✅E-mail
namestring—Nome

Resposta 200 OK: { "message": "Inscrição realizada com sucesso" }

Erros:

CódigoMotivo
400E-mail inválido
409E-mail já inscrito

POST /api/newsletter/unsubscribe​

Cancela a inscrição de um e-mail na newsletter.

Autenticação: Nenhuma

Body:

CampoTipoObrigatórioDescrição
emailstring✅E-mail

Resposta 200 OK: { "message": "Inscrição cancelada" }


13. Contato​

POST /api/contact​

Envia uma mensagem de contato via formulário.

Autenticação: Nenhuma

Body:

CampoTipoObrigatórioDescrição
namestring✅Nome do remetente
emailstring✅E-mail para resposta
subjectstring✅Assunto da mensagem
messagestring✅Corpo da mensagem

Resposta 200 OK: { "message": "Mensagem enviada com sucesso" }

Erros:

CódigoMotivo
400Campos obrigatórios ausentes
429Rate limit (anti-spam)

14. Admin​

⚠️ Autenticação obrigatória em todos os endpoints /api/admin/

Todos os endpoints admin exigem Cookie JWT com role: ADMIN. Qualquer requisição sem sessão válida de administrador recebe 403 Forbidden com { "error": "Acesso negado" }.


14.1 Produtos (Admin)​

GET /api/admin/products​

Lista todos os produtos (incluindo inativos) com paginação.

Query Params:

ParâmetroTipoDescrição
pageintegerPágina (padrão: 1)
limitintegerItens/página (padrão: 20, máx: 100)
searchstringBusca por nome
categorystringFiltrar por slug de categoria
activebooleanFiltrar por status
featuredbooleanFiltrar produtos em destaque

Resposta 200 OK:

{
"data": [
{
"id": "clx1a2b3c4d",
"name": "Vela de Lavanda 200g",
"slug": "vela-lavanda-200g",
"price": 39.90,
"stock": 25,
"active": true,
"featured": false,
"category": { "name": "Velas Aromáticas", "slug": "velas-aromaticas" },
"images": [{ "url": "...", "isPrimary": true }],
"_count": { "orderItems": 87 },
"createdAt": "2024-01-20T12:00:00.000Z"
}
],
"pagination": { "page": 1, "limit": 20, "total": 53, "totalPages": 3 }
}

POST /api/admin/products​

Cria um novo produto. O slug é automaticamente verificado para unicidade (sufixo numérico adicionado se necessário).

Body:

CampoTipoObrigatórioDescrição
namestring✅Nome do produto (mín. 2 chars)
slugstring✅Slug URL-friendly (mín. 2 chars)
descriptionstring—Descrição
pricenumber✅Preço em R$ (positivo)
comparePricenumber—Preço "de" para exibir riscado
stockinteger✅Estoque inicial (≥ 0)
skustring—Código SKU
weightnumber—Peso em kg
categoryIdstring—ID da categoria
featuredboolean—Em destaque (padrão: false)
activeboolean—Ativo (padrão: true)
imagesarray—Ver estrutura abaixo
images[].urlstring✅URL da imagem
images[].altstring—Texto alternativo
images[].isPrimaryboolean—Imagem principal
images[].orderinteger—Ordem de exibição

Resposta 201 Created: Objeto completo do produto com imagens e categoria.

Erros:

CódigoMotivo
400Validação falhou
403Não é administrador
409Slug já existe (conflict raro)

GET /api/admin/products/[id]​

Retorna detalhes completos do produto incluindo variantes e imagens.

Resposta 200 OK: Objeto completo do produto.


PATCH /api/admin/products/[id]​

Atualiza campos de um produto. Todos os campos do schema são aceitos parcialmente.

Resposta 200 OK: Objeto do produto atualizado.


DELETE /api/admin/products/[id]​

Remove um produto permanentemente.

Resposta 200 OK: { "message": "Produto removido" }


POST /api/admin/products/bulk​

Executa operação em lote sobre múltiplos produtos.

Body:

CampoTipoObrigatórioDescrição
idsstring[]✅Array de IDs dos produtos
actionstring✅"delete", "activate" ou "deactivate"

Exemplo de request:

{
"ids": ["clx1a2b3c4d", "clx5e6f7g8h", "clx9i0j1k2l"],
"action": "deactivate"
}

Resposta 200 OK: { "updated": 3 } ou { "deleted": 3 }


POST /api/admin/products/[id]/clone​

Clona um produto. O novo slug é gerado automaticamente com sufixo (ex.: vela-lavanda-200g-2).

Resposta 201 Created: Objeto completo do produto clonado.


14.2 Variantes​

Tipos de Variante​

GET /api/admin/variant-types​

Lista todos os tipos de variante (ex.: Cor, Tamanho, Aroma).

Resposta 200 OK:

[
{ "id": "clxvt001", "name": "Cor", "slug": "cor", "order": 0 },
{ "id": "clxvt002", "name": "Tamanho", "slug": "tamanho", "order": 1 }
]

POST /api/admin/variant-types​

Cria um novo tipo de variante.

Body:

CampoTipoObrigatórioDescrição
namestring✅Nome do tipo
slugstring✅Slug único
orderinteger—Ordem de exibição

PATCH /api/admin/variant-types/[typeId]​

Atualiza um tipo de variante.


DELETE /api/admin/variant-types/[typeId]​

Remove um tipo de variante (e suas opções).


Opções de Variante​

GET /api/admin/variant-types/[typeId]/options​

Lista as opções de um tipo (ex.: Vermelho, Azul para o tipo Cor).

Resposta 200 OK:

[
{ "id": "clxvo001", "value": "Roxo Lavanda", "order": 0 },
{ "id": "clxvo002", "value": "Branco Natural", "order": 1 }
]

POST /api/admin/variant-types/[typeId]/options​

Cria uma nova opção para o tipo.

Body:

CampoTipoObrigatórioDescrição
valuestring✅Valor da opção
orderinteger—Ordem

PATCH /api/admin/variant-types/[typeId]/options/[optionId]​

Atualiza uma opção.


DELETE /api/admin/variant-types/[typeId]/options/[optionId]​

Remove uma opção.


Variantes do Produto​

GET /api/admin/products/[id]/variants​

Lista todas as variantes de um produto específico.

Resposta 200 OK:

[
{
"id": "clxvar001",
"price": 39.90,
"comparePrice": null,
"stock": 10,
"sku": "VEL-LAV-200-ROXO",
"values": [
{
"id": "clxvarval001",
"variantOptionId": "clxvo001",
"variantOption": { "value": "Roxo Lavanda", "variantType": { "name": "Cor" } }
}
]
}
]

POST /api/admin/products/[id]/variants​

Cria uma nova variante para o produto.

Body:

CampoTipoObrigatórioDescrição
pricenumber✅Preço da variante
stockinteger✅Estoque
skustring—SKU da variante
comparePricenumber—Preço "de"
valuesarray✅Opções que compõem a variante
values[].variantOptionIdstring✅ID da opção de variante

Resposta 201 Created: Objeto da variante criada.


PATCH /api/admin/products/[id]/variants/[variantId]​

Atualiza uma variante.


DELETE /api/admin/products/[id]/variants/[variantId]​

Remove uma variante.


14.3 Upload de Imagens​

POST /api/admin/upload​

Faz upload de uma imagem para uso em produtos. Aceita multipart/form-data.

Autenticação: Cookie JWT ✅ (role: ADMIN)

Content-Type: multipart/form-data

Form Fields:

CampoTipoObrigatórioDescrição
fileFile✅Arquivo de imagem (JPEG, PNG, WebP)

Resposta 200 OK:

{
"url": "https://cdn.ljvelasearomas.com.br/uploads/vela-lavanda-200g-hero.jpg"
}

Exemplo cURL:

curl -X POST https://ljvelasearomas.com.br/api/admin/upload \
-H "Cookie: token=<JWT>" \
-F "file=@/path/to/imagem.jpg"

Erros:

CódigoMotivo
400Nenhum arquivo enviado
403Não é administrador
413Arquivo muito grande

14.4 Pedidos (Admin)​

GET /api/admin/orders​

Lista todos os pedidos com filtros avançados.

Query Params:

ParâmetroTipoDescrição
statusstringFiltrar por status (ver tabela abaixo)
qstringBusca por número do pedido, nome ou e-mail
fromstringData inicial (ISO 8601, ex.: 2025-01-01)
tostringData final (ISO 8601)
pageintegerPágina (padrão: 1)
limitintegerItens/página (padrão: 20)

Status de pedido disponíveis:

ValorDescrição
PENDINGAguardando pagamento
PROCESSINGPagamento confirmado, em preparo
SHIPPEDEnviado / Em trânsito
DELIVEREDEntregue
CANCELLEDCancelado
REFUNDEDReembolsado

GET /api/admin/orders/[id]​

Retorna detalhe completo de um pedido.


PATCH /api/admin/orders/[id]​

Atualiza o status de um pedido.

Body:

CampoTipoObrigatórioDescrição
statusstring✅Novo status (ver tabela acima)
notestring—Nota interna sobre a atualização

Resposta 200 OK: Objeto do pedido atualizado.


GET /api/admin/orders/export​

Exporta pedidos como arquivo CSV.

Query Params:

ParâmetroTipoDescrição
statusstringFiltrar por status
fromstringData inicial (ISO 8601)
tostringData final (ISO 8601)

Resposta 200 OK:

Content-Type: text/csv; charset=utf-8
Content-Disposition: attachment; filename="pedidos-2025-01-10.csv"

POST /api/admin/orders/[id]/notes​

Adiciona uma nota interna ao pedido (visível apenas para admins).

Body:

CampoTipoObrigatórioDescrição
notestring✅Texto da nota

Resposta 201 Created: Objeto da nota criada.


NF-e (Nota Fiscal Eletrônica)​

POST /api/admin/orders/[id]/nfe/emitir​

Emite a NF-e para o pedido via integração fiscal.

Resposta 200 OK:

{
"status": "autorizada",
"chave": "35250112345678000100550010000001231234567890",
"numero": 123,
"serie": "001"
}

GET /api/admin/orders/[id]/nfe/danfe​

Faz download do DANFE (PDF) da NF-e emitida.

Resposta 200 OK:

Content-Type: application/pdf
Content-Disposition: attachment; filename="danfe-clxord001.pdf"

POST /api/admin/orders/[id]/nfe/cancelar​

Cancela uma NF-e emitida.

Resposta 200 OK: { "status": "cancelada" }


14.5 Cupons (Admin)​

GET /api/admin/coupons​

Lista todos os cupons cadastrados.

Resposta 200 OK:

[
{
"id": "clxcoupon01",
"code": "LAVANDA10",
"type": "PERCENT",
"value": 10,
"minOrderValue": 80.00,
"maxUses": 100,
"usedCount": 47,
"expiresAt": "2025-12-31T23:59:59.000Z",
"active": true,
"createdAt": "2025-01-01T00:00:00.000Z"
}
]

POST /api/admin/coupons​

Cria um novo cupom de desconto.

Body:

CampoTipoObrigatórioDescrição
codestring✅Código do cupom (unique, uppercase recom.)
typestring✅"PERCENT" ou "FIXED"
valuenumber✅Percentual (0–100) ou valor em R$
minOrderValuenumber—Valor mínimo do pedido para ativar
maxUsesinteger—Limite de usos totais
expiresAtstring—Data de expiração (ISO 8601)
activeboolean✅Se o cupom está ativo

Resposta 201 Created: Objeto do cupom criado.


PATCH /api/admin/coupons/[id]​

Atualiza um cupom.


DELETE /api/admin/coupons/[id]​

Remove um cupom.


14.6 Clientes​

GET /api/admin/customers​

Lista todos os clientes cadastrados.

Query Params:

ParâmetroTipoDescrição
searchstringBusca por nome ou e-mail
activebooleanFiltrar por status da conta

Resposta 200 OK:

{
"data": [
{
"id": "clx1a2b3c4d",
"name": "Maria Silva",
"email": "maria@email.com",
"isActive": true,
"createdAt": "2024-03-15T10:30:00.000Z",
"_count": { "orders": 5 }
}
],
"pagination": { "page": 1, "limit": 20, "total": 312, "totalPages": 16 }
}

GET /api/admin/customers/[id]​

Retorna dados completos do cliente, incluindo histórico de pedidos.


PATCH /api/admin/customers/[id]/status​

Ativa ou suspende a conta de um cliente.

Body:

CampoTipoObrigatórioDescrição
activeboolean✅true ativa, false suspende

Nota: Contas suspensas não conseguem fazer login (403 Forbidden).


GET /api/admin/customers/export​

Exporta a lista de clientes como CSV.

Resposta: Arquivo CSV com Content-Disposition: attachment.


14.7 Avaliações​

GET /api/admin/reviews​

Lista todas as avaliações de produtos.

Query Params:

ParâmetroTipoDescrição
approvedbooleantrue = aprovadas, false = pendentes

PATCH /api/admin/reviews/[id]​

Aprova ou rejeita uma avaliação.

Body:

CampoTipoObrigatórioDescrição
approvedboolean✅true aprova, false rejeita

Resposta 200 OK: Objeto da review atualizada.


DELETE /api/admin/reviews/[id]​

Remove uma avaliação permanentemente.


14.8 Estoque​

GET /api/admin/stock​

Lista produtos com estoque atual e movimentações recentes.

Resposta 200 OK:

[
{
"id": "clx1a2b3c4d",
"name": "Vela de Lavanda 200g",
"sku": "VEL-LAV-200",
"stock": 25,
"recentMovements": [
{
"id": "clxmov001",
"delta": -2,
"reason": "PURCHASE",
"source": "ORDER",
"createdAt": "2025-01-10T15:30:00.000Z"
}
]
}
]

Motivos de movimentação (reason):

ValorDescrição
PURCHASEVenda (decremento por pedido)
ADJUSTMENTAjuste manual pelo admin ou API
RETURNDevolução

PATCH /api/admin/stock/[productId]​

Atualiza o estoque de um produto diretamente (ajuste manual).

Body:

CampoTipoObrigatórioDescrição
stockinteger✅Novo estoque (≥ 0)

Resposta 200 OK: { "productId": "...", "stock": 42 }


14.9 Frete (Tarifas e Provedores)​

GET /api/admin/shipping​

Lista todas as tarifas de frete estáticas cadastradas.


POST /api/admin/shipping​

Cria uma nova tarifa estática.

Body:

CampoTipoObrigatórioDescrição
namestring✅Nome da tarifa (ex.: "Sul/Sudeste")
statesstring[]✅Lista de UFs cobertas (ex.: ["SP","RJ"])
pricenumber✅Preço em R$
estimatedDaysinteger✅Prazo estimado em dias úteis

PATCH /api/admin/shipping/[id]​

Atualiza uma tarifa estática.


DELETE /api/admin/shipping/[id]​

Remove uma tarifa estática.


GET /api/admin/shipping/providers​

Retorna o status de conexão das integrações de transportadora.

Resposta 200 OK:

{
"providers": [
{ "name": "Melhor Envio", "status": "connected", "lastCheck": "2025-01-10T12:00:00.000Z" },
{ "name": "Correios", "status": "connected", "lastCheck": "2025-01-10T12:00:00.000Z" },
{ "name": "Superfrete", "status": "disconnected", "lastCheck": "2025-01-10T12:00:00.000Z" }
]
}

14.10 Webhooks Outbound​

Webhooks outbound são chamadas HTTP que o sistema envia para endpoints externos quando eventos ocorrem (ex.: novo pedido, estoque baixo).

GET /api/admin/webhooks​

Lista todos os endpoints de webhook cadastrados.

Resposta 200 OK:

[
{
"id": "clxwh001",
"url": "https://meuapp.com/webhooks/loja",
"events": ["order.created", "order.status_changed", "stock.low"],
"active": true,
"createdAt": "2025-01-01T00:00:00.000Z"
}
]

POST /api/admin/webhooks​

Registra um novo endpoint de webhook.

Body:

CampoTipoObrigatórioDescrição
urlstring✅URL HTTPS do endpoint
secretstring✅Segredo para verificação HMAC
eventsstring[]✅Eventos a escutar (ver lista abaixo)

Eventos disponíveis:

EventoDescrição
order.createdNovo pedido criado
order.status_changedStatus do pedido atualizado
order.paidPedido pago
stock.lowProduto com estoque abaixo do limiar
stock.updatedEstoque atualizado via API/webhook
customer.createdNovo cliente cadastrado

PATCH /api/admin/webhooks/[id]​

Atualiza URL, secret ou eventos de um webhook.


DELETE /api/admin/webhooks/[id]​

Remove o endpoint de webhook.


POST /api/admin/webhooks/[id]/test​

Dispara um payload de teste para verificar conectividade do endpoint.

Resposta 200 OK:

{
"delivered": true,
"statusCode": 200,
"duration": 143
}

14.11 API Keys​

GET /api/admin/api-keys​

Lista todas as API Keys cadastradas. O valor da chave nunca é retornado — apenas metadados.

Resposta 200 OK:

[
{
"id": "clxkey001",
"name": "Integração ERP",
"scopes": ["products:read", "orders:read", "stock:write"],
"lastUsedAt": "2025-01-10T10:00:00.000Z",
"createdAt": "2025-01-01T00:00:00.000Z"
}
]

POST /api/admin/api-keys​

Cria uma nova API Key. O valor bruto da chave (rawKey) é retornado apenas uma vez nesta resposta e não pode ser recuperado posteriormente. O servidor armazena somente o hash SHA-256.

Body:

CampoTipoObrigatórioDescrição
namestring✅Nome descritivo da chave
scopesstring[]✅Escopos permitidos (ver tabela)

Resposta 201 Created:

{
"id": "clxkey002",
"name": "Integração ERP",
"scopes": ["products:read", "stock:write"],
"rawKey": "lvk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"createdAt": "2025-01-10T16:00:00.000Z"
}

⚠️ Atenção: Copie e salve o rawKey imediatamente. Ele não será exibido novamente.


DELETE /api/admin/api-keys/[id]​

Revoga (remove) uma API Key. Requisições que usarem a chave revogada receberão 401.


14.12 Dashboard​

GET /api/admin/dashboard​

Retorna métricas agregadas por período.

Query Params:

ParâmetroTipoPadrãoValores
periodstring30d7d, 30d, 90d

Resposta 200 OK:

{
"period": "30d",
"orders": {
"total": 142,
"change": 12.5
},
"revenue": {
"total": 18430.50,
"change": 8.3
},
"avgOrderValue": 129.79,
"newCustomers": 47,
"topProducts": [
{
"productId": "clx1a2b3c4d",
"name": "Vela de Lavanda 200g",
"sales": 38,
"revenue": 1516.20
}
]
}

GET /api/admin/dashboard/stats​

Retorna indicadores rápidos em tempo real (sem período).

Resposta 200 OK:

{
"totalProducts": 53,
"totalCategories": 6,
"totalOrders": 1482,
"totalRevenue": 193450.70,
"pendingOrders": 8,
"recentOrders": [
{
"id": "clxord099",
"orderNumber": "VEL-20250110-0099",
"total": 89.90,
"status": "PENDING",
"user": { "name": "João Costa", "email": "joao@email.com" },
"createdAt": "2025-01-10T17:55:00.000Z"
}
]
}

14.13 Configurações​

PATCH /api/admin/settings/puck​

Salva o conteúdo da homepage construído com o editor Puck.

Body:

CampoTipoObrigatórioDescrição
dataobject✅Objeto PuckData serializado

Resposta 200 OK: { "saved": true }


PATCH /api/admin/settings/puck-about​

Salva o conteúdo da página /sobre construído com Puck.

Body: Mesmo formato de /settings/puck.


PATCH /api/admin/settings/analytics​

Salva as configurações dos serviços de analytics.

Body:

CampoTipoObrigatórioDescrição
ga4Idstring—Google Analytics 4 ID
mpIdstring—Meta Pixel ID
clarityIdstring—Microsoft Clarity Project ID

Resposta 200 OK: { "saved": true }


PATCH /api/admin/settings/change-password​

Altera a senha do administrador logado.

Body:

CampoTipoObrigatórioDescrição
currentPasswordstring✅Senha atual
newPasswordstring✅Nova senha

Resposta 200 OK: { "message": "Senha alterada" }


15. API v1 — Integração Programática​

A API v1 é projetada para integrações server-to-server (ERPs, WMS, scripts de automação). Utiliza autenticação por API Key e tem CORS aberto para todas as origens.

Autenticação​

Todas as requisições devem incluir o header:

Authorization: Bearer lvk_live_<token>

Cada chamada verifica:

  1. Existência e formato da chave (lvk_live_ prefix)
  2. Hash SHA-256 contra o banco de dados
  3. Escopo necessário para a operação

Resposta em caso de falha:

HTTP/1.1 401 Unauthorized
{ "error": "API key inválida ou sem permissão" }

Escopos​

EscopoPermissão
products:readListar e consultar produtos
products:writeCriar e editar produtos
stock:writeAtualizar estoque via API e webhook
orders:readListar e consultar pedidos
orders:writeAtualizar status de pedidos

CORS​

Os endpoints /api/v1/* retornam os seguintes headers:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type

GET /api/v1/products​

Lista produtos com filtros. Escopo: products:read.

Query Params:

ParâmetroTipoPadrãoDescrição
pageinteger1Página
limitinteger50Itens/página (máx. 100)
activebooleantruefalse inclui inativos
categorystring—Slug da categoria
low_stockboolean—true retorna apenas produtos com estoque ≤ 5

Resposta 200 OK:

{
"data": [
{
"id": "clx1a2b3c4d",
"name": "Vela de Lavanda 200g",
"slug": "vela-lavanda-200g",
"sku": "VEL-LAV-200",
"price": "39.90",
"comparePrice": "49.90",
"stock": 25,
"active": true,
"featured": false,
"weight": 0.3,
"updatedAt": "2025-01-10T15:30:00.000Z",
"category": { "id": "clxcat001", "name": "Velas Aromáticas", "slug": "velas-aromaticas" },
"images": [{ "url": "...", "alt": "Vela de Lavanda 200g" }]
}
],
"pagination": { "page": 1, "limit": 50, "total": 53, "totalPages": 2 }
}

Exemplo cURL:

curl https://ljvelasearomas.com.br/api/v1/products?low_stock=true \
-H "Authorization: Bearer lvk_live_a1b2c3d4e5f6..."

GET /api/v1/products/[id]​

Retorna detalhes de um produto por ID. Escopo: products:read.

Path Params:

ParâmetroTipoDescrição
idstringID do produto

Resposta 200 OK: Mesmo objeto do endpoint de listagem, campo único.

Erros:

CódigoMotivo
401API Key inválida
404Produto não encontrado

PATCH /api/v1/products/[id]/stock​

Atualiza o estoque de um produto. Escopo: stock:write.

Body:

CampoTipoObrigatórioDescrição
stockinteger✅Novo estoque (≥ 0)

Resposta 200 OK:

{
"id": "clx1a2b3c4d",
"sku": "VEL-LAV-200",
"stock": 42,
"updatedAt": "2025-01-10T16:00:00.000Z"
}

Exemplo cURL:

curl -X PATCH https://ljvelasearomas.com.br/api/v1/products/clx1a2b3c4d/stock \
-H "Authorization: Bearer lvk_live_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{"stock": 42}'

GET /api/v1/orders​

Lista pedidos. Escopo: orders:read.

Query Params:

ParâmetroTipoDescrição
statusstringFiltrar por status do pedido
pageintegerPágina (padrão: 1)
limitintegerItens/página (padrão: 50, máx: 100)

Resposta 200 OK: Lista paginada de pedidos com itens e pagamento.


GET /api/v1/orders/[id]​

Retorna detalhes de um pedido por ID. Escopo: orders:read.

Erros:

CódigoMotivo
401API Key inválida
404Pedido não encontrado

16. Webhook Inbound — Estoque​

POST /api/webhooks/stock​

Atualiza o estoque de produtos via webhook externo (ex.: ERP, WMS). Registra movimentações no histórico de estoque e dispara webhooks outbound caso estoque fique abaixo do limiar.

Autenticação: API Key com escopo stock:write

Authorization: Bearer lvk_live_<token>

Content-Type: application/json


Modo sync — Sincronização em Lote por SKU​

Define o estoque exato para uma lista de SKUs. Funciona com SKU de produto ou SKU de variante.

Body:

{
"type": "sync",
"items": [
{ "sku": "VEL-LAV-200", "stock": 42 },
{ "sku": "VEL-ROS-150", "stock": 18 },
{ "sku": "VEL-BAU-100-BRANCO", "stock": 0 }
]
}
CampoTipoObrigatórioDescrição
typestring✅"sync"
itemsarray✅Lista de itens a sincronizar
items[].skustring✅SKU do produto ou variante
items[].stockinteger✅Novo estoque exato (≥ 0)

Modo set — Definir Estoque por ID​

Define o estoque exato de um produto ou variante por ID.

Body:

{
"type": "set",
"productId": "clx1a2b3c4d",
"variantId": "clxvar001",
"stock": 42
}
CampoTipoObrigatórioDescrição
typestring✅"set"
productIdstring✅ID do produto
variantIdstring—ID da variante (omitir para o produto)
stockinteger✅Novo estoque exato (≥ 0)

Modo delta — Incremento/Decremento Relativo​

Aplica um delta ao estoque atual. O valor mínimo resultante é 0 (clamp automático).

Body:

{
"type": "delta",
"productId": "clx1a2b3c4d",
"variantId": "clxvar001",
"delta": -3
}
CampoTipoObrigatórioDescrição
typestring✅"delta"
productIdstring✅ID do produto
variantIdstring—ID da variante (omitir para o produto)
deltainteger✅Incremento positivo ou decremento negativo

Exemplo: Se o estoque atual for 5 e delta for -8, o estoque resultante será 0 (não negativo).


Resposta 200 OK​

{
"ok": true,
"updated": 3,
"errors": [
"SKU não encontrado: VEL-INEXISTENTE-999"
]
}
CampoDescrição
oktrue se ao menos parte do payload foi processada
updatedNúmero de produtos/variantes atualizados com sucesso
errorsArray de mensagens para itens que falharam (não aborta a operação)

Comportamento de erro parcial: Em modo sync, SKUs não encontrados são acumulados em errors e o processamento dos demais itens continua. Nos modos set e delta, se o produto/variante não for encontrado, a requisição retorna 404 imediatamente.

Webhooks Outbound Disparados​

Após processar, o servidor dispara automaticamente:

EventoCondição
stock.lowEstoque resultante ≤ limiar configurado (padrão: 5 unidades)
stock.updatedAo menos 1 item atualizado com sucesso

Erros:

CódigoMotivo
400JSON malformado no body
401API Key ausente, inválida ou sem escopo
404Produto ou variante não encontrado (set/delta)
422Payload com estrutura inválida
500Erro interno do servidor

Exemplo cURL — sincronização em lote:

curl -X POST https://ljvelasearomas.com.br/api/webhooks/stock \
-H "Authorization: Bearer lvk_live_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"type": "sync",
"items": [
{ "sku": "VEL-LAV-200", "stock": 42 },
{ "sku": "VEL-ROS-150", "stock": 18 }
]
}'

Documentação gerada para LJ Velas & Aromas — ljvelasearomas.com.br