# Usar Stripe para aceptar pagos con SCA

> Formspree Docs · Plugins · 28 de febrero de 2026

#### 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](https://stripe.com/docs/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](https://stripe.com/docs/strong-customer-authentication#impact) a pagos en línea donde el banco del cliente y el negocio están ambos en el [Espacio Económico Europeo](https://en.wikipedia.org/wiki/European_Economic_Area) (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](https://stripe.com/docs/testing).
-   Algunos métodos de pago que usan [Sources](https://stripe.com/docs/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](https://stripe.com/docs/testing#disputes) más simple.
-   En test mode, los [webhooks](https://stripe.com/docs/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

  
![mceclip0.png](/images/zendesk/9479210aa8c1e005.png)

_**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.

![mceclip0.png](/images/zendesk/e61d8f0b2e0b9e6c.png)

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.

![mceclip4.png](/images/zendesk/ac89283388ab406b.png)

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.**_

![mceclip0.png](/images/zendesk/f97e2f49dac06df8.png)

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:

![mceclip1.png](/images/zendesk/e07fed14e1716088.png)

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](https://formspree.io/blog/custom-payment-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](https://stripe.com/payments/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](https://stripe.com/docs/payments/accept-a-payment-synchronously):

**Archivo HTML**

```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**

```javascript
$(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](https://gist.github.com/colevscode/9cf19623e157cbe6822ffb8bd6e707fb), o nuestros estilos de reset de formulario de ejemplo [aquí](https://gist.github.com/colevscode/ce67075b62f843b7e95b1d5a1370035b).

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](https://stripe.com/docs/payments/payment-intents) 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_key` que se usará para reenviar la solicitud a Formspree una vez que el pago haya sido validado

#### **Ejemplo del cuerpo de respuesta**

```javascript
{
  "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](https://stripe.com/docs/js/payment_intents/handle_card_action) de Stripe, enviando el `payment_intent_client_secret`. Esto realizará cualquier validación de front-end requerida, como abrir el [3DS Modal](https://stripe.com/docs/payments/3d-secure) 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**

```javascript
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**

![mceclip2.png](/images/zendesk/dcb1c309939d07c1.png)

Si la función [handleCardAction](https://stripe.com/docs/js/payment_intents/handle_card_action) 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:**

```javascript
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:

1.  Intentar cobrar la tarjeta. Si requiere SCA se devolverá una respuesta 402 con los datos del payment intent y la resubmit key.
2.  Llamar a Stripe handleCardAction con el client secret del payment intent devuelto del primer intento y hacer [3DS](https://stripe.com/docs/payments/3d-secure).
3.  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)**

```javascript
$(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](https://stripe.com/docs/testing) y nuestra [publicación de blog](https://formspree.io/blog/custom-payment-stripe/).
