@dariomvg/create
stripepagospago-unicowebhooksintegracion

Stripe Pagos Únicos — Configuración

Módulo autocontenido para pagos únicos con Stripe en un proyecto de Next.js App Router. Sin suscripciones ni facturación: solo crear un pago, seguir su estado y reembolsarlo si hace falta.

Dependencias

Este módulo usa:

  • stripe — SDK del lado del servidor, usado en lib/stripe/service.ts
  • @stripe/stripe-js — SDK del lado del cliente, usado en lib/stripe/client.ts

No se instalan automáticamente: agregalos con tu gestor de paquetes preferido antes de usar el módulo.

Mapa de archivos

lib/stripe/
├── service.ts   # Internal logic + Stripe SDK instance. Don't touch/import directly elsewhere.
├── actions.ts   # Server Actions — import into Server Components.
├── types.ts     # Shared types — safe to import anywhere.
└── client.ts    # Client-side helpers — import into Client Components.

app/api/webhooks/stripe/
└── route.ts     # Webhook endpoint. Register this URL in your Stripe Dashboard.

.env.local       # Stripe keys (see below).

1. Variables de entorno

Completá .env.local:

VariableDónde conseguirla
STRIPE_SECRET_KEYDashboard → Developers → API keys
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYDashboard → Developers → API keys
STRIPE_WEBHOOK_SECRETDashboard → Developers → Webhooks (o la salida de stripe listen en local)

2. Webhooks

En el Stripe Dashboard, agregá un endpoint que apunte a:

https://yourdomain.com/api/webhooks/stripe

Suscribilo como mínimo a:

  • payment_intent.succeeded
  • payment_intent.payment_failed
  • payment_intent.canceled
  • charge.refunded
  • checkout.session.completed

Para probar en local, usá el Stripe CLI:

stripe listen --forward-to localhost:3000/api/webhooks/stripe

La lógica de negocio de lo que pasa con cada evento (cumplir un pedido, enviar un email, etc.) va dentro de stripeService.handleWebhookEvent en service.ts: es la única parte de service.ts pensada para extenderse a medida que tu app crece.

3. Uso

Checkout alojado (lo más simple: redirigir a una página alojada por Stripe)

Del lado del servidor, en un Server Component o en una form action:

import { createCheckoutSession } from "@/lib/stripe/actions";

const result = await createCheckoutSession({
  amount: 2000, // $20.00, in cents
  currency: "usd",
  productName: "Pro plan — one time",
  successUrl: "https://yourdomain.com/success",
  cancelUrl: "https://yourdomain.com/cancel",
});

if (result.success) {
  // result.data.url — redirect the user here, or:
  // result.data.sessionId — pass to redirectToCheckout() client-side
}

Del lado del cliente, si preferís redirigir desde el navegador con el id de la sesión:

"use client";
import { redirectToCheckout } from "@/lib/stripe/client";

await redirectToCheckout(sessionId);

Formulario de pago personalizado (embebido, con Stripe Elements)

Del lado del servidor:

import { createPaymentIntent } from "@/lib/stripe/actions";

const result = await createPaymentIntent({ amount: 2000, currency: "usd" });
// result.data.clientSecret — pass to your Elements form

Del lado del cliente, después de recolectar los datos de la tarjeta con Stripe Elements:

"use client";
import { confirmCardPayment } from "@/lib/stripe/client";

await confirmCardPayment(clientSecret, paymentMethodId);

Consultar el estado

import { getPayment, getPaymentStatus } from "@/lib/stripe/actions";

const status = await getPaymentStatus(paymentIntentId);
const full = await getPayment(paymentIntentId);

Cancelar / reembolsar

import { cancelPayment, refundPayment } from "@/lib/stripe/actions";

await cancelPayment(paymentIntentId);

await refundPayment({ paymentIntentId }); // full refund
await refundPayment({ paymentIntentId, amount: 500 }); // partial, $5.00

Métodos de pago

import { listPaymentMethods } from "@/lib/stripe/actions";

const methods = await listPaymentMethods(stripeCustomerId);

Manejo de errores

Cada función de actions.ts y client.ts devuelve:

{ success: true, data: T } | { success: false, error: string }

Verificá siempre result.success antes de leer result.data: nada lanza errores a través del límite del módulo, así que nunca necesitás un try/catch alrededor de estas llamadas.

Notas

  • service.ts es el único archivo que importa el paquete stripe o lee STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET. Mantenelo así: es lo que hace imposible filtrar la secret key a un Client Component por accidente.
  • Las páginas de éxito/cancelación (successUrl/cancelUrl) no están incluidas acá: este módulo solo produce los datos y las URLs; apuntalas a tus páginas de éxito/cancelación de checkout existentes.