# Acepta pagos con tarjeta sin webhooks Aprende a confirmar un pago con tarjeta en tu servidor y a gestionar las solicitudes de autenticación de tarjeta. # Web > This is a Web for when platform is web. View the full page at https://docs.stripe.com/payments/accept-a-payment-synchronously?platform=web. > Stripe recomienda utilizar el [Payment Element](https://docs.stripe.com/payments/quickstart-checkout-sessions.md) más nuevo en lugar de Card Element, lo que te permite aceptar distintos métodos de pago con un solo Element. Obtén más información sobre [cuándo usar Card Element y Payment Element](https://docs.stripe.com/payments/payment-card-element-comparison.md). Para tener más opciones de soporte y capacidad de corrección en el futuro, usa la [integración estándar](https://docs.stripe.com/payments/accept-a-payment.md) para pagos asincrónicos. Esta integración espera la respuesta del cliente y finaliza el pago en el servidor, sin usar *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) ni procesar eventos fuera de línea. Aunque pueda parecer más simple, esta integración es difícil de escalar a medida que tu negocio crece y presenta varias limitaciones: Si estás migrando la actual integración de Stripe desde la API Charges, sigue las instrucciones de la [guía de migración](https://docs.stripe.com/payments/payment-intents/migration.md). - **Solo acepta tarjetas**: tendrás que escribir más líneas de código para aceptar ACH y los métodos de pago regionales más utilizados por separado. - **Riesgo de duplicación del cargo**: al crearse un nuevo PaymentIntent de forma sincrónica cada vez que el cliente intenta pagar, corres el riesgo de cobrarle al cliente dos veces por error. Asegúrate de adoptar [prácticas recomendadas](https://docs.stripe.com/error-low-level.md#idempotency). - **Viaje adicional al cliente**: las tarjetas con 3D Secure o aquellas sujetas a normativas como la *Autenticación reforzada de clientes (SCA)* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) requieren pasos adicionales del lado del cliente. ​ Ten en cuenta estas limitaciones si decides usar esta integración. De lo contrario, usa la [integración estándar](https://docs.stripe.com/payments/accept-a-payment.md). ## Configurar Stripe Primero, necesitas una cuenta de Stripe. [Inscríbete ahora](https://dashboard.stripe.com/register). Usa nuestras bibliotecas oficiales para acceder a la API de Stripe desde tu aplicación: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ## Recopilar datos de tarjeta [Lado del cliente] Recopila los datos de tarjeta del lado del cliente con Stripe.js y Stripe Elements. Elements es un conjunto de componentes de interfaz de usuario prediseñados para recopilar y validar el número de tarjeta, el código postal y la fecha de vencimiento. Un Stripe Element contiene un iframe que envía la información del pago a Stripe en modo seguro a través de una conexión HTTPS. La dirección de la página de finalización de compra también debe empezar con https:// en lugar de http:// para que funcione tu integración. Puedes probar tu integración sin usar HTTPS. [Habilítala](https://docs.stripe.com/security/guide.md#tls) cuando todo esté listo para aceptar pagos reales. #### HTML + JS Incluye el script de [Stripe.js](https://docs.stripe.com/js.md) en el encabezado de cada página de tu sitio. Elements se encuentra disponible automáticamente como función de Stripe.js. ```html ``` Si incluyes el script en cada página de tu sitio, podrás sacar provecho de las [funcionalidades antifraude avanzadas](https://docs.stripe.com/radar.md) de Stripe y de la capacidad de detectar comportamientos anómalos en la navegación. ### Crear el formulario de pago Para recopilar los datos de tarjeta de tus clientes en modo seguro, Elements crea componentes de interfaz de usuario alojados en Stripe. Luego se colocan en tu formulario de pago como un iframe. Para determinar dónde insertar estos componentes, crea elementos DOM (contenedores) vacíos con ID únicos en tu formulario de pago. #### HTML ```html
``` A continuación, crea una instancia del [objeto Stripe](https://docs.stripe.com/js.md#stripe-function) suministrando tu [clave de API](https://docs.stripe.com/keys.md) publicable como primer parámetro. Luego, crea una instancia del [objeto Elements](https://docs.stripe.com/js.md#stripe-elements) y úsala para [montar](https://docs.stripe.com/js.md#element-mount) un elemento Card en el marcador de posición correspondiente en la página. ```javascript const stripe = Stripe('<>'); const elements = stripe.elements(); // Set up Stripe.js and Elements to use in checkout form const style = { base: { color: "#32325d", fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: "antialiased", fontSize: "16px", "::placeholder": { color: "#aab7c4" } }, invalid: { color: "#fa755a", iconColor: "#fa755a" }, }; const cardElement = elements.create('card', {style}); cardElement.mount('#card-element'); ``` El `card` Element simplifica el formulario de pago y minimiza la cantidad de campos obligatorios insertando un único campo de entrada flexible que recopila todos los datos necesarios de la tarjeta en modo seguro. De lo contrario, combina `cardNumber`, `cardExpiry` y `cardCvc` Elements para obtener un formulario de tarjeta de múltiples entradas flexible. > Recopila siempre el código postal para aumentar las tasas de aceptación de tarjetas y disminuir el fraude. > > El [Card Element de una sola línea](https://docs.stripe.com/js/element/other_element?type=card) recopila y envía automáticamente el código postal del cliente a Stripe. Si creas un formulario de pago con Elements divididos ([número de tarjeta](https://docs.stripe.com/js/element/other_element?type=cardNumber), [vencimiento](https://docs.stripe.com/js/element/other_element?type=cardExpiry), [CVC](https://docs.stripe.com/js/element/other_element?type=cardCvc)), agrega un campo de entrada separado para el código postal del cliente. ### Crear un PaymentMethod Por último, usa [stripe.createPaymentMethod](https://docs.stripe.com/js/payment_methods/create_payment_method) del lado de tu cliente para recopilar los datos de la tarjeta y crear un [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) en cuanto el usuario haga clic en el botón de envío. ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); const result = await stripe.createPaymentMethod({ type: 'card', card: cardElement, billing_details: { // Include any additional collected billing details. name: 'Jenny Rosen', }, }); stripePaymentMethodHandler(result); }); ``` #### React #### npm Instala [React Stripe.js](https://www.npmjs.com/package/@stripe/react-stripe-js) y el [cargador Stripe.js](https://www.npmjs.com/package/@stripe/stripe-js) desde el registro público npm. ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` #### umd También proporcionamos una versión de UMD para sitios que no usan npm ni módulos. Incluye el script de Stripe.js, que exporta la función global `Stripe`, y la versión de UMD de Stripe.js para React, que exporta el objeto global `ReactStripe`. Carga siempre el script de Stripe.js directamente desde **js.stripe.com** para cumplir con la normativa PCI. No lo incluyas en un paquete ni alojes una copia en tus sistemas. ```html ``` > La [demo en CodeSandbox](https://codesandbox.io/s/react-stripe-official-q1loc?fontsize=14&hidenavigation=1&theme=dark) te permite probar Stripe.js para React sin la necesidad de crear un nuevo proyecto. ### Agrega Stripe.js y Elements a tu página Para utilizar los componentes de Element, ajusta el componente de tu página de confirmación de compra en un [proveedor de Elements](https://docs.stripe.com/sdks/stripejs-react.md#elements-provider). Llama a `loadStripe` con tu clave publicable y especifica el valor `Promise` devuelto en el proveedor `Elements`. ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import {Elements} from '@stripe/react-stripe-js'; import {loadStripe} from '@stripe/stripe-js'; import CheckoutForm from './CheckoutForm'; // Make sure to call `loadStripe` outside of a component's render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('<>'); function App() { return ( ); }; ReactDOM.render(, document.getElementById('root')); ``` ### Agrega y configura un componente CardElement Utiliza componentes Element individuales, como `CardElement`, para crear tu formulario. #### JSX ```jsx /** * Use the CSS tab above to style your Element's container. */ import React from 'react'; import {CardElement} from '@stripe/react-stripe-js'; import './Styles.css' const CARD_ELEMENT_OPTIONS = { style: { base: { color: "#32325d", fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: "antialiased", fontSize: "16px", "::placeholder": { color: "#aab7c4", }, }, invalid: { color: "#fa755a", iconColor: "#fa755a", }, }, }; function CardSection() { return ( ); }; export default CardSection; ``` Elements es completamente personalizable. Puedes [diseñar Elements](https://docs.stripe.com/js/elements_object/create_element?type=card#elements_create-options) que hagan juego con tu sitio, lo que les brindará a tus clientes un proceso de compra sin inconvenientes. También es posible diseñar varios estados de entrada, por ejemplo, cuando el Element tiene foco. El `CardElement` simplifica el formulario y minimiza la cantidad de campos obligatorios insertando un único campo de entrada flexible que recopila todos los datos necesarios de la tarjeta y para la facturación en modo seguro. De lo contrario, combina `CardNumberElement`, `CardExpiryElement` y `CardCvcElement` en un formulario de tarjeta flexible de entrada múltiple. > Recopila siempre el código postal para aumentar las tasas de aceptación de tarjetas y disminuir el fraude. > > El [Card Element de una sola línea](https://docs.stripe.com/js/element/other_element?type=card) recopila y envía automáticamente el código postal del cliente a Stripe. Si creas un formulario de pago con Elements divididos ([número de tarjeta](https://docs.stripe.com/js/element/other_element?type=cardNumber), [vencimiento](https://docs.stripe.com/js/element/other_element?type=cardExpiry), [CVC](https://docs.stripe.com/js/element/other_element?type=cardCvc)), agrega un campo de entrada separado para el código postal del cliente. ### Crear un PaymentMethod En el controlador de envío del formulario de pago, usa [stripe.createPaymentMethod](https://docs.stripe.com/js/payment_methods/create_payment_method) para recopilar los datos de la tarjeta y crear un [PaymentMethod](https://docs.stripe.com/api/payment_methods.md). Para llamar a `stripe.createPaymentMethod` desde el componente de tu formulario de pago, utiliza los hooks [useStripe](https://docs.stripe.com/sdks/stripejs-react.md#usestripe-hook) y [useElements](https://docs.stripe.com/sdks/stripejs-react.md#useelements-hook). Si prefieres componentes de clase tradicionales en lugar de hooks, puedes usar un [ElementsConsumer](https://docs.stripe.com/sdks/stripejs-react.md#elements-consumer). #### Hooks ```jsx import React from 'react'; import {useStripe, useElements, CardElement} from '@stripe/react-stripe-js'; import CardSection from './CardSection'; export default function CheckoutForm() { const stripe = useStripe(); const elements = useElements(); const handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); if (!stripe || !elements) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; }const result = await stripe.createPaymentMethod({ type: 'card', card: elements.getElement(CardElement), billing_details: { // Include any additional collected billing details. name: 'Jenny Rosen', }, }); stripePaymentMethodHandler(result); }; return (
); } ``` #### Componentes de clase ```jsx import React from 'react'; import {ElementsConsumer, CardElement} from '@stripe/react-stripe-js'; import CardSection from './CardSection'; class CheckoutForm extends React.Component { handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); const {stripe, elements} = this.props if (!stripe || !elements) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; }const result = await stripe.createPaymentMethod({ type: 'card', card: elements.getElement(CardElement), billing_details: { // Include any additional collected billing details. name: 'Jenny Rosen', } }); stripePaymentMethodHandler(result); }; render() { const {stripe} = this.props; return (
); } } export default function InjectedCheckoutForm() { return ( {({stripe, elements}) => ( )} ); } ``` ## Envía el PaymentMethod a tu servidor [Lado del cliente] Si el *PaymentMethod* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) se creó correctamente, envía su ID a tu servidor. ```javascript const stripePaymentMethodHandler = async (result) => { if (result.error) { // Show error in payment form } else { // Otherwise send paymentMethod.id to your server (see Step 4) const res = await fetch('/pay', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ payment_method_id: result.paymentMethod.id, }), }) const paymentResponse = await res.json(); // Handle server response (see Step 4) handleServerResponse(paymentResponse); } } ``` ## Crear un PaymentIntent [Lado del servidor] Configura un punto de conexión en tu servidor para recibir la solicitud. Este punto de conexión también se utilizará [más adelante](https://docs.stripe.com/payments/accept-a-payment-synchronously.md#confirm-payment) para gestionar las tarjetas que requieran un paso adicional de autenticación. [Crea un nuevo PaymentIntent](https://docs.stripe.com/payments/payment-intents.md#creating-a-paymentintent) con la ID del [PaymentMethod](https://docs.stripe.com/api/payment_methods/object.md) creado en el cliente. Puedes *confirmar* (Confirming a PaymentIntent indicates that the customer intends to pay with the current or provided payment method. Upon confirmation, the PaymentIntent attempts to initiate a payment) el PaymentIntent estableciendo la propiedad [confirm](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-confirm) como “true” al crear el PaymentIntent o llamando a [confirm](https://docs.stripe.com/api/payment_intents/confirm.md) después de su creación. También se admite [Separar la autorización de la captura](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method.md) con pagos con tarjeta. Si el pago requiere otras acciones, como autenticación con 3D Secure, el estado del PaymentIntent se establecerá en `requires_action`. Si el pago falla, el estado vuelve a ser `requires_payment_method` y debes mostrarle un mensaje de error al usuario. Si el pago no requiere ninguna autenticación adicional, se crea un cargo y el estado del PaymentIntent se establece en `succeeded`. > En las versiones de la API anteriores al [2019-02-11](https://docs.stripe.com/upgrades.md#2019-02-11), `requires_payment_method` aparece como `requires_source` y `requires_action` aparece como `requires_source_action`. #### curl ```bash curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -d "payment_method"="{{PAYMENT_METHOD_ID}}" \ -d "amount"=1099 \ -d "currency"="usd" \ -d "confirmation_method"="manual" \ -d "confirm"="true" ``` Si quieres guardar la tarjeta para volver a utilizarla más adelante, crea un objeto [Customer](https://docs.stripe.com/api/customers/create.md) para almacenar el *PaymentMethod* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) y especifica estos otros parámetros al crear el PaymentIntent: - [cliente](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer). Establecido en el ID del objeto *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments). - [setup_future_usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage). Se establece en `off_session` para informarle a Stripe que planeas reutilizar este PaymentMethod para *pagos fuera de la sesión* (A payment is described as off-session if it occurs without the direct involvement of the customer, using previously-collected payment information) cuando tu cliente no esté presente. Establecer esta propiedad guarda el PaymentMethod en Customer después de que se confirma la PaymentIntent y se completan las acciones necesarias del usuario. Consulta el ejemplo de código sobre [cómo guardar tarjetas después de un pago](https://github.com/stripe-samples/saving-card-after-payment/tree/master/without-webhooks) para obtener más información. ## Gestionar las siguientes acciones [Lado del cliente] Escribe código para gestionar situaciones que requieran la intervención de tu cliente. Normalmente, un pago se efectiviza después de que lo confirmas en el servidor en el [paso 4](https://docs.stripe.com/payments/accept-a-payment-synchronously.md#create-payment-intent). Sin embargo, cuando el PaymentIntent requiere otra acción de parte del cliente, como autenticar con *3D Secure* (3D Secure (3DS) provides an additional layer of authentication for credit card transactions that protects businesses from liability for fraudulent card payments), este código interviene. Usa [stripe.handleCardAction](https://docs.stripe.com/js/payment_intents/handle_card_action) para activar la interfaz de usuario con el fin de gestionar la acción del cliente. Si la autenticación se realiza correctamente, el estado del PaymentIntent es `requires_confirmation`. Confirma el PaymentIntent otra vez en tu servidor para finalizar el pago. Mientras realices pruebas, usa un [número de tarjeta de prueba](https://docs.stripe.com/testing.md#regulatory-cards) que requiera autenticación (por ejemplo, 4000002760003184) para forzar ese flujo. Si usas una tarjeta que no necesita autenticación (por ejemplo, 4242424242424242), se omite esta parte del flujo y la operación finaliza en el paso 4. ```javascript const handleServerResponse = async (response) => { if (response.error) { // Show error from server on payment form } else if (response.requires_action) { // Use Stripe.js to handle the required card action const { error: errorAction, paymentIntent } = await stripe.handleCardAction(response.payment_intent_client_secret); if (errorAction) { // Show error from Stripe.js in payment form } else { // The card action has been handled // The PaymentIntent can be confirmed again on the server const serverResponse = await fetch('/pay', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ payment_intent_id: paymentIntent.id }) }); handleServerResponse(await serverResponse.json()); } } else { // Show success message } } ``` > `stripe.handleCardAction` puede tardar varios segundos en completarse. Durante ese tiempo, deshabilita el formulario para evitar que se envíe nuevamente y muestra un indicador de espera, como un indicador giratorio. Si se produce un error, muéstralo al cliente, vuelve a habilitar el formulario y oculta el indicador de espera. Si el cliente necesita realizar pasos adicionales para completar el pago, como la autenticación, Stripe.js lo guía a través de ese proceso. ## Confirmar el PaymentIntent nuevamente [Lado del servidor] Este código solo se ejecuta cuando un pago requiere autenticación adicional, tal como se hizo en el paso anterior. El código en sí no es opcional porque cualquier pago puede requerir este paso extra. Utilizando el mismo punto de conexión que configuraste [arriba](https://docs.stripe.com/payments/accept-a-payment-synchronously.md#create-payment-intent), *confirma* (Confirming an intent indicates that the customer intends to use the current or provided payment method. Upon confirmation, the intent attempts to initiate the portions of the flow that have real-world side effects) el PaymentIntent nuevamente para finalizar el pago y *completar* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) el pedido. Cerciórate de que esta confirmación se produzca en el término de una hora a partir del intento de pago. De lo contrario, el pago fallará y volverá a `requires_payment_method`. #### curl ```bash curl https://api.stripe.com/v1/payment_intents/{{PAYMENT_INTENT_ID}}/confirm \ -u <>: \ -X "POST" ``` ## Probar la integración ​​Dispones de varias tarjetas de prueba que puedes usar en un entorno de prueba para verificar que la integración esté lista. Úsalas con cualquier CVC y una fecha de vencimiento futura. | Número | Descripción | | ---------------- | -------------------------------------------------------------------------------------------------------------- | | 4242424242424242 | La transacción se realiza con éxito y se procesa el pago de inmediato. | | 4000002500003155 | Exige autenticación. Stripe activa un cuadro de diálogo que le solicita al cliente completar la autenticación. | | 4000000000009995 | Siempre da error con un código de rechazo `insufficient_funds`. | Para ver la lista completa de tarjetas de prueba, consulta nuestra guía sobre [pruebas](https://docs.stripe.com/testing.md). ## Optional: Volver a pedir el CVC When creating subsequent payments on a saved card, you might want to re-collect the CVC of the card as an additional fraud measure to verify the user. Empieza por [enumerar](https://docs.stripe.com/api/payment_methods/list.md) los métodos de pago asociados a tu *cliente* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) para determinar cuáles le mostrarás para volver a recopilar el CVC. En el cliente, usa el `cardCvc` Element para volver a recopilar el valor del CVC del usuario para uno de los métodos de pago y luego tokeniza los datos del CVC usando [stripe.createToken](https://docs.stripe.com/js/tokens/create_token?type=cvc_update). Después de enviar el token del CVC a tu servidor, crea un PaymentIntent en tu servidor con el importe, la moneda y el token del CVC en el parámetro `payment_method_options[card][cvc_token]`. Como sucede con todos los demás tokens, los tokens de CVC no se pueden usar más de una vez, por lo que cada PaymentIntent debe usar su propio token de CVC único. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d payment_method={{PAYMENT_METHOD_ID}} \ -d customer={{CUSTOMER_ID}} \ -d amount=1099 \ -d currency=usd \ -d confirmation_method=manual \ -d confirm=true \ -d "payment_method_options[card][cvc_token]={{CVC_TOKEN_ID}}" ``` A payment might succeed even with a failed CVC check. To prevent this, configure your [Radar rules](https://docs.stripe.com/radar/rules.md#traditional-bank-checks) to block payments when CVC verification fails. # iOS > This is a iOS for when platform is ios. View the full page at https://docs.stripe.com/payments/accept-a-payment-synchronously?platform=ios. Para tener más opciones de soporte y capacidad de corrección en el futuro, usa la [integración estándar](https://docs.stripe.com/payments/accept-a-payment.md) para pagos asincrónicos. Esta integración utiliza un único flujo del cliente al servidor para procesar pagos, sin usar *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) ni procesar eventos fuera de línea. Aunque pueda parecer más simple, esta integración es difícil de escalar a medida que tu negocio crece y presenta varias limitaciones: - **Solo acepta tarjetas**: tendrás que escribir más líneas de código para aceptar ACH y los métodos de pago regionales más utilizados por separado. - **Riesgo de duplicación del cargo**: al crearse un nuevo PaymentIntent de forma sincrónica cada vez que el cliente intenta pagar, corres el riesgo de cobrarle al cliente dos veces por error. Asegúrate de adoptar [prácticas recomendadas](https://docs.stripe.com/error-low-level.md#should-retry). - **Gestión manual de autenticación**: las tarjetas con 3D Secure o sujetas a requisitos normativos, como la *Autenticación reforzada de clientes (SCA)* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase), exigen que el cliente complete pasos adicionales. Ten en cuenta estas limitaciones si decides usar esta integración. De lo contrario, usa la [integración estándar](https://docs.stripe.com/payments/accept-a-payment.md). ## Configurar Stripe [Lado del cliente] [Lado del servidor] Primero, necesitas una cuenta de Stripe. [Inscríbete ahora](https://dashboard.stripe.com/register). ### Lado del servidor Esta integración necesita puntos de conexión en tu servidor que se comuniquen con la API de Stripe. Usa nuestras bibliotecas oficiales para acceder a la API de Stripe desde tu servidor: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ### Lado del cliente El [SDK para iOS de Stripe](https://github.com/stripe/stripe-ios) es de código abierto, está [plenamente documentado](https://stripe.dev/stripe-ios/index.html) y es compatible con aplicaciones que admiten iOS 13 o posterior. #### Swift Package Manager Para instalar el SDK, sigue estos pasos: 1. En Xcode, selecciona **Archivo** > **Agregar dependencias de paquetes…** e introduce `https://github.com/stripe/stripe-ios-spm` como URL del repositorio. 1. Selecciona el número de versión más reciente en nuestra [página de versiones](https://github.com/stripe/stripe-ios/releases). 1. Agrega el producto **StripePaymentsUI** al [objetivo de tu aplicación](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app). #### CocoaPods 1. Si aún no lo has hecho, instala la última versión de [CocoaPods](https://guides.cocoapods.org/using/getting-started.html). 1. Si no tienes un [Podfile](https://guides.cocoapods.org/syntax/podfile.html), crea uno al ejecutar el siguiente comando: ```bash pod init ``` 1. Agrega esta línea a tu `Podfile`: ```podfile pod 'StripePaymentsUI' ``` 1. Ejecuta el siguiente comando: ```bash pod install ``` 1. De ahora en adelante, no olvides usar el archivo `.xcworkspace` en lugar del archivo `.xcodeproj` para abrir tu proyecto en Xcode. 1. En el futuro, para actualizar a la última versión del SDK, ejecuta lo siguiente: ```bash pod update StripePaymentsUI ``` #### Carthage 1. Si aún no lo has hecho, instala la última versión de [Carthage](https://github.com/Carthage/Carthage#installing-carthage). 1. Agrega esta línea a tu `Cartfile`: ```cartfile github "stripe/stripe-ios" ``` 1. Sigue las [instrucciones de instalación de Carthage](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos). Asegúrate de incrustar todos los frameworks obligatorios enumerados [aquí](https://github.com/stripe/stripe-ios/tree/master/StripePaymentsUI/README.md#manual-linking). 1. En el futuro, para actualizar a la última versión del SDK, ejecuta el siguiente comando: ```bash carthage update stripe-ios --platform ios ``` #### Framework manual 1. Ve a nuestra [página de versiones de GitHub](https://github.com/stripe/stripe-ios/releases/latest) y descarga y descomprime **Stripe.xcframework.zip**. 1. Arrastra **StripePaymentsUI.xcframework** a la sección **Binarios incrustados** de la configuración **General** de tu proyecto en Xcode. Asegúrate de seleccionar **Copiar elementos si es necesario**. 1. Repite el paso 2 para todos los frameworks obligatorios enumerados [aquí](https://github.com/stripe/stripe-ios/tree/master/StripePaymentsUI/README.md#manual-linking). 1. En el futuro, para actualizar a la última versión de nuestro SDK, repite los pasos 1 a 3. > Para obtener más detalles sobre la última versión del SDK y las versiones anteriores, consulta la página [Versiones](https://github.com/stripe/stripe-ios/releases) en GitHub. Para recibir notificaciones cuando se publique una nueva versión, [mira las versiones](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository) del repositorio. Configura el SDK con tu [clave publicable](https://dashboard.stripe.com/test/apikeys) de Stripe al iniciar la aplicación. Esto permite que tu aplicación haga solicitudes a la API de Stripe. #### Swift ```swift import UIKitimportStripePaymentsUI @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {StripeAPI.defaultPublishableKey = "<>" // do any other necessary launch configuration return true } } ``` > Usa las [claves de prueba](https://docs.stripe.com/keys.md#obtain-api-keys) durante las pruebas y el desarrollo, y tus claves para [modo activo](https://docs.stripe.com/keys.md#test-live-modes) cuando publiques tu aplicación. ## Crea tu pantalla de finalización de compra [Lado del cliente] Recopila los datos de la tarjeta del cliente de manera segura con [STPPaymentCardTextField](https://stripe.dev/stripe-ios/stripe-payments-ui/Classes/STPPaymentCardTextField.html), un componente de interfaz de usuario (IU) insertable proporcionado por el SDK que recopila el número de la tarjeta, la fecha de vencimiento, el CVC y el código postal. ![](https://d37ugbyn3rpeym.cloudfront.net/docs/mobile/ios/card-field.mp4) Crea una instancia del componente de tarjeta y un botón “Pagar” con el siguiente código: #### Swift ```swift import UIKit import StripePaymentsUI class CheckoutViewController: UIViewController { lazy var cardTextField: STPPaymentCardTextField = { let cardTextField = STPPaymentCardTextField() return cardTextField }() lazy var payButton: UIButton = { let button = UIButton(type: .custom) button.layer.cornerRadius = 5 button.backgroundColor = .systemBlue button.titleLabel?.font = UIFont.systemFont(ofSize: 22) button.setTitle("Pay", for: .normal) button.addTarget(self, action: #selector(pay), for: .touchUpInside) return button }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white let stackView = UIStackView(arrangedSubviews: [cardTextField, payButton]) stackView.axis = .vertical stackView.spacing = 20 stackView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(stackView) NSLayoutConstraint.activate([ stackView.leftAnchor.constraint(equalToSystemSpacingAfter: view.leftAnchor, multiplier: 2), view.rightAnchor.constraint(equalToSystemSpacingAfter: stackView.rightAnchor, multiplier: 2), stackView.topAnchor.constraint(equalToSystemSpacingBelow: view.topAnchor, multiplier: 2), ]) } @objc func pay() { // ... } } ``` Ejecuta tu aplicación y constata que tu página de finalización de compra muestre el componente de tarjeta y el botón de pago. ## Recopilar datos de tarjeta [Lado del cliente] Cuando tu cliente esté listo para finalizar el proceso de compra, crea un *PaymentMethod* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) con los datos recopilados por el elemento tarjeta. #### Swift ```swift class CheckoutViewController: UIViewController { // ... @objc func pay() { // Collect card details on the client STPAPIClient.shared.createPaymentMethod(with: cardTextField.paymentMethodParams) { [weak self] paymentMethod, error in // Create PaymentMethod failed if let createError = error { self?.displayAlert(title: "Payment failed", message: createError.localizedDescription) } if let paymentMethodId = paymentMethod?.stripeId { self?.pay(withPaymentMethod: paymentMethodId) } } } func pay(withPaymentMethod paymentMethodId: String? = nil, withPaymentIntent paymentIntentId: String? = nil) { // ...continued in the next step } // ... } ``` ## Crear un PaymentIntent [Lado del cliente] [Lado del servidor] Stripe utiliza un objeto `PaymentIntent` para representar tu intención de cobrarle a un cliente y hace el seguimiento de los intentos de cobro y de los cambios en el estado del pago a lo largo del proceso. ### En el servidor Agrega un punto de conexión que cree el PaymentIntent con los siguientes parámetros: - [payment_method_id](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method): la ID del PaymentMethod del paso anterior - [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url): debe incluirse si se ha [configurado una URL de retorno](https://docs.stripe.com/payments/3d-secure.md) - [use_stripe_sdk](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-use_stripe_sdk) - Para aplicaciones que se integren con el [SDK para iOS de Stripe v16.0.0](https://github.com/stripe/stripe-ios/blob/master/CHANGELOG.md#1600-2019-07-18) o superior, el valor de este parámetro debe establecerse en `true` - Para aplicaciones que se integren con versiones anteriores del SDK, **no especifiques este parámetro** - [confirmar](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-confirm): establece este valor en “verdadero” para *confirmar* (Confirming a PaymentIntent indicates that the customer intends to pay with the current or provided payment method. Upon confirmation, the PaymentIntent attempts to initiate a payment) el PaymentIntent Si quieres guardar la tarjeta para volver a utilizarla más adelante, crea un objeto [Customer](https://docs.stripe.com/api/customers/create.md) para almacenar el PaymentMethod y especifica estos otros parámetros al crear el PaymentIntent: - [cliente](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer): establecido en el ID del objeto *Customer* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments). - [setup_future_usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage): establecido en `off_session` para indicar a Stripe que planeas reutilizar este PaymentMethod para *pagos fuera de la sesión* (A payment is described as off-session if it occurs without the direct involvement of the customer, using previously-collected payment information) sin la presencia del cliente. Si se define esta propiedad, el PaymentMethod se guarda en el objeto Customer después de la confirmación del PaymentIntent y de que el usuario completa las acciones solicitadas. Después de crear el PaymentIntent, devuelve lo siguiente al cliente: - el [secreto de cliente](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) del PaymentIntent - `requiresAction: true` si el [estado](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-status) del PaymentIntent es `requires_action` > Mira un [ejemplo de la implementación de servidor](https://github.com/stripe-samples/accept-a-payment/tree/master/custom-payment-flow/server). ### En el cliente Solicita un `PaymentIntent` desde tu servidor. Este ejemplo especifica al servidor una lista de ítems para determinar el precio. Decide cuánto cobrar siempre del lado del servidor, un entorno de confianza, no del lado del cliente. Esto impide que clientes maliciosos puedan elegir sus propios precios. #### Swift ```swift let BackendUrl = "http://127.0.0.1:4242/" class CheckoutViewController: UIViewController { // ... func displayAlert(title: String, message: String, restartDemo: Bool = false) { // ...omitted for brevity } func pay(withPaymentMethod paymentMethodId: String? = nil, withPaymentIntent paymentIntentId: String? = nil) { // Create a PaymentIntent on the server let url = URL(string: BackendUrl + "pay")! var json: [String: Any] = [:] if let paymentMethodId = paymentMethodId { json = [ "useStripeSdk": true, "paymentMethodId": paymentMethodId, "currency": "usd", "items": [ "id": "photo_subscription" ] ] } else if let paymentIntentId = paymentIntentId { json = [ "paymentIntentId": paymentIntentId, ] } var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try? JSONSerialization.data(withJSONObject: json) let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, requestError) in guard let response = response as? HTTPURLResponse, response.statusCode == 200, let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] else { self?.displayAlert(title: "Payment failed", message: requestError?.localizedDescription ?? "") return } let payError = json["error"] as? String let clientSecret = json["clientSecret"] as? String let requiresAction = json["requiresAction"] as? Bool // Payment failed if let payError = payError { self?.displayAlert(title: "Payment failed", message: payError) } // Payment succeeded, no additional action required else if clientSecret != nil && (requiresAction == nil || requiresAction == false) { self?.displayAlert(title: "Payment succeeded", message: clientSecret ?? "", restartDemo: true) } // Payment requires additional action else if clientSecret != nil && requiresAction == true && self != nil { // ...continued in the next step } }) task.resume() } } ``` ## Gestionar las siguientes acciones [Lado del cliente] Escribe código para gestionar situaciones que requieran la intervención de tu cliente. Normalmente, un pago se efectiviza después de que lo confirmas en el servidor en el [paso 4](https://docs.stripe.com/payments/accept-a-payment-synchronously.md#ios-create-payment-intent). Sin embargo, cuando el PaymentIntent requiere otra acción de parte del cliente, como autenticar con *3D Secure* (3D Secure (3DS) provides an additional layer of authentication for credit card transactions that protects businesses from liability for fraudulent card payments), este código interviene. En estos casos, el estado del PaymentIntent se establece en `requires_action`. En el cliente, especifica el ID del PaymentIntent en [STPPaymentHandler handleNextActionForPayment](https://stripe.dev/stripe-ios/stripe-payments/Classes/STPPaymentHandler.html#/c:@M@StripePayments@objc\(cs\)STPPaymentHandler\(im\)handleNextActionForPayment:withAuthenticationContext:returnURL:completion:). `STPPaymentHandler` presenta controladores de vista con el [STPAuthenticationContext](https://stripe.dev/stripe-ios/stripe-payments/Protocols/STPAuthenticationContext.html) especificado y guía al cliente durante la autenticación. Para obtener más detalles, lee sobre la [autenticación con 3D Secure en iOS](https://docs.stripe.com/payments/3d-secure.md?platform=ios). Después de gestionar las acciones necesarias de lado del cliente, el estado del PaymentIntent cambia a `requires_confirmation`. Este paso habilita a tu integración a *completar* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) el pedido en tu back-end de manera sincrónica y enviar el resultado de esta operación al cliente. Envía el ID del PaymentIntent a tu back-end y confírmalo nuevamente en el término de una hora para finalizar el pago. De lo contrario, falla el intento de pago y vuelve a `requires_payment_method`. #### Swift ```swift class CheckoutViewController: UIViewController { // ... // Create or confirm a PaymentIntent on the server func pay(withPaymentMethod paymentMethodId: String? = nil, withPaymentIntent paymentIntentId: String? = nil) { // ... // Payment requires additional action else if clientSecret != nil && requiresAction == true && self != nil { let paymentHandler = STPPaymentHandler.shared() paymentHandler.handleNextAction(forPayment: clientSecret!, with: self!, returnURL: nil) { status, paymentIntent, handleActionError in switch (status) { case .failed: self?.displayAlert(title: "Payment failed", message: handleActionError?.localizedDescription ?? "") break case .canceled: self?.displayAlert(title: "Payment canceled", message: handleActionError?.localizedDescription ?? "") break case .succeeded: if let paymentIntent = paymentIntent, paymentIntent.status == STPPaymentIntentStatus.requiresConfirmation { print("Re-confirming PaymentIntent after handling action") self?.pay(withPaymentIntent: paymentIntent.stripeId) } else { self?.displayAlert(title: "Payment succeeded", message: paymentIntent?.description ?? "", restartDemo: true) } break @unknown default: fatalError() break } } } // ... } } extension CheckoutViewController: STPAuthenticationContext { func authenticationPresentingViewController() -> UIViewController { return self } } ``` ## Probar la integración ​​Dispones de varias tarjetas de prueba que puedes usar en un entorno de prueba para verificar que la integración esté lista. Úsalas con cualquier CVC y una fecha de vencimiento futura. | Número | Descripción | | ---------------- | -------------------------------------------------------------------------------------------------------------- | | 4242424242424242 | La transacción se realiza con éxito y se procesa el pago de inmediato. | | 4000002500003155 | Exige autenticación. Stripe activa un cuadro de diálogo que le solicita al cliente completar la autenticación. | | 4000000000009995 | Siempre da error con un código de rechazo `insufficient_funds`. | Para ver la lista completa de tarjetas de prueba, consulta nuestra guía sobre [pruebas](https://docs.stripe.com/testing.md). ## Optional: Volver a pedir el CVC When creating subsequent payments on a saved card, you might want to re-collect the CVC of the card as an additional fraud measure to verify the user. Empieza por [enumerar](https://docs.stripe.com/api/payment_methods/list.md) los métodos de pago asociados a tu *cliente* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) para determinar cuáles le mostrarás para volver a recopilar el CVC. Después de volver a recopilar los datos del CVC del cliente, tokeniza los datos usando [STPAPIClient createTokenForCVCUpdate](https://stripe.dev/stripe-ios/stripe-payments/Classes/STPAPIClient.html#/c:@CM@StripePayments@StripeCore@objc\(cs\)STPAPIClient\(im\)createTokenForCVCUpdate:completion:). #### Swift ```swift import UIKit import StripePaymentsUI class CheckoutViewController: UIViewController { // ... func tokenizeCVC() { guard let cvc = cvc else { return; } STPAPIClient.shared.createToken(forCVCUpdate: cvc) { (token, error) in if error != nil || token == nil { // handle error } else { let tokenId = token?.tokenId // pass the token ID to your backend } } } // ... } ``` Después de enviar el token del CVC a tu servidor, crea un PaymentIntent en tu servidor con el importe, la moneda y el token del CVC en el parámetro `payment_method_options[card][cvc_token]`. ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d payment_method={{PAYMENT_METHOD_ID}} \ -d customer={{CUSTOMER_ID}} \ -d amount=1099 \ -d currency=usd \ -d confirmation_method=manual \ -d confirm=true \ -d "payment_method_options[card][cvc_token]={{CVC_TOKEN_ID}}" ``` A payment might succeed even with a failed CVC check. To prevent this, configure your [Radar rules](https://docs.stripe.com/radar/rules.md#traditional-bank-checks) to block payments when CVC verification fails. ## See also - [Aceptar Apple Pay](https://docs.stripe.com/apple-pay.md) # Android > This is a Android for when platform is android. View the full page at https://docs.stripe.com/payments/accept-a-payment-synchronously?platform=android. Para tener más opciones de soporte y capacidad de corrección en el futuro, usa la [integración estándar](https://docs.stripe.com/payments/accept-a-payment.md) para pagos asincrónicos. Esta integración utiliza un único flujo del cliente al servidor para procesar pagos, sin usar *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) ni procesar eventos fuera de línea. Aunque pueda parecer más simple, esta integración es difícil de escalar a medida que tu negocio crece y presenta varias limitaciones: - **Solo acepta tarjetas**: tendrás que escribir más líneas de código para aceptar ACH y los métodos de pago regionales más utilizados por separado. - **Riesgo de duplicación del cargo**: al crearse un nuevo PaymentIntent de forma sincrónica cada vez que el cliente intenta pagar, corres el riesgo de cobrarle al cliente dos veces por error. Asegúrate de adoptar [prácticas recomendadas](https://docs.stripe.com/error-low-level.md#should-retry). - **Gestión manual de autenticación**: las tarjetas con 3D Secure o sujetas a requisitos normativos, como la *Autenticación reforzada de clientes (SCA)* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase), exigen que el cliente complete pasos adicionales. Ten en cuenta estas limitaciones si decides usar esta integración. De lo contrario, usa la [integración estándar](https://docs.stripe.com/payments/accept-a-payment.md). ## Configurar Stripe [Lado del cliente] [Lado del servidor] Primero, necesitas una cuenta de Stripe. [Inscríbete ahora](https://dashboard.stripe.com/register). ### Lado del servidor Esta integración necesita puntos de conexión en tu servidor que se comuniquen con la API de Stripe. Usa nuestras bibliotecas oficiales para acceder a la API de Stripe desde tu servidor: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ### Lado del cliente El [SDK para Android de Stripe](https://github.com/stripe/stripe-android) es de código abierto y está [completamente documentado](https://stripe.dev/stripe-android/). Para instalar el SDK, agrega `stripe-android` al bloque `dependencies` de tu archivo [app/build.gradle](https://developer.android.com/studio/build/dependencies): #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Stripe Android SDK implementation("com.stripe:stripe-android:23.2.0") // Include the financial connections SDK to support US bank account as a payment method implementation("com.stripe:financial-connections:23.2.0") } ``` > Para conocer detalles de la última versión y de versiones anteriores del SDK, consulta la página [Versiones](https://github.com/stripe/stripe-android/releases) en GitHub. Para recibir una notificación cuando se publique una nueva versión, [mira las versiones del repositorio](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). Configura el SDK con tu [clave publicable](https://dashboard.stripe.com/apikeys) de Stripe para que pueda hacer solicitudes a la API de Stripe, así como en tu subclase `Application`: #### Kotlin ```kotlin import com.stripe.android.PaymentConfiguration class MyApp : Application() { override fun onCreate() { super.onCreate() PaymentConfiguration.init( applicationContext, "<>" ) } } ``` > Usa las [claves de prueba](https://docs.stripe.com/keys.md#obtain-api-keys) durante las pruebas y el desarrollo, y tus claves para [modo activo](https://docs.stripe.com/keys.md#test-live-modes) cuando publiques tu aplicación. Nuestros ejemplos de código también utilizan [OkHttp](https://github.com/square/okhttp) y [GSON](https://github.com/google/gson) para hacer solicitudes HTTP a un servidor. ## Crea tu pantalla de compra [Lado del cliente] Recopila los datos de la tarjeta del cliente de manera segura con [CardInputWidget](https://stripe.dev/stripe-android/payments-core/com.stripe.android.view/-card-input-widget/index.html), un componente de interfaz de usuario (IU) proporcionado por el SDK que recopila el número de a la tarjeta, la fecha de vencimiento, el CVC y el código postal. ![](https://d37ugbyn3rpeym.cloudfront.net/docs/mobile/android/android-card-input-widget-with-postal.mp4) Crea una instancia del componente de tarjeta y un botón “Pagar” agregando lo siguiente al diseño de tu página de finalización de compra: ```xml