Usar Stripe para aceptar pagos con SCA
Disponible en: Free (Test mode), Professional, Business
Stripe es una plataforma de procesamiento de pagos que permite a los comerciantes aceptar pagos con tarjeta de crédito en sus aplicaciones y sitios web. Cuando conectas tu formulario a una cuenta de Stripe, puedes realizar cargos y recibir pagos desde tu sitio web.
¿Qué hay de nuevo?
El plugin de Stripe (V2) ahora soporta validación backend de pagos, cargos variables para donaciones y Strong Customer Authentication opcional.
Strong Customer Authentication (SCA) es una regulación que entró en vigor el 14 de septiembre de 2019. Requiere cambios en cómo los clientes europeos se autentican en pagos en línea. Esta regulación solo aplica a pagos en línea donde el banco del cliente y el negocio están ambos en el Espacio Económico Europeo (EEE).
Puedes saber si estás usando el nuevo plugin V2 de Stripe si la configuración de tu plugin muestra una Stripe Publishable Key. Si no ves la Publishable Key, puedes actualizar tu plugin a la última versión eliminando y volviendo a conectar el plugin. No se perderán datos.
Paso 1: Conectar a Stripe
Test Mode vs Live Mode
Los modos test y live funcionan de manera casi idéntica, con algunas diferencias necesarias:
- En test mode, los pagos no son procesados por las redes de tarjetas o proveedores de pagos, y solo se puede usar nuestra información de pago de prueba.
- Algunos métodos de pago que usan Sources tienen un flujo más matizado en live mode, con más pasos requeridos que en test mode.
- Las disputas también tienen un flujo más matizado en live mode, y un proceso de prueba más simple.
- En test mode, los webhooks que no fueron reconocidos exitosamente se reintentan tres veces durante unas pocas horas (en contraste con 72 horas para live mode).
Para ver los cargos de prueba, ve a tu Stripe Dashboard y haz clic en View Test Data

Ten en cuenta que si quieres cambiar de Test Mode a Live Mode necesitarás eliminar y crear el plugin de nuevo para obtener nuevas credenciales válidas a través de Stripe OAuth.
Sugerimos tener un formulario de entorno de desarrollo/staging conectado a test mode y un formulario de producción conectado a live mode.
Configuración del plugin de Stripe
Una vez que hayas agregado un formulario en Formspree, puedes conectarlo a Stripe usando el plugin de Stripe. Para hacerlo, primero ve a la pestaña Plugins de tu formulario. Luego haz clic en el botón del plugin de Stripe.

Después de hacer clic en el botón del plugin de Stripe podrás conectarte en modo Test o Live.
Test mode está disponible para todos los planes. Live mode solo está disponible para planes mejorados.

Selecciona qué modo quieres y haz clic en connect. Una vez que hayas iniciado sesión usando tu nombre de usuario y contraseña de Stripe, se te pedirá configurar la información del cargo de Stripe para este formulario. Establece la moneda y el precio que se cobrará cada vez que se envíe el formulario.
Hacer clic en allow variable price permitirá al desarrollador o visitante del sitio establecer el precio en el lado del cliente. Esto permite a un formulario cobrar una cantidad variable, como para una donación. También puede usarse para permitir que un formulario cobre diferentes precios dependiendo de otros factores, como un producto seleccionado. Una vez que se haga clic en allow variable price, el precio se leerá del campo del formulario price.
Precaución: si el precio variable está habilitado, cualquier cliente puede cambiar este valor directamente, o mediante ingeniería inversa de tu código, y crear cargos por cualquier cantidad. Asegúrate de verificar los cargos enviados a tu cuenta de Stripe. No validamos este valor.

Una vez que hayas terminado la configuración, haz clic en Connect para habilitar el plugin.
En el futuro, si quieres cambiar la descripción y el precio o deshabilitar el plugin por completo, puedes hacerlo haciendo clic nuevamente en el botón de Stripe para ajustar su configuración.
Una vez que hayas terminado la configuración y conexión de tu plugin de Stripe, verás este mensaje:

