E-commerce com Next.js
Como criar um carrinho e Stripe Checkout com Next.js
Implemente carrinhos anônimos e de clientes, preços controlados pelo servidor, Stripe Checkout, webhooks assinados, pedidos idempotentes e validação de estoque no Next.js.
Um carrinho registra a intenção de compra. Não autoriza um preço, não reserva estoque automaticamente nem comprova a conclusão do pagamento.
Definir a identidade e a duração do carrinho
Crie um token aleatório de carrinho para visitantes anônimos e guarde-o em um cookie seguro HTTP-only. O banco controla carrinho, IDs das variantes dos itens, quantidades, horários e status. Após o login, associe ou mescle o carrinho com o do cliente conforme regras explícitas.
Defina uma expiração por inatividade e decida se carrinhos concluídos se tornam registros imutáveis. Não armazene o carrinho inteiro ou os preços oficiais em um cookie legível pelo navegador, onde clientes e extensões podem alterá-los.
Validar cada alteração do carrinho
Uma ação de adição aceita ID da variante e quantidade, resolve o carrinho pelo token controlado pelo servidor, verifica se a variante está ativa, aplica limites de quantidade e faz upsert do item. Nunca aceita do navegador a propriedade da conta, o preço do SKU ou a moeda.
Retorne um erro esperado para variantes inválidas ou indisponíveis. Revalide a exibição do carrinho após gravar para que o usuário veja a própria alteração. Autorização e verificação de propriedade devem estar dentro da ação, mesmo quando a interface só mostra controles válidos.
"use server";
export async function addToCart(variantId: string, quantity: number) {
const cart = await requireCart();
const variant = await getPurchasableVariant(variantId);
if (!variant) return { error: "Variant unavailable" };
await upsertCartLine(cart.id, variant.id, clampQuantity(quantity));
updateTag("cart:" + cart.id);
}Mesclar carrinhos anônimos e de clientes
No login, carregue os dois carrinhos em uma única transação no servidor. Combine variantes iguais respeitando os limites de compra, preserve itens únicos válidos e informe os itens removidos ou alterados. Marque o carrinho anônimo como mesclado para que repetir a requisição não duplique quantidades.
Não escolha silenciosamente o carrinho mais caro ou mais novo. O produto deve definir se o carrinho do cliente ganha, se os carrinhos se fundem ou se o comprador escolhe. Teste o comportamento em múltiplas abas e chamadas de login repetidas.
Recalcular os preços antes do Checkout
Carregue no servidor todas as variantes ativas e os preços atuais, aplique descontos validados, calcule os dados de impostos e as opções de frete e crie um retrato do pedido pendente. Se preço ou disponibilidade mudarem, retorne o carrinho atualizado para confirmação explícita em vez de cobrar silenciosamente outro valor.
Monte os itens da Stripe a partir dos registros do servidor. Adicione o ID do pedido pendente aos metadados e use uma chave estável de idempotência para tentativas repetidas de checkout quando o negócio exigir uma única operação no provedor.
Confirmar o pagamento através de webhooks
A URL de sucesso indica que o Checkout retornou, mas não comprova a liquidação do pagamento. Verifique a assinatura do webhook sobre o corpo bruto, localize o pedido pendente por metadados confiáveis e registre o evento Stripe com uma restrição de unicidade.
Crie ou marque o pedido final uma vez e depois enfileire o e-mail de confirmação e o processamento do pedido. Um evento duplicado deve retornar sucesso sem repetir esses efeitos. Uma sessão expirada pode liberar reservas e devolver o carrinho ao estado editável.
export async function POST(request: Request) {
const rawBody = await request.text();
const signature = request.headers.get("stripe-signature");
const event = stripe.webhooks.constructEvent(
rawBody,
signature,
process.env.STRIPE_WEBHOOK_SECRET,
);
await processCheckoutEventOnce(event);
return new Response(null, { status: 200 });
}Proteger as leituras de carrinhos e pedidos
O acesso ao carrinho anônimo exige um token impossível de adivinhar emitido pelo servidor. Carrinhos de clientes e pedidos exigem o proprietário autenticado. Páginas de confirmação devem consultar o pedido pela referência segura para exposição pública e pelo contexto do proprietário, sem expor IDs sequenciais do banco.
Retorne DTOs restritos aos Client Components. Objetos do provedor de pagamento, campos internos antifraude, payloads de webhooks e erros do banco ficam no servidor. Os logs devem usar IDs de pedidos e eventos sem imprimir desnecessariamente dados de pagamento ou endereço.
Testar adulterações, novas tentativas e expiração
Altere a variante, a quantidade e o preço enviado; repita as ações de adição e mesclagem; entregue um webhook duas vezes e eventos fora de ordem; expire o Checkout; remova estoque durante o pagamento; e solicite o pedido de outro cliente. Todo resultado deve ser seguro e explicável.
Implante a compilação de produção na Adios com referências aos segredos da Stripe e do banco. Verifique a rota HTTPS gerada em modo de teste, inspecione os logs de execução e cadastre o webhook estável do domínio personalizado somente após a versão informar que está saudável.