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
pageinteger1Nú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
namestringNome completo
emailstringE-mail válido
passwordstringSenha 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
emailstringE-mail
passwordstringSenha

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
currentPasswordstringSenha atual
newPasswordstringNova 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)
searchstringBusca por nome ou descrição
categorystringSlug da categoria
featuredbooleanSomente produtos em destaque (true)
sortstringnewestprice_asc, price_desc, newest, popular
minPricenumberPreço mínimo (R$)
maxPricenumberPreço máximo (R$)
inStockbooleanSomente 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
qstringTermo de busca
pageintegerPágina (padrão 1)
limitintegerLimite (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
ratingintegerNota de 1 a 5
titlestringTítulo da avaliação
bodystringTexto 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
addressIdstringID do endereço de entrega (deve pertencer ao usuário)
cartItemsarrayItens do pedido. Se omitido, usa o carrinho salvo no BD
cartItems[].productIdstringID do produto
cartItems[].quantityintegerQuantidade (mínimo 1)
cartItems[].pricenumberPreço sugerido (ignorado — servidor usa preço do banco)
notesstringObservações do pedido
couponIdstringID 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
orderIdstringID 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
orderIdstringID do pedido
tokenstringToken do cartão gerado pelo MP Brick
paymentMethodIdstringMétodo (ex.: visa, master)
installmentsintegerNúmero de parcelas
issuerIdstringID 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
orderIdstringID 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
cepstringCEP de destino (8 dígitos, com ou sem -)
subtotalnumberSubtotal do pedido em R$
weightnumberPeso 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
codestringCódigo do cupom (case-insensitive)
subtotalnumberSubtotal 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
labelstringRótulo (ex.: "Casa", "Trabalho")
streetstringLogradouro
numberstringNúmero
complementstringComplemento
districtstringBairro
citystringCidade
statestringUF (2 letras, ex.: SP)
zipCodestringCEP (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
productIdstringID 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
emailstringE-mail
namestringNome

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
emailstringE-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
namestringNome do remetente
emailstringE-mail para resposta
subjectstringAssunto da mensagem
messagestringCorpo 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
namestringNome do produto (mín. 2 chars)
slugstringSlug URL-friendly (mín. 2 chars)
descriptionstringDescrição
pricenumberPreço em R$ (positivo)
comparePricenumberPreço "de" para exibir riscado
stockintegerEstoque inicial (≥ 0)
skustringCódigo SKU
weightnumberPeso em kg
categoryIdstringID da categoria
featuredbooleanEm destaque (padrão: false)
activebooleanAtivo (padrão: true)
imagesarrayVer estrutura abaixo
images[].urlstringURL da imagem
images[].altstringTexto alternativo
images[].isPrimarybooleanImagem principal
images[].orderintegerOrdem 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
namestringNome do tipo
slugstringSlug único
orderintegerOrdem 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
valuestringValor da opção
orderintegerOrdem

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
pricenumberPreço da variante
stockintegerEstoque
skustringSKU da variante
comparePricenumberPreço "de"
valuesarrayOpções que compõem a variante
values[].variantOptionIdstringID 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
fileFileArquivo 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
statusstringNovo status (ver tabela acima)
notestringNota 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
notestringTexto 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
codestringCódigo do cupom (unique, uppercase recom.)
typestring"PERCENT" ou "FIXED"
valuenumberPercentual (0–100) ou valor em R$
minOrderValuenumberValor mínimo do pedido para ativar
maxUsesintegerLimite de usos totais
expiresAtstringData de expiração (ISO 8601)
activebooleanSe 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
activebooleantrue 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
approvedbooleantrue 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
stockintegerNovo 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
namestringNome da tarifa (ex.: "Sul/Sudeste")
statesstring[]Lista de UFs cobertas (ex.: ["SP","RJ"])
pricenumberPreço em R$
estimatedDaysintegerPrazo 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
urlstringURL HTTPS do endpoint
secretstringSegredo 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
namestringNome 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
dataobjectObjeto 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
ga4IdstringGoogle Analytics 4 ID
mpIdstringMeta Pixel ID
clarityIdstringMicrosoft Clarity Project ID

Resposta 200 OK: { "saved": true }


PATCH /api/admin/settings/change-password

Altera a senha do administrador logado.

Body:

CampoTipoObrigatórioDescrição
currentPasswordstringSenha atual
newPasswordstringNova 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
categorystringSlug da categoria
low_stockbooleantrue 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
stockintegerNovo 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"
itemsarrayLista de itens a sincronizar
items[].skustringSKU do produto ou variante
items[].stockintegerNovo 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"
productIdstringID do produto
variantIdstringID da variante (omitir para o produto)
stockintegerNovo 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"
productIdstringID do produto
variantIdstringID da variante (omitir para o produto)
deltaintegerIncremento 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