# 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.

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.

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
```
Ejecuta tu aplicación y constata que tu pantalla 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.
#### Kotlin
```kotlin
class CheckoutActivity : AppCompatActivity() {
private lateinit var stripe: Stripe
// ...
private fun pay() {
val weakActivity = WeakReference(this)
// Collect card details on the client
val cardInputWidget =
findViewById(R.id.cardInputWidget)
val params = cardInputWidget.paymentMethodCreateParams
if (params == null) {
return
}
// Configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API
stripe = Stripe(applicationContext, PaymentConfiguration.getInstance(applicationContext).publishableKey)
lifecycleScope.launch {
runCatching {
stripe.createPaymentMethod(params)
}.fold(
onSuccess = { result ->
// Create a PaymentIntent on the server with a PaymentMethod
print("Created PaymentMethod")
pay(result.id, null)
},
onFailure = {
displayAlert(weakActivity.get(), "Payment failed", "Error: $it")
}
)
}
}
private fun pay(paymentMethod: String?, paymentIntent: String?) {
// ...
}
}
```
## 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
- [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 Android de Stripe v10.0.0](https://github.com/stripe/stripe-android/blob/master/CHANGELOG.md#1000---2019-07-19) y versiones posteriores, 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, le devuelve al cliente lo siguiente:
- 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.
#### Kotlin
```kotlin
class CheckoutActivity : AppCompatActivity() {
private val backendUrl = "http://10.0.2.2:4242/"
private val httpClient = OkHttpClient()
private fun displayAlert(activity: Activity?, title: String, message: String, restartDemo: Boolean = false) {
// omitted for brevity
}
private fun pay(paymentMethod: String?, paymentIntent: String?) {
val weakActivity = WeakReference(this)
var json = ""
if (!paymentMethod.isNullOrEmpty()) {
json = """
{
"useStripeSdk":true,
"paymentMethodId":"$paymentMethod",
"currency":"usd",
"items": [
{"id":"photo_subscription"}
]
}
"""
}
else if (!paymentIntent.isNullOrEmpty()) {
json = """
{
"paymentIntentId":"$paymentIntent"
}
"""
}
// Create a PaymentIntent on the server
val mediaType = "application/json; charset=utf-8".toMediaType()
val body = json.toRequestBody(mediaType)
val request = Request.Builder()
.url(backendUrl + "pay")
.post(body)
.build()
httpClient.newCall(request)
.enqueue(object: Callback {
override fun onFailure(call: Call, e: IOException) {
displayAlert(weakActivity.get(), "Payment failed", "Error: $e")
}
override fun onResponse(call: Call, response: Response) {
// Request failed
if (!response.isSuccessful) {
displayAlert(weakActivity.get(), "Payment failed", "Error: $response")
} else {
val responseData = response.body?.string()
var responseJson = JSONObject(responseData)
val payError: String? = responseJson.optString("error")
val clientSecret: String? = responseJson.optString("clientSecret")
val requiresAction: Boolean? = responseJson.optBoolean("requiresAction")
// Payment failed
if (payError != null && payError.isNotEmpty()) {
displayAlert(weakActivity.get(), "Payment failed", "Error: $payError")
}
// Payment succeeded
else if ((clientSecret != null && clientSecret.isNotEmpty())
&& (requiresAction == null || requiresAction == false)) {
displayAlert(weakActivity.get(), "Payment succeeded", "$clientSecret", restartDemo = true)
}
// Payment requires additional actions
else if ((clientSecret != null && clientSecret.isNotEmpty())
&& requiresAction == true) {
runOnUiThread {
if (weakActivity.get() != null) {
// ...continued in the next step
}
}
}
}
}
})
}
}
```
## Gestionar las siguientes acciones [Lado del cliente]
Si el pago requiere otras acciones como la *autenticación 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), el estado del PaymentIntent pasa a ser `requires_action`. En el lado del cliente, especifica el ID del `PaymentIntent` en [handleNextActionForPayment](https://stripe.dev/stripe-android/payments-core/com.stripe.android/-stripe/handle-next-action-for-payment.html). Este SDK presenta otras actividades y guía al cliente a través del proceso de autenticación. Para obtener más información, consulta [Cómo admitir la autenticación con 3D Secure en Android](https://docs.stripe.com/payments/3d-secure.md?platform=android).
Después de gestionar una acción obligatoria del lado del cliente, el estado del PaymentIntent es `requires_confirmation`. Este paso permite que tu integración *complete* (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 y envíe el resultado de esta operación al cliente.
Envía el ID del PaymentIntent a tu back-end y vuelve a confirmarlo en el término de una hora para finalizar el pago. De lo contrario, el intento de pago fallará y volverá a `requires_payment_method`.
#### Kotlin
```kotlin
class CheckoutActivity : AppCompatActivity() {
// ...
private fun pay(paymentMethod: String?, paymentIntent: String?) {
// ...
val activity = weakActivity.get()!!
stripe.handleNextActionForPayment(activity, clientSecret)
// ...
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val weakActivity = WeakReference(this)
// Handle the result of stripe.handleNextActionForPayment
if (stripe.isPaymentResult(requestCode, data)) {
lifecycleScope.launch {
runCatching {
stripe.getPaymentIntentResult(requestCode, data!!)
}.fold(
onSuccess = { result ->
val paymentIntent = result.intent
val status = paymentIntent.status
if (status == StripeIntent.Status.Succeeded) {
val gson = GsonBuilder().setPrettyPrinting().create()
displayAlert(
weakActivity.get(),
"Payment succeeded",
gson.toJson(paymentIntent),
restartDemo = true
)
} else if (status == StripeIntent.Status.RequiresPaymentMethod) {
// Payment failed – allow retrying using a different payment method
displayAlert(
weakActivity.get(),
"Payment failed",
paymentIntent.lastPaymentError!!.message ?: ""
)
} else if (status == StripeIntent.Status.RequiresConfirmation) {
print("Re-confirming PaymentIntent after handling a required action")
pay(null, paymentIntent.id)
} else {
displayAlert(
weakActivity.get(),
"Payment status unknown",
"unhandled status: $status",
restartDemo = true
)
}
}, onFailure = {
// Payment request failed – allow retrying using the same payment method
displayAlert(weakActivity.get(), "Payment failed", it.toString())
}
)
}
}
}
}
```
El resultado de la autenticación del pago vuelve a la actividad de tu llamado a través de [Activity#onActivityResult()](https://developer.android.com/reference/android/app/Activity.html#onActivityResult\(int,%20int,%20android.content.Intent\)). Gestiona el resultado llamando a [Stripe#onPaymentResult()](https://stripe.dev/stripe-android/payments-core/com.stripe.android/-stripe/on-payment-result.html) en `Activity#onActivityResult()`. El [PaymentIntentResult](https://stripe.dev/stripe-android/payments-core/com.stripe.android/-payment-intent-result/index.html) devuelto en [ApiResultCallback#onSuccess()](https://stripe.dev/stripe-android/payments-core/com.stripe.android/-api-result-callback/on-success.html) tiene dos captadores:
- `getIntent()`: un objeto [PaymentIntent](https://stripe.dev/stripe-android/payments-core/com.stripe.android/-stripe-intent-result/index.html#com.stripe.android/StripeIntentResult/intent/#/PointingToDeclaration/) recuperado después de la confirmación/autenticación
- `getOutcome()`: un valor [StripeIntentResult.Status](https://stripe.dev/stripe-android/payments-core/com.stripe.android/-stripe-intent-result/index.html#com.stripe.android/StripeIntentResult/outcome/#/PointingToDeclaration/) que indica el resultado de la autenticación del pago
- `SUCCEEDED`: autenticación de pago realizada correctamente
- `FAILED`: autenticación de pago fallida
- `CANCELED`: el cliente canceló la autenticación de pago solicitada
- `TIMEDOUT`: se agotó el tiempo de espera del intento de autenticación de pago
## 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 el CVC del cliente, tokeniza los datos del CVC usando [Stripe#createCvcUpdateToken()](https://stripe.dev/stripe-android/payments-core/com.stripe.android/-stripe/create-cvc-update-token.html).
#### Kotlin
```kotlin
class CheckoutActivity : AppCompatActivity() {
private val stripe: Stripe by lazy {
Stripe(this, "<>")
}
private fun tokenizeCvc(cvc: String) {
stripe.createCvcUpdateToken(
cvc,
callback = CvcUpdateResultCallback()
)
}
private class CvcUpdateResultCallback : ApiResultCallback {
override fun onSuccess(result: Token) {
val tokenId = result.id
// pass token ID to your backend
}
override fun onError(e: Exception) {
// handle error
}
}
}
```
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 Google Pay](https://docs.stripe.com/google-pay.md)
# React Native
> This is a React Native for when platform is react-native. View the full page at https://docs.stripe.com/payments/accept-a-payment-synchronously?platform=react-native.
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 servidor] [Lado del cliente]
### 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 React Native](https://github.com/stripe/stripe-react-native) es de código abierto y está plenamente documentado. Internamente, utiliza SDK para [iOS nativo](https://github.com/stripe/stripe-ios) y [Android](https://github.com/stripe/stripe-android). Para instalar el SDK para React Native de Stripe, ejecuta uno de los siguientes comandos en el directorio del proyecto (según el administrador de paquetes que utilices):
#### hilado
```bash
yarn add @stripe/stripe-react-native
```
#### npm
```bash
npm install @stripe/stripe-react-native
```
A continuación, instala otras dependencias necesarias:
- Para iOS, vaya al directorio **ios** y ejecute `pod install` para asegurarse de que también instala las dependencias nativas necesarias.
- Para Android, no hay más dependencias para instalar.
> Recomendamos seguir la [guía oficial de TypeScript](https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project) para agregar soporte para TypeScript.
### Inicialización de Stripe
Para inicializar Stripe en tu aplicación React Native, ajusta tu pantalla de pago con el componente `StripeProvider` o usa el método de inicialización `initStripe`. Solo se requiere la [clave publicable](https://docs.stripe.com/keys.md#obtain-api-keys) de la API en `publishableKey`. El siguiente ejemplo muestra cómo inicializar Stripe usando el componente `StripeProvider`.
```jsx
import { useState, useEffect } from 'react';
import { StripeProvider } from '@stripe/stripe-react-native';
function App() {
const [publishableKey, setPublishableKey] = useState('');
const fetchPublishableKey = async () => {
const key = await fetchKey(); // fetch key from your server here
setPublishableKey(key);
};
useEffect(() => {
fetchPublishableKey();
}, []);
return (
{/* Your app code here */}
);
}
```
> Usa las [claves de prueba](https://docs.stripe.com/keys.md#obtain-api-keys) de la API 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 página de finalización de compra [Lado del cliente]
Recopila los datos de la tarjeta del cliente de manera segura con `CardField`, un componente de interfaz de usuario (IU) proporcionado por el SDK que recopila el número de tarjeta, la fecha de vencimiento, el CVC y el código postal.

Agrega el componente `CardField` a tu pantalla de pago para recopilar los datos de la tarjeta de tus clientes de forma segura. Usa la devolución de llamada de `onCardChange` para examinar la información no confidencial de la tarjeta, como por ejemplo la marca, y comprobar si los datos están al completo.
```javascript
import { CardField, useStripe } from '@stripe/stripe-react-native';
function PaymentScreen() {
// ...
return (
{
console.log('cardDetails', cardDetails);
}}
onFocus={(focusedField) => {
console.log('focusField', focusedField);
}}
/>
);
}
```
Ejecuta tu aplicación y asegúrate de que en la página de finalización de compra, aparezca el componente `CardField`.
## 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 componente `CardField`.
```javascript
import { CardField, useStripe } from '@stripe/stripe-react-native';
function PaymentScreen() {
const { createPaymentMethod, handleNextAction } = useStripe();
const pay = async () => {
// Gather customer billing information (for example, email)
const billingDetails: CreatePaymentMethod.BillingDetails = {
email: 'email@stripe.com',
phone: '+48888000888',
addressCity: 'Houston',
addressCountry: 'US',
addressLine1: '1459 Circle Drive',
addressLine2: 'Texas',
addressPostalCode: '77063',
};
// Create payment method
const { paymentMethod, error } = await createPaymentMethod({
paymentMethodType: 'Card',
paymentMethodData: {
billingDetails,
}
});
};
// ...
}
```
## Envía el PaymentMethod a tu servidor [Lado del cliente]
Si el PaymentMethod se creó correctamente, envía su ID a tu servidor.
```javascript
// ...
const pay = async () => {
// ...
// Send the PaymentMethod to your server to create a PaymentIntent
const response = await fetch(`/pay`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ paymentMethodId: paymentMethod.id }),
});
const { error, requires_action, payment_intent_client_secret } = await response.json();
if (error) {
// Error creating or confirming PaymentIntent
Alert.alert('Error', paymentIntentError);
return;
}
if (payment_intent_client_secret && !requires_action) {
// Payment succeeded
Alert.alert('Success', 'The payment was confirmed successfully!');
}
if (payment_intent_client_secret && requires_action) {
// ...continued below
}
};
// ...
```
## 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]
Normalmente, un pago se efectiviza después de que lo *confirmas* (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) en el servidor, en el paso 4. No obstante, algunos flujos de pago requieren una acción más por parte del cliente, como la autenticación 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).
Para los casos que requieren acciones siguientes, el estado del PaymentIntent es `requires_action`. En el cliente, pasa el *secreto de cliente* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)) del PaymentIntent a `handleNextAction`. El controlador nativo presenta una vista y guía al cliente a través del flujo de autenticación. Después de gestionar las acciones necesarias de lado del cliente, el estado del PaymentIntent cambia a `requires_confirmation`. Esto permite que tu integración cumpla con el pedido en tu back-end y envíe el resultado de la *entrega* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) al cliente.
Envía el ID del PaymentIntent a tu back-end y vuelve a confirmarlo en el término de una hora para finalizar el pago. De lo contrario, el intento de pago fallará y volverá a `requires_payment_method`.
```javascript
// ...
const pay = async () => {
// ...
// If PaymentIntent requires action, call handleNextAction
if (payment_intent_client_secret && requires_action) {
const { error, paymentIntent } = await handleNextAction(payment_intent_client_secret);
if (error) {
Alert.alert(`Error code: ${error.code}`, error.message);
} else if (paymentIntent) {
if (
paymentIntent.status === PaymentIntents.Status.RequiresConfirmation
) {
// Confirm the PaymentIntent again on your server
const response = await fetch(`/pay`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ payment_intent_id: paymentIntent.id }),
});
const { error, success } = await response.json();
if (error) {
// Error during confirming Intent
Alert.alert('Error', error);
} else if (success) {
Alert.alert('Success', 'The payment was confirmed successfully!');
}
} else {
// Payment succedeed
Alert.alert('Success', 'The payment was confirmed successfully!');
}
}
}
};
// ...
```
## 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
Cuando se crean pagos sucesivos con una tarjeta guardada, es conveniente volver a pedir el CVC de la tarjeta como una medida antifraude adicional para verificar al usuario.
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 el CVC del cliente, tokeniza los datos del CVC con `createTokenForCVCUpdate`.
```javascript
function PaymentScreen() {
// ...
const { createTokenForCVCUpdate } = useStripe();
const tokenizeCVC = async () => {
const { error, tokenId } = await createTokenForCVCUpdate();
if (error) {
// handle error
} else if (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.