Copia la Publishable Key. La usaremos para construir nuestro flujo de checkout.
Paso 2: Construye tu flujo de checkout con Stripe Elements (no requiere SCA)
NOTA: Si estás usando React, consulta nuestro tutorial sobre Cómo construir un formulario de pago personalizado con React y Stripe.
Ahora que has configurado tu formulario de Formspree con el plugin de Stripe, es momento de construir tu flujo de checkout. Para cobrar pagos, debes tokenizar una tarjeta de crédito para enviarla de manera segura a Formspree.
Una forma sencilla de hacerlo es usando Stripe Elements. Es un conjunto de componentes UI predefinidos, como inputs y botones, para construir tu flujo de checkout. Está disponible como una característica de Stripe.js. Stripe.js tokeniza la información sensible dentro de un Element sin que toque tus servidores ni los nuestros.
Luego solo necesitas enviar el método de pago tokenizado a Formspree, que creará y cobrará el pago.
Aquí hay un ejemplo inspirado en los Stripe Docs:
Archivo HTML
<head>
<title>Checkout</title>
<script src="https://js.stripe.com/v3/"></script>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<form id="payment-form" action="">
<div id="card-element">
<!-- Elements will create input elements here -->
</div>
<!-- We'll put the error messages in this element -->
<div id="card-errors" role="alert"></div>
<button id="submit">Pay</button>
</form>
</body>
Archivo JS
$(document).ready(function () {
// Stripe settings
var stripe = Stripe("YOUR_PUBLISHABLE_KEY_COPIED_FROM_DASHBOARD");
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
},
};
var card = elements.create("card", {
style: style,
});
card.mount("#card-element");
card.on("change", ({ error }) => {
const displayError = document.getElementById("card-errors");
if (error) {
displayError.textContent = error.message;
} else {
displayError.textContent = "";
}
});
// end stripe
var form = document.getElementById("payment-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
// Tokenize card info
stripe
.createPaymentMethod({
type: "card",
card: card,
billing_details: {
// Include any additional collected billing details.
name: "Jenny Rosen",
email: "jenny@rosen.com",
},
})
.then(stripePaymentMethodHandler);
});
function stripePaymentMethodHandler(result) {
if (result.error) {
// Show error to user
console.log(result.error);
} else {
// Otherwise send payment method to your server
fetch("https://formspree.io/f/FORM_ID", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
// Send the tokenized card
paymentMethod: result.paymentMethod.id,
email: "jenny@rosen.com",
// add here any data that you want to send to Formspree
}),
}).then(function (result) {
// Handle server response
result.json().then(function (json) {
handleServerResponse(json);
});
});
}
}
function handleServerResponse(response) {
if (response.error) {
// Display errors on the payment form
console.log(response.error);
} else {
// Display a success message
console.log("Payment finished successfully");
}
}
});
Para dar estilo a tus elementos de Stripe, consulta este ejemplo, o nuestros estilos de reset de formulario de ejemplo aquí.
En este punto, tienes un formulario funcional que puede hacer cargos a titulares de tarjetas no europeos.
Paso 3: (Opcional) Soporte para pagos SCA
Después de completar el paso 2, tu formulario debería enviar correctamente y crear cargos en Stripe. Sin embargo, si el banco del remitente requiere SCA, el formulario generará un error. Para soportar SCA necesitamos agregar un paso más al flujo anterior.
En la primera solicitud, el servidor de Formspree intentará crear un Payment Intent y cobrarlo. Si la tarjeta requiere una acción adicional como SCA, el cargo fallará y el payment intent devolverá un status requires_action.
El servidor de Formspree devolverá una respuesta HTTP Status 402 con la siguiente información:
- El ID del payment intent creado
- Un client secret del payment intent que se usará para hacer una solicitud a Stripe para validar el pago
- Un
resubmit_keyque se usará para reenviar la solicitud a Formspree una vez que el pago haya sido validado
Ejemplo del cuerpo de respuesta
{
"message": "requires_action",
"resubmitKey": <key_generated_by_formspree>,
"stripe": {
"paymentIntentId": <id_from_the_payment_intent>,
"paymentIntentClientSecret": <secret_generated_by_stripe>,
"requiresAction": true
}
}
Ahora podemos validar el pago llamando a la función handleCardAction de Stripe, enviando el payment_intent_client_secret. Esto realizará cualquier validación de front-end requerida, como abrir el 3DS Modal para completar SCA.
El siguiente ejemplo demuestra cómo actualizar la función handleServerResponse() que creamos en el último paso para detectar cualquier acción requerida. Luego reenvía el formulario con el payment intent y un nuevo resubmit_key.
Ejemplo JS
function handleServerResponse(response) {
if (response.error) {
// Show error from server on payment form
console.log(response.error);
} else if (response && response.stripe.requiresAction) {
// Stripe require additional actions to charge this card
// Use Stripe.js to handle required card action and open 3DS
stripe
.handleCardAction(response.stripe.paymentIntentClientSecret)
.then(function (stripeResult) {
// TODO: implement this function to resubmit the form
resubmitForm(stripeResult, response.resubmitKey);
});
} else {
console.log("Payment finished successfully");
}
}
Modal 3DS de Stripe

