Pagos
Cómo cobra el pago, cómo conectar Stripe o PayPal y qué le pasa a un pedido en cada paso.
Para el paquete Full Stack
Cómo cobra el pago
El cliente paga en la propia página del proveedor, Stripe Checkout o PayPal, así que ni el sitio web ni la API ven nunca un número de tarjeta. La API calcula ella misma el precio del pedido, a partir de su propio menú, sus tarifas y sus descuentos, nunca a partir de los precios que envía el navegador.
| Método | Se ofrece cuando | Qué pasa |
|---|---|---|
| Pago con tarjeta (Stripe) | STRIPE_SECRET_KEY está configurada | El pedido se guarda sin pagar y el navegador va a la página de Stripe. El pedido pasa a pagado cuando la API ha preguntado a Stripe qué pasó y el importe coincide. |
| PayPal | PAYPAL_CLIENT_ID y PAYPAL_CLIENT_SECRET están configurados | Lo mismo, en la página de PayPal: la API captura el pago aprobado antes de que el pedido cuente como pagado. |
| Pago de demostración | No hay ningún proveedor configurado | Marca el pedido como pagado sin mover dinero, para poder probar todo el proceso en local. Nunca se ofrece junto a un proveedor configurado. |
Los invitados pueden pagar con su nombre y su correo; los clientes con sesión iniciada ven el pedido en su cuenta. Un pedido pagado pasa a la cola de la cocina; el personal no puede confirmar uno sin pagar.
Los precios están en dólares estadounidenses. En los ajustes de demostración, la entrega cuesta $2.99 y la recogida es gratuita, con un mínimo de entrega de $10.00. No hay una línea de impuestos aparte: el cliente paga los precios del menú más la tarifa, menos cualquier descuento. El personal cambia las tarifas en el panel, en Settings, Restaurant, que también muestra los métodos de pago que ofrece esta versión y si cada uno funciona en modo de prueba o real.
Conecta Stripe
Añade tu clave secreta
Desde la página de claves de API del panel de Stripe, pon la clave secreta en el
.envde la API. Usa una clave de prueba (sk_test_…) hasta que estés listo para cobrar dinero real: no mueve nada.El .env de la APISTRIPE_SECRET_KEY=sk_test_…Suscribe el webhook
En Stripe, añade un endpoint de webhook en la dirección de tu API seguida de
/api/payments/webhooks/stripe, suscrito acheckout.session.completed,checkout.session.expired,charge.refundedycharge.dispute.created. Copia su secreto de firma en el.envde la API.El .env de la APISTRIPE_WEBHOOK_SECRET=whsec_…Comprueba las direcciones de retorno
Stripe devuelve el navegador a
API_PUBLIC_URL, y la API lo reenvía al sitio web enSTOREFRONT_URL. En local, los dos valores por defecto funcionan. En tus propios dominios, configura ambos con las direcciones reales.Reinicia la API
Resultado esperado: El pago ofrece "Pay by card", y Settings, Restaurant, Payments lo muestra como ofrecido, en modo de prueba.
La clave publicable no es necesaria: el pago se hace en la propia página de Stripe. Para probar el webhook en tu propio equipo, la CLI de Stripe puede reenviar eventos a http://localhost:8000/api/payments/webhooks/stripe y muestra el secreto de firma que debes usar mientras está en marcha.
Conecta PayPal
Añade las credenciales de tu aplicación
Desde el panel de desarrollador de PayPal, copia el client id y el secreto de tu aplicación en el
.envde la API.PAYPAL_ENVessandboxpor defecto, que no mueve dinero;liveacepta pagos reales.El .env de la APIPAYPAL_CLIENT_ID=your-paypal-sandbox-client-id PAYPAL_CLIENT_SECRET=your-paypal-sandbox-client-secret PAYPAL_ENV=sandboxSuscribe el webhook
Añade un webhook en la dirección de tu API seguida de
/api/payments/webhooks/paypal, con los eventos de captura de pago: completado, denegado, reembolsado y revertido. Copia el id del webhook en el.envde la API: la API verifica cada llamada con él.El .env de la APIPAYPAL_WEBHOOK_ID=your-paypal-webhook-idReinicia la API
Resultado esperado: El pago ofrece PayPal.
Qué le pasa a un pedido
| Evento | El pedido |
|---|---|
| El cliente lo hace | Se guarda como pendiente y sin pagar. Reserva su stock y los puntos de recompensa que el cliente canjeó. |
| El proveedor confirma el pago | Pagado, por la vuelta del cliente o por el webhook, lo que llegue primero. La vuelta del navegador por sí sola nunca marca un pedido como pagado: la API pregunta antes al proveedor. |
| El cliente abandona la página de pago | Se comprueba con el proveedor a los 35 minutos con Stripe y a las 3 horas con PayPal, y luego se cancela como pago fallido, devolviendo su stock y sus puntos. |
| El proveedor informa de un reembolso completo | Reembolsado, y se retiran los puntos que ganó. Un reembolso parcial de Stripe se registra y deja el pedido como está. |
Un pago que llega para un pedido ya cancelado se registra como pendiente de reembolso y nunca recupera el pedido. El personal no puede marcar un pedido como reembolsado a mano: los reembolsos se hacen en Stripe o PayPal, y el webhook actualiza el pedido.
El pago de demostración
- Sin ningún proveedor configurado, el pago muestra "Demo payment" y "Place demo order". El pedido queda pagado al momento, sin mover dinero, para poder probar de principio a fin la cola de la cocina y la página de seguimiento.
- En cuanto se configura Stripe o PayPal, el pago de demostración desaparece, y se rechaza un pedido que lo pida.
- El webhook propio del pago de demostración,
POST /api/payments/webhooks/demo, rechaza todas las llamadas salvo quePAYMENT_WEBHOOK_SECRETesté configurado y se envíe como cabecerax-webhook-secret.
Cobrar pagos reales
- Cambia a las claves reales (
sk_live_…, o la aplicación real de PayPal conPAYPAL_ENV=live) y a un webhook creado en modo real, que tiene su propio secreto de firma o id. - Configura
API_PUBLIC_URLySTOREFRONT_URLcon tus direcciones reales, y añade el sitio web aCORS_ORIGIN: una dirección de retorno fuera de esa lista se rechaza. - Settings, Restaurant, Payments muestra cada método como "Live, real money" en cuanto funciona con credenciales reales.
- Los importes están siempre en dólares estadounidenses: la API cobra en
CURRENCYdeback-end/src/common/constants/ordering.constants.ts, y los dos frontends muestran los precios en dólares. Otra moneda supone un cambio de código en la API y en los frontends, conNEXT_PUBLIC_ANALYTICS_CURRENCYconfigurado a juego.