Ir al contenido

Cobrar con tarjeta y otras pasarelas

De serie, la tienda cobra por transferencia, contrarreembolso, Bizum y criptomonedas. Eso funciona sin dar de alta nada y sin que nadie pueda cerrarte la cuenta.

Si además quieres tarjeta, hay cinco pasarelas listas. Cada una aparece sola en cuanto pones sus credenciales; sin ellas, no existe.

Para qué Trae
MONEI España Bizum, tarjeta, PayPal, Apple y Google Pay
Stripe Internacional Tarjeta, Apple y Google Pay, SEPA, iDEAL
PayPal El botón que más pide el comprador PayPal y tarjeta
Mollie Norte de Europa iDEAL, Bancontact, tarjeta, SEPA
Adyen Volumen alto Tarjeta y métodos locales de medio mundo

Si vendes en España, MONEI. Es Entidad de Pago con licencia del Banco de España, llega a las mismas vías bancarias que el TPV de tu banco y hace Bizum de verdad.

¿Y Redsys? Es el TPV de CaixaBank, BBVA o Santander, y sería la primera opción, pero sus librerías oficiales son PHP, Java y .NET. Integrarlo aquí significaría escribir su firma criptográfica a mano, y eso en un cobro es la clase de error que no encuentra ninguna prueba: lo encuentra el cliente al que se le ha cobrado dos veces. MONEI cubre ese terreno sin inventarse nada.

Poner las variables en el .env del backend y reiniciar. Nada más.

Terminal window
# España: Bizum y tarjeta
MONEI_API_KEY=pk_...
MONEI_WEBHOOK_URL=https://tu-tienda.com/hooks/payment/pasarela_monei
# Internacional
STRIPE_API_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
# PayPal
PAYPAL_CLIENT_ID=...
PAYPAL_CLIENT_SECRET=...
PAYPAL_WEBHOOK_ID=... # opcional, ver más abajo
# El dominio del escaparate: a él vuelve el comprador después de pagar fuera
PAYMENT_RETURN_URL=https://tu-tienda.com

Y en el .env del escaparate, si usas Stripe:

Terminal window
STRIPE_PUBLIC_KEY=pk_live_... # la pública, la que ve el navegador
SITE_URL=https://tu-tienda.com

La ruta exacta de vuelta la pone el tema, porque cambia con el idioma de la página: un comprador que estaba en /en/checkout vuelve a /en/checkout/volver y no acaba en castellano justo al confirmar la compra.

Después hay que activarla en el checkout: Panel → Ajustes → Regiones, y marcarla en la región que corresponda. Estar configurada no es estar visible.

Stripe lo prohíbe en sus condiciones para Reino Unido y la UE, y Shopify Payments igual. No es un problema técnico ni se arregla configurando nada: la cuenta se cierra, normalmente sin aviso y con el dinero retenido.

Los procesadores especializados cobran del 1 % al 5 % y retienen reservas de hasta el 10 % durante 180 días.

Por eso los métodos de serie —transferencia, contrarreembolso, Bizum y cripto— no son un apaño mientras llega la tarjeta. Para ese sector son la vía fiable, y para cualquiera son lo que evita depender de que a nadie le parezca mal lo que vendes.

Qué ve el comprador
Transferencia, contrarreembolso, Bizum Confirma el pedido y ya está
PayPal, Mollie, MONEI Va a la página de la pasarela y vuelve
Stripe Paga sin salir de la tienda, en un formulario de Stripe
Adyen Paga sin salir, en el Drop-in de Adyen con todos sus métodos

Con las dos últimas el pedido se cierra al volver, no al pulsar el botón. Cerrarlo antes sería aceptar pedidos que nadie ha pagado.

Y la página de vuelta no se cree lo que diga la URL. Que el comprador haya vuelto solo significa «ya puedes mirar»: se le pregunta a la pasarela, y si el dinero no está, no hay pedido — por mucho que ponga ?success=true, que es algo que cualquiera puede escribir.

Con las demás, al volver se le pregunta a la pasarela y ya está. Con Adyen no se puede: su API no sabe contestar sobre una sesión sin un dato que solo tiene el navegador, y su propia documentación dice que el resultado llega asíncrono, en un webhook.

Ese webhook va firmado con HMAC, así que lo que dice es de fiar y trae dentro el estado y el importe. Pero significa una cosa importante:

Con Adyen, el webhook tiene que llegar. Si su URL no es accesible desde internet, el comprador paga y el pedido no se cierra. En local no funciona sin un túnel.

El Drop-in enseña de una vez todos los métodos que tengas activados en tu cuenta —tarjeta, iDEAL, Klarna, lo que sea— y se encarga él del 3-D Secure.

Con soloAutorizar la pasarela reserva el dinero al hacer el pedido y no lo cobra hasta que lo capturas desde el panel, al enviar.

Sirve para no cobrar lo que quizá no puedas servir. Pero una reserva caduca —entre unos días y un mes según la pasarela— y si caduca no hay nada que cobrar. Si no vas a preparar los pedidos rápido, no lo actives.

En el panel, un pago reservado sale como autorizado, no como pagado. Es a propósito: servir con una reserva es regalar la mercancía si expira.

Cada pasarela avisa a la tienda cuando un pago cambia. La URL es siempre:

https://tu-tienda.com/hooks/payment/pasarela_<pasarela>

Lo que llega en ese aviso no se cree. Se comprueba la firma, se saca de él únicamente el identificador del pago y se le vuelve a preguntar a la pasarela cuál es el estado. Suena exagerado hasta que se piensa qué es un webhook: una petición que puede mandar cualquiera que adivine la URL, diciendo «esto ya está pagado».

Detalles por pasarela:

  • Stripe y Adyen firman con un secreto. Sin ese secreto configurado, la tienda no acepta ningún aviso suyo — una ruta abierta que marca pedidos como pagados no puede quedarse viva por un olvido en el .env.
  • MONEI firma con su cabecera propia; lo valida su SDK.
  • Mollie no firma, a propósito: su aviso trae solo el identificador justamente para que haya que repreguntar.
  • PayPal no usa un secreto compartido: se le pregunta a él si el aviso es suyo. Con PAYPAL_WEBHOOK_ID se hace esa comprobación; sin él, la seguridad la da volver a consultar el pedido.

«falta el paquete stripe» — la pasarela está configurada pero su librería no está instalada. npm i stripe en el backend.

«La pasarela “adyen” necesita merchantAccount» — sale al arrancar, no al cobrar, y es deliberado: una pasarela mal configurada tiene que dar la cara antes de que haya un cliente en el checkout.

Un pago se queda en «pendiente» — mira el registro de avisos de la pasarela. Casi siempre es la URL del webhook mal puesta o inaccesible desde fuera.

Las cinco viven en @pcreative/payments-contract, cada una sobre el SDK oficial de su pasarela. Para añadir una más se implementan seis operaciones —crear, consultar, capturar, cancelar, reembolsar y webhook— y se registra igual que las demás. El resto del sistema no se entera.