Si la función handleCardAction tiene éxito, ahora puedes reenviar el formulario a Formspree enviando el resubmit_key y el paymentIntent que recibiste antes después del primer intento fallido.
Ejemplo de reenvío del formulario:
function resubmitForm(result, resubmitKey) {
console.log("handle Stripe SCA result");
if (result.error) {
// Show error in payment form
console.log("Stripe SCA error");
} else {
// The card action has been handled
// The PaymentIntent can be confirmed again on the server
fetch('https://formspree.io/f/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
paymentIntent: result.paymentIntent.id ,
resubmitKey: resubmitKey,
email: 'jenny@rosen.com',
})
}).then(function(result) {
return result.json();
}).then(handleServerResponse);
}
}
Cuando Formspree reciba el segundo envío, intentará nuevamente cobrar el payment intent con la información de la tarjeta que debería haber sido validada en el lado del cliente a través del flujo SCA de Stripe. Puedes reenviar los mismos campos del envío original. Cualquier cambio en estos campos actualizará los datos del formulario.
Ten en cuenta que el resubmit_key expirará si no se usa de manera oportuna. En este escenario, Formspree devolverá un código de respuesta HTTP 404.
Resumen
En resumen, los pasos son:
- Intentar cobrar la tarjeta. Si requiere SCA se devolverá una respuesta 402 con los datos del payment intent y la resubmit key.
- Llamar a Stripe handleCardAction con el client secret del payment intent devuelto del primer intento y hacer 3DS.
- Reenviar el formulario enviando la resubmit key, el payment intent id y el email. Formspree reintentará el cobro para finalizar el envío.
Echa un vistazo al flujo completo de checkout con SCA
Archivo JS (SCA)
$(document).ready(function () {
// Stripe settings
var stripe = Stripe("YOUR_PUBLISHABLE_KEY_COPIED_FROM_DASHBOARD");
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
},
};
var card = elements.create("card", {
style: style,
});
card.mount("#card-element");
card.on("change", ({ error }) => {
const displayError = document.getElementById("card-errors");
if (error) {
displayError.textContent = error.message;
} else {
displayError.textContent = "";
}
});
// end stripe
var form = document.getElementById("payment-form");
form.addEventListener("submit", function (ev) {
event.preventDefault();
stripe
.createPaymentMethod({
type: "card",
card: card,
billing_details: {
// Include any additional collected billing details.
name: "Jenny Rosen",
email: "jenny@rosen.com",
},
})
.then(stripePaymentMethodHandler);
});
function stripePaymentMethodHandler(result) {
if (result.error) {
console.log("Error creating payment method");
} else {
// First submission attempt
fetch("https://formspree.io/f/FORM_ID", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
paymentMethod: result.paymentMethod.id,
email: "jenny@rosen.com",
}),
}).then(function (response) {
// Handle server response (see Step 4)
response.json().then(function (json) {
handleServerResponse(json);
});
});
}
}
function handleServerResponse(response) {
if (response.stripe && response.stripe.requiresAction) {
// Stripe require additional actions to charge this card
// Use Stripe.js to handle required card action and open 3DS
stripe
.handleCardAction(response.stripe.paymentIntentClientSecret)
.then(function (stripeResult) {
// Get handleCardAction response and resubmit
resubmitForm(stripeResult, response.resubmitKey);
});
} else if (response.error) {
// Show error from server on payment form
console.log(response.error);
} else {
console.log("Payment finished successfully");
}
}
function resubmitForm(result, resubmitKey) {
console.log("handle Stripe SCA result");
if (result.error) {
// Display error in the payment form
console.log("Stripe SCA error");
} else {
// The card action has been handled
// The PaymentIntent can be confirmed again on the server
fetch("https://formspree.io/f/FORM_ID", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
paymentIntent: result.paymentIntent.id,
resubmitKey: resubmitKey,
email: "jenny@rosen.com",
}),
})
.then(function (confirmResult) {
return confirmResult.json();
})
.then(handleServerResponse);
}
}
});
Para leer más sobre pruebas con Stripe y Stripe SCA accede a https://stripe.com/docs/testing y nuestra publicación de blog.