# Crear una integración de suscripciones Crear y administrar las suscripciones para aceptar pagos recurrentes. ## Start here: Install agent skills Stripe recommends using official skills to integrate with the API using best practices. Follow the instructions below to learn how. **Tip: Use curl instead of Fetch tools.** Skills are detailed 10–20 KB markdown files. Fetch tools summarize them. `curl -sL` guarantees the full content. **Using `npx skills`**: Check if `npx` is installed on the system. If `npx` is available, run `npx skills add https://docs.stripe.com --list` to list available skills, then run `npx skills add https://docs.stripe.com --yes --skill <--skill other-skills>` to install individual skills. **If `npx skills` isn’t available**: You can use curl to fetch the index of available skills, what they do, and their files from `https://docs.stripe.com/.well-known/skills/index.json`. To download a skill and its related files, use curl to download them from `https://docs.stripe.com/.well-known/skills/`. For this article, we recommend using these skills: `stripe-best-practices` #### Checkout #### Página alojada en Stripe # Página alojada > This is a Página alojada for when platform is web and ui is stripe-hosted. View the full page at https://docs.stripe.com/billing/subscriptions/build-subscriptions?platform=web&ui=stripe-hosted. #### Esfuerzo de integración Complexity: 2/5 #### Personalización de la interfaz de usuario (IU) Personalización limitada - 20 fuentes preestablecidas - 3 radios de borde preestablecidos - Fondo y color de borde personalizados - Logotipo personalizado #### Tipo de integración Utiliza las páginas alojadas prediseñadas para cobrar los pagos y gestionar tus *suscripciones* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis). [Pruébalo](https://checkout.stripe.dev/) ## Tu próximo desarrollo Esta guía describe cómo vender suscripciones mensuales de precio fijo utilizando [Stripe Checkout](https://docs.stripe.com/payments/checkout.md). Esta guía te explica cómo: - Modelar tu empresa creando un catálogo de productos. - Agregar una Checkout Session a tu sitio, incluidos un botón y las páginas de confirmación y cancelación de transacciones. - Monitorear los eventos de suscripción y brindar acceso a tu servicio. - Configura el [portal de clientes](https://docs.stripe.com/customer-management.md) . - Agregar una sesión del portal de clientes a tu sitio, incluidos un botón y el redireccionamiento. - Permitir que tus clientes administren sus suscripciones a través del portal. - Aprende a utilizar el [modo de facturación flexible](https://docs.stripe.com/billing/subscriptions/billing-mode.md) para acceder a un comportamiento de facturación mejorado y a funcionalidades adicionales. Si no estás preparado para codificar una integración, puedes configurar las suscripciones básicas [manualmente en el Dashboard](https://docs.stripe.com/no-code/subscriptions.md) o utilizar [Payment Links](https://docs.stripe.com/payment-links.md) para configurar las suscripciones sin escribir ningún código. Obtén más información sobre [cómo diseñar una integración](https://docs.stripe.com/billing/subscriptions/design-an-integration.md) para comprender las decisiones y los recursos necesarios para una integración completa. Después de completar la integración, puedes ampliarla a lo siguiente: - Muestra [impuestos](https://docs.stripe.com/payments/checkout/taxes.md) - Aplica [descuentos](https://docs.stripe.com/billing/subscriptions/coupons.md#using-coupons-in-checkout) - Ofrece a los clientes un [periodo de prueba gratuito](https://docs.stripe.com/billing/subscriptions/trials.md) - Agrega [métodos de pago](https://docs.stripe.com/payments/payment-methods/integration-options.md) - Integre la [página de facturas alojadas](https://docs.stripe.com/invoicing/hosted-invoice-page.md) - Utiliza Checkout en el [modo de configuración](https://docs.stripe.com/payments/save-and-reuse.md) - Establece [facturación por consumo](https://docs.stripe.com/products-prices/pricing-models.md#usage-based-pricing), [niveles de precios](https://docs.stripe.com/products-prices/pricing-models.md#tiered-pricing), y [precios por consumo](https://docs.stripe.com/products-prices/pricing-models.md#usage-based-pricing) - Administra los [prorrateos](https://docs.stripe.com/billing/subscriptions/prorations.md) - Permite que los clientes se [suscriban a varios productos](https://docs.stripe.com/billing/subscriptions/quantities.md#multiple-product-sub) - Integra [entitlements](https://docs.stripe.com/billing/entitlements.md) para gestionar el acceso a las funcionalidades de tu producto. ## Configura Stripe Instala el cliente de Stripe que prefieras: #### 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' ``` Opcionalmente, instala la CLI de Stripe. La CLI proporciona pruebas de [webhook](https://docs.stripe.com/webhooks.md#test-webhook), y puedes ejecutarla para crear tus productos y precios. Para obtener más opciones de instalación, consulta [Empezar a usar la CLI de Stripe](https://docs.stripe.com/stripe-cli.md). ## Crear el modelo de tarifas [Dashboard o CLI de Stripe] Los [modelos de precios recurrentes](https://docs.stripe.com/products-prices/pricing-models.md) representan los productos o servicios que vendes, cuánto cuestan, qué monedas aceptas para los pagos y el período de servicio para las suscripciones. Para crear el modelo de precios, crea [productos](https://docs.stripe.com/api/products.md) (lo que vendes) y [precios](https://docs.stripe.com/api/prices.md) (cuánto cuestan y con qué frecuencia cobrar por los productos). En este ejemplo, se utiliza una tarifa con tasa fija con dos opciones de niveles de servicio diferentes: básico y premium. Para cada opción de nivel de servicio, debes crear un producto y un precio recurrente. Si quieres agregar un cargo por única vez, como el costo de instalación, crea un tercer producto con un precio por única vez. Cada producto se factura de forma mensual. El precio del producto básico es de 5 USD. El precio del producto premium es de 15 USD. Consulta la guía de [tarifas con tasa fija](https://docs.stripe.com/subscriptions/pricing-models/flat-rate-pricing.md) para ver un ejemplo con tres niveles. #### Dashboard Ve a la página [Agregar un producto](https://dashboard.stripe.com/test/products/create) y crea dos productos. Agrega un precio a cada producto, cada uno con un período de facturación mensual recurrente: - Producto prémium: servicio prémium con más funcionalidades - Precio: Tarifa plana | 15 USD - Producto básico: servicio básico con las funcionalidades mínimas - Precio: Tarifa plana | 5 USD Después de crear los precios, registra los ID de precio para usarlos en otros pasos. Los ID de precio se ven así: `price_G0FvDp6vZvdwRZ`. Cuando esté todo listo, usa el botón **Copiar en modo activo**, en la parte superior derecha de la página, para clonar el producto y pasarlo de [entorno de prueba a modo activo](https://docs.stripe.com/keys.md#test-live-modes). #### API Puedes usar la API para crear los [productos](https://docs.stripe.com/api/products.md) y los [precios](https://docs.stripe.com/api/prices.md). Crear el producto premium: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Premium Service" \ -d "description=Premium service with extra features" ``` Crear el producto básico: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Basic Service" \ -d "description=Basic service with minimum features" ``` Registra el ID de cada producto. Se ve así: ```json { "id": "prod_H94k5odtwJXMtQ", "object": "product", "active": true, "attributes": [ ], "created": 1587577341, "description": "Premium service with extra features", "images": [ ], "livemode": false, "metadata": { }, "name": "Billing Guide: Premium Service", "statement_descriptor": null, "type": "service", "unit_label": null, "updated": 1587577341 } ``` Usa los ID de producto para crear el precio de cada producto. El número [unit_amount](https://docs.stripe.com/api/prices/object.md#price_object-unit_amount) está en centavos. Por ejemplo, `1500` = 15 USD. Crear el precio superior: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{PREMIUM_PRODUCT_ID}} \ -d unit_amount=1500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Crear el precio básico: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{BASIC_PRODUCT_ID}} \ -d unit_amount=500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Registra el ID de cada precio para poder utilizarlo en los pasos siguientes. Se ve así: ```json { "id": "price_HGd7M3DV3IMXkC", "object": "price", "product": "prod_HGd6W1VUqqXGvr", "type": "recurring", "currency": "usd", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "active": true, "billing_scheme": "per_unit", "created": 1589319695, "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "unit_amount": 1500, "unit_amount_decimal": "1500", "tiers": null, "tiers_mode": null, "transform_quantity": null } ``` Si ofreces varios períodos de facturación, usa el proceso de compra para las [ventas adicionales](https://docs.stripe.com/payments/checkout/upsells.md) a los clientes en períodos de facturación más largos y cobra más ingresos por adelantado. Para conocer otros modelos de precios, consulta [Ejemplos de Billing](https://docs.stripe.com/products-prices/pricing-models.md). ## Crea una Checkout Session [Cliente y servidor] Agrega un botón de pago en tu sitio web que llame a un punto de conexión del lado del servidor para crear una Checkout Session. ```html Checkout
``` En el back-end de tu solicitud, define un punto de conexión que [cree la sesión](https://docs.stripe.com/api/checkout/sessions/create.md) para que tu front-end la llame. Necesitará estos valores: - El ID de precio de la suscripción por la que el cliente ha creado la cuenta (tu front-end especifica este valor). - Tu `success_url`, que es una página de su sitio web a la que Checkout devuelve a tu cliente después de completar el pago. Opcionalmente, puedes: - Configura un [ciclo de facturación anclado](https://docs.stripe.com/billing/subscriptions/billing-cycle.md) a tu suscripción en esta llamada. - Usa [el texto personalizado](https://docs.stripe.com/payments/checkout/custom-components.md?platform=web&payment-ui=stripe-hosted#customize-text) a fin de incluir tus Condiciones de suscripción y cancelación, además de un enlace que permita a tus clientes actualizar o cancelar su suscripción. Te recomendamos configurar [los recordatorios y las notificaciones por correo electrónico](https://docs.stripe.com/invoicing/send-email.md#email-configuration) para tus suscriptores. Si creaste un precio único en el [paso 2](https://docs.stripe.com/billing/subscriptions/build-subscriptions.md#create-pricing-model), pasa también ese ID de precio. Tras crear una Checkout Session, redirige a tu cliente a la [URL](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-url) que se devolvió en la respuesta. Puedes habilitar un comportamiento de suscripción más preciso y predecible cuando crees una Checkout Session configurando el tipo de [modo de facturación](https://docs.stripe.com/billing/subscriptions/billing-mode.md) como `flexible`. Debes utilizar la versión de la API de Stripe [2025-06-30.basil](https://docs.stripe.com/changelog/basil.md#2025-06-30.basil) o posterior. > Puedes utilizar [lookup_keys](https://docs.stripe.com/products-prices/manage-prices.md#lookup-keys) a fin de obtener precios en lugar de ID de precios. Para ver un ejemplo, consulta el [modelo de solicitud](https://github.com/stripe-samples/subscription-use-cases/tree/main/fixed-price-subscriptions). #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' # The price ID passed from the front end. # price_id = params['priceId'] price_id = '{{PRICE_ID}}' session = Stripe::Checkout::Session.create({ success_url: 'https://example.com/success.html?session_id={CHECKOUT_SESSION_ID}', mode: 'subscription', line_items: [{ # For usage-based billing, don't pass quantity quantity: 1, price: price_id }], subscription_data: { billing_mode: { type: 'flexible' } } }) # Redirect to the URL returned on the session # redirect session.url, 303 ``` Este ejemplo personaliza la `success_url` añadiendo el identificador de sesión. Más información sobre [personalización de la página de éxito](https://docs.stripe.com/payments/checkout/custom-success-page.md). Desde tu [Dashboard](https://dashboard.stripe.com/settings/payment_methods), activa los métodos de pago que deseas aceptar de tus clientes. Checkout admite [varios métodos de pago](https://docs.stripe.com/payments/payment-methods/payment-method-support.md#product-support). ## Dar acceso a las suscripciones y monitorearlas [Servidor] If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Una vez que la suscripción se ha completado con éxito, el cliente regresa a su sitio web en la dirección `success_url`, que inicia un evento `checkout.session.completed` *webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests). Cuando recibas un evento `checkout.session.completed`, utiliza [entitlements](https://docs.stripe.com/billing/entitlements.md) para aprovisionar la suscripción. Continúa aprovisionando cada mes (si facturas mensualmente) a medida que recibas eventos `invoice.paid`. Si recibes un evento `invoice.payment_failed`, notifícalo a tu cliente y envíalo al portal de clientes para que actualice su método de pago. Para determinar el siguiente paso para la lógica de tu sistema, comprueba el tipo de evento y analiza la carga útil de cada [objeto de evento](https://docs.stripe.com/api/events/object.md), como `invoice.paid`. Almacena los objetos de evento `subscription.id` y `customer.id` en tu base de datos para su verificación. Para realizar pruebas, puedes supervisar los eventos en la [pestaña Eventos](https://dashboard.stripe.com/workbench/events) de [Workbench](https://docs.stripe.com/workbench.md). Para producción, configura un punto de conexión webhook y suscríbete a los tipos de eventos apropiados. Si no conoces tu clave `STRIPE_WEBHOOK_SECRET`, ve a la vista de detalles del destino de la [pestaña Webhooks](https://dashboard.stripe.com/workbench/webhooks) de Workbench para consultarla. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/webhook' do webhook_secret = '{{STRIPE_WEBHOOK_SECRET}}' # Ejemplo: whsec_c7681Dm payload = request.body.read if !webhook_secret.empty? # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured. sig_header = request.env['HTTP_STRIPE_SIGNATURE'] event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, webhook_secret ) rescue JSON::ParserError => e # Invalid payload status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature puts '⚠️ Webhook signature verification failed.' status 400 return end else data = JSON.parse(payload, symbolize_names: true) event = Stripe::Event.construct_from(data) end # Get the type of webhook event sent event_type = event['type'] data = event['data'] data_object = data['object'] case event_type when 'checkout.session.completed' # Payment is successful and the subscription is created. # You should provision the subscription and save the customer ID to your database. when 'invoice.paid' # Continue to provision the subscription as payments continue to be made. # Store the status in your database and check when a user accesses your service. # This approach helps you avoid hitting rate limits. when 'invoice.payment_failed' # The payment failed or the customer doesn't have a valid payment method. # The subscription becomes past_due. Notify your customer and send them to the # customer portal to update their payment information. else puts "Unhandled event type: \#{event.type}" end status 200 end ``` Como mínimo, debes monitorear estos tipos de eventos: | Nombre del evento | Descripción | | ---------------------------- | -------------------------------------------------------------------------------------------------- | | `checkout.session.completed` | Se envía cuando un cliente completa con éxito la sesión de pago, para informarle una nueva compra. | | `invoice.paid` | Se envía en cada período de facturación cuando se realiza correctamente un pago. | | `invoice.payment_failed` | Se envía en cada período de facturación si hay un problema con el método de pago del cliente. | Para conocer aún más eventos que supervisar, consulta [Webhooks de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md). ## Configurar el portal de clientes [Dashboard] El [portal de clientes](https://docs.stripe.com/customer-management.md) les permite a tus clientes gestionar directamente sus suscripciones y facturas existentes. Utiliza el [Dashboard](https://dashboard.stripe.com/test/settings/billing/portal) para configurar el portal. Como mínimo, asegúrate de [configurar el portal](https://docs.stripe.com/customer-management.md) para que los clientes puedan actualizar sus métodos de pago. ## Crear una sesión del portal [Servidor] Definir un punto de conexión que [cree la sesión del portal de clientes](https://docs.stripe.com/api/customer_portal/sessions/create.md) para que tu front-end la llame. El `CUSTOMER_ID` se refiere al ID de cliente creado por una Checkout Session que guardaste mientras procesabas el evento `checkout.session.completed`. También puedes establecer un enlace de redirección predeterminado para el portal en el Dashboard. Pasa un valor opcional `return_url` para la página de tu sitio a la que redirigir a tu cliente cuando termine de gestionar tu suscripción: #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' # This is the URL that users are redirected to after they're done # managing their billing. return_url = '{{DOMAIN_URL}}' # Ejemplo: http://example.com customer_id = '{{CUSTOMER_ID}}' # Ejemplo: cus_GBV60HKsE0mb5v session = Stripe::BillingPortal::Session.create({ customer: customer_id, return_url: return_url, }) # Redirect to the URL for the session # redirect session.url, 303 ``` ## Dirigir a los clientes al portal de clientes [Cliente] En el front-end, agrega un botón a la página de la dirección `success_url` que proporcione un enlace al portal de clientes: ```html Manage Billing
``` Después de salir del portal de clientes, el cliente vuelve a tu sitio web en la `return_url`. Sigue [monitoreando los eventos](https://docs.stripe.com/billing/subscriptions/webhooks.md) para hacer el seguimiento del estado de la suscripción del cliente. Si configuras el portal de clientes para permitir acciones como la cancelación de una suscripción, [supervisa eventos adicionales](https://docs.stripe.com/customer-management/integrate-customer-portal.md#webhooks). ## Prueba la integración ### Prueba métodos de pago Usa la siguiente tabla para probar diferentes métodos y escenarios de pago. | Método de pago | Escenario | Cómo hacer la prueba | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Débito directo BECS | Tu cliente paga correctamente con débito directo BECS. | Completa el formulario con el número de cuenta `900123456` y BSB `000000`. El PaymentIntent confirmado pasa en un principio al estado `processing` y, tres minutos más tarde, a `succeeded`. | | Débito directo BECS | El pago de tu cliente falla con un código de error `account_closed`. | Completa el formulario con el número de cuenta `111111113` y BSB `000000`. | | Tarjeta de crédito | El pago con tarjeta se efectúa correctamente y no requiere autenticación. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4242 4242 4242 4242` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | El pago con tarjeta requiere *autenticación* (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). | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0025 0000 3155` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | La tarjeta es rechazada con el código `insufficient_funds`. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0000 0000 9995` y cualquier fecha de vencimiento, CVC y código postal. | | Débito directo SEPA | Tu cliente paga correctamente con débito directo SEPA. | Completa el formulario con el número de cuenta `AT321904300235473204`. El PaymentIntent confirmado pasa inicialmente al estado “en proceso” y, tres minutos más tarde, a “completado”. | | Débito directo SEPA | El estado de PaymentIntent de tu cliente pasa de `processing` a `requires_payment_method`. | Completa el formulario con el número de cuenta `AT861904300235473202`. | ### Supervisa los acontecimientos Configura webhooks para escuchar los eventos de cambio de suscripción, como actualizaciones y cancelaciones. Puedes ver [eventos de webhook de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md) en el [Dashboard](https://dashboard.stripe.com/test/events) o con el [Stripe CLI](https://docs.stripe.com/webhooks.md#test-webhook). Obtén más información sobre [Comprobación de la integración con Billing](https://docs.stripe.com/billing/testing.md). ## See also - [Ofrece a los clientes un periodo de prueba gratuito](https://docs.stripe.com/billing/subscriptions/trials.md) - [Aplica descuentos](https://docs.stripe.com/billing/subscriptions/coupons.md#using-coupons-in-checkout) - [Administra los prorrateos](https://docs.stripe.com/billing/subscriptions/prorations.md) - [Integra los derechos para gestionar el acceso a las funcionalidades de tu producto](https://docs.stripe.com/billing/entitlements.md) #### Formulario integrado # Página integrada > This is a Página integrada for when platform is web and ui is embedded-form. View the full page at https://docs.stripe.com/billing/subscriptions/build-subscriptions?platform=web&ui=embedded-form. #### Esfuerzo de integración Complexity: 2/5 #### Personalización de la interfaz de usuario Personalizar el aspecto #### Tipo de integración Utiliza formularios integrados preintegrados para cobrar los pagos y gestionar *suscripciones* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis). ## Configurar el servidor ### Configura Stripe Instala el cliente de Stripe que prefieras: #### 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' ``` ### Crear un producto y un precio Los [modelos de precios recurrentes](https://docs.stripe.com/products-prices/pricing-models.md) representan los productos o servicios que vendes, cuánto cuestan, qué monedas aceptas para los pagos y el período de servicio para las suscripciones. Para crear el modelo de precios, crea [productos](https://docs.stripe.com/api/products.md) (lo que vendes) y [precios](https://docs.stripe.com/api/prices.md) (cuánto cuestan y con qué frecuencia cobrar por los productos). En este ejemplo, se utiliza una tarifa con tasa fija con dos opciones de niveles de servicio diferentes: básico y premium. Para cada opción de nivel de servicio, debes crear un producto y un precio recurrente. Si quieres agregar un cargo por única vez, como el costo de instalación, crea un tercer producto con un precio por única vez. Cada producto se factura de forma mensual. El precio del producto básico es de 5 USD. El precio del producto premium es de 15 USD. Consulta la guía de [tarifas con tasa fija](https://docs.stripe.com/subscriptions/pricing-models/flat-rate-pricing.md) para ver un ejemplo con tres niveles. #### Dashboard Ve a la página [Agregar un producto](https://dashboard.stripe.com/test/products/create) y crea dos productos. Agrega un precio a cada producto, cada uno con un período de facturación mensual recurrente: - Producto prémium: servicio prémium con más funcionalidades - Precio: Tarifa plana | 15 USD - Producto básico: servicio básico con las funcionalidades mínimas - Precio: Tarifa plana | 5 USD Después de crear los precios, registra los ID de precio para usarlos en otros pasos. Los ID de precio se ven así: `price_G0FvDp6vZvdwRZ`. Cuando esté todo listo, usa el botón **Copiar en modo activo**, en la parte superior derecha de la página, para clonar el producto y pasarlo de [entorno de prueba a modo activo](https://docs.stripe.com/keys.md#test-live-modes). #### API Puedes usar la API para crear los [productos](https://docs.stripe.com/api/products.md) y los [precios](https://docs.stripe.com/api/prices.md). Crear el producto premium: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Premium Service" \ -d "description=Premium service with extra features" ``` Crear el producto básico: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Basic Service" \ -d "description=Basic service with minimum features" ``` Registra el ID de cada producto. Se ve así: ```json { "id": "prod_H94k5odtwJXMtQ", "object": "product", "active": true, "attributes": [ ], "created": 1587577341, "description": "Premium service with extra features", "images": [ ], "livemode": false, "metadata": { }, "name": "Billing Guide: Premium Service", "statement_descriptor": null, "type": "service", "unit_label": null, "updated": 1587577341 } ``` Usa los ID de producto para crear el precio de cada producto. El número [unit_amount](https://docs.stripe.com/api/prices/object.md#price_object-unit_amount) está en centavos. Por ejemplo, `1500` = 15 USD. Crear el precio superior: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{PREMIUM_PRODUCT_ID}} \ -d unit_amount=1500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Crear el precio básico: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{BASIC_PRODUCT_ID}} \ -d unit_amount=500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Registra el ID de cada precio para poder utilizarlo en los pasos siguientes. Se ve así: ```json { "id": "price_HGd7M3DV3IMXkC", "object": "price", "product": "prod_HGd6W1VUqqXGvr", "type": "recurring", "currency": "usd", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "active": true, "billing_scheme": "per_unit", "created": 1589319695, "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "unit_amount": 1500, "unit_amount_decimal": "1500", "tiers": null, "tiers_mode": null, "transform_quantity": null } ``` Si ofreces varios períodos de facturación, usa el proceso de compra para las [ventas adicionales](https://docs.stripe.com/payments/checkout/upsells.md) a los clientes en períodos de facturación más largos y cobra más ingresos por adelantado. Para conocer otros modelos de precios, consulta [Ejemplos de facturación](https://docs.stripe.com/products-prices/pricing-models.md). ### Crea una Checkout Session Añade un punto de conexión en tu servidor que cree una *Checkout Session* (A Checkout Session represents your customer's session as they pay for one-time purchases or subscriptions through Checkout. After a successful payment, the Checkout Session contains a reference to the Customer, and either the successful PaymentIntent or an active Subscription). Cuando crees la [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md), pasa los siguientes parámetros: - To use the embedded_page payment form, set [ui_mode](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-ui_mode) to `embedded`. - Para crear suscripciones si tu cliente pague, configura el [modo ](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-mode) en `suscripción`. - Para definir la página a la que volverá tu cliente después de completar o intentar el pago, especifique una [return_url](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-return_url). Incluye la variable de plantilla `{CHECKOUT_SESSION_ID}` en la URL. Checkout sustituye la variable por el ID de Checkout Session antes de redirigir a tu cliente. Tú creas y alojas la página de retorno en tu sitio web. - Con el fin de incluir tus Condiciones de suscripción y cancelación, además de un enlace que permita a tus clientes actualizar o cancelar su suscripción, utiliza [el texto personalizado](https://docs.stripe.com/payments/checkout/custom-components.md?ui=embedded-form#customize-payment-method-reuse-agreement-and-subscription-terms) de manera opcional. Te recomendamos configurar los recordatorios y las notificaciones por [correo electrónico](https://docs.stripe.com/invoicing/send-email.md#email-configuration) para tus suscriptores. Para montar Checkout, utiliza el `client_secret` de la Checkout Session devuelto en la respuesta. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=subscription \ -d "line_items[0][price]={{PRICE_ID}}" \ -d "line_items[0][quantity]=1" \ -d ui_mode=embedded_page \ --data-urlencode "return_url=https://example.com/checkout/return?session_id={CHECKOUT_SESSION_ID}" ``` ## Crear tu página de suscripciones [Cliente] ### Montar Checkout #### HTML + JS #### Cargar Stripe.js Utiliza *Stripe.js* (Use Stripe.js’ APIs to tokenize customer information, collect sensitive card data, and accept payments with browser payment APIs) para *cumplir con la normativa PCI* (Any party involved in processing, transmitting, or storing credit card data must comply with the rules specified in the Payment Card Industry (PCI) Data Security Standards. PCI compliance is a shared responsibility and applies to both Stripe and your business) asegurándote de que los datos del pago se envíen directamente a Stripe sin que pasen por tu servidor. Carga siempre Stripe.js directamente desde js.stripe.com para cumplir con la normativa PCI. No incluyas el script en un paquete ni alojes una copia por tu cuenta. #### Definir el formulario de pago Para cobrar de forma segura la información del cliente, crea un marcador de posición vacío `div`. Stripe inserta un iframe en el `div`. Checkout está disponible como parte de [Stripe.js](https://docs.stripe.com/js.md). Para incluir el script de Stripe.js en tu página, agrégalo al encabezado de tu archivo HTML. A continuación, crea un nodo DOM vacío (contenedor) para usarlo en el montaje. ```html Accept a payment
``` #### Inicializar Stripe.js Inicializa Stripe.js con la clave publicable de tu API. #### Obtener el secreto de cliente de una Checkout Session Crea una función asíncrona `fetchClientSecret` que realice una solicitud a tu servidor para [crear una Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md) y recuperar el secreto de cliente. #### Inicializar Checkout Inicializa Checkout con tu función `fetchClientSecret` y móntala en el marcador de posición. `
` en tu formulario de pago. Checkout se realiza en un iframe que envía de forma segura la información de pago a Stripe a través de una conexión HTTPS. Evita colocar Checkout en otro iframe, ya que algunos métodos de pago requieren un redireccionamiento a otra página para confirmar el pago. ```javascript // Initialize Stripe.js const stripe = Stripe('<>'); initialize(); // Fetch Checkout Session and retrieve the client secret async function initialize() { const fetchClientSecret = async () => { const response = await fetch("/create-checkout-session", { method: "POST", }); const { clientSecret } = await response.json(); return clientSecret; }; // Initialize Checkout const checkout = await stripe.createEmbeddedCheckoutPage({ fetchClientSecret, }); // Mount Checkout checkout.mount('#checkout'); } ``` #### React #### Agregar Stripe a tu aplicación de React Instala [React Stripe.js](https://docs.stripe.com/sdks/stripejs-react.md) para cumplir con la normativa PCI, ya que los datos de pago van directamente a Stripe y nunca llegan a tu servidor. ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` #### Cargar Stripe.js Para configurar la biblioteca de Stripe, llama a `loadStripe()` con tu clave de API publicable de Stripe. Crea un `EmbeddedCheckoutProvider`. Pasa la `Promise` devuelta al proveedor. #### Obtener el secreto de cliente de una Checkout Session Crea una función asíncrona `fetchClientSecret` que realice una solicitud a tu servidor para [crear una Checkout Session](https://docs.stripe.com/api/checkout/sessions/create.md) y recuperar el secreto de cliente. #### Inicializar Checkout Para permitir que los componentes secundarios accedan al servicio de Stripe a través del consumidor de Checkout incrustado, pasa la promesa resultante de `loadStripe` y la función `fetchClientSecret` como una `option` al proveedor de Checkout incrustado. ```jsx import * as React from 'react'; import {loadStripe} from '@stripe/stripe-js'; import { EmbeddedCheckoutProvider, EmbeddedCheckout } from '@stripe/react-stripe-js'; // Make sure to call `loadStripe` outside of a component's render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('pk_test_123', { }); const App = ({fetchClientSecret}) => { const options = {fetchClientSecret}; return ( ) } ``` ## Mostrar página de devolución Después de que tu cliente intente realizar el pago, Stripe lo redirige a una página de retorno que alojas en tu sitio web. Cuando creaste la Checkout Session, especificaste la URL de la página de retorno en el parámetro [return_url](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-return_url). > Durante el pago, algunos métodos de pago redirigen al cliente a una página intermedia, como una página de autorización bancaria. Cuando el cliente completa esa página, Stripe lo redirige a tu página de retorno. #### Crear un punto de conexión para recuperar una Checkout Session Añade un punto de conexión para recuperar el estado de una Checkout Session con el ID de la Checkout Session en la URL. #### Recuperar una Checkout Session Para utilizar los datos de la sesión de pago, envía inmediatamente una solicitud al punto final de tu servidor para [recuperar el estado de la Checkout Session](https://docs.stripe.com/api/checkout/sessions/retrieve.md) utilizando el ID de Checkout en la URL tan pronto como se cargue tu página de retorno. #### Manejar la sesión Maneja el resultado establecido en el estado de la sesión: - `complete`: el pago se efectuó correctamente. Usa la información de la Checkout Session para mostrar una página que indique que el pago se realizó correctamente. - `open`: el pago falló o se canceló. Vuelve a montar Checkout para que tu cliente pueda volver a intentarlo. ```js // Retrieve a Checkout Session // Use the session ID initialize(); async function initialize() { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const sessionId = urlParams.get('session_id'); const response = await fetch(`/session-status?session_id=${sessionId}`); const session = await response.json(); // Handle the session according to its status if (session.status == 'open') { // Remount embedded Checkout window.location.replace('http://localhost:4242/checkout.html') } else if (session.status == 'complete') { document.getElementById('success').classList.remove('hidden'); document.getElementById('customer-email').textContent = session.customer_email; // Show success page // Optionally use session.payment_status or session.customer_email // to customize the success page } } ``` ```javascript // Add an endpoint to fetch the Checkout Session status app.get('/session_status', async (req, res) => { const session = await stripe.checkout.sessions.retrieve(req.query.session_id); const customer = await stripe.customers.retrieve(session.customer); res.send({ status: session.status, payment_status: session.payment_status, customer_email: customer.email }); }); ``` ## Optional: Configurar el portal de clientes Puedes configurar el *portal de clientes* (The customer portal is a secure, Stripe-hosted page that lets your customers manage their subscriptions and billing details) para que tus clientes gestionen directamente sus suscripciones y facturas existentes. Puedes configurar el portal en el Dashboard. Para reducir la pérdida de clientes, puedes configurar el portal para que les permita a los clientes actualizar sus métodos de pago en caso de pagos fallidos. Para ayudar a los clientes a encontrarlo, añade un botón en tu sitio web que redirija al portal de clientes para que puedan gestionar su suscripción. Al hacer clic en este botón, el cliente será redirigido a la página del portal de clientes alojada en Stripe. Obtén más información sobre el [portal de clientes](https://docs.stripe.com/customer-management.md) y otras opciones de gestión de clientes. #### Crear una sesión del portal Para añadir un portal de clientes, define un punto de conexión que [cree la sesión del portal de clientes](https://docs.stripe.com/api/customer_portal/sessions/create.md) para que tu front-end la llame. El `CUSTOMER_ID` se refiere al ID de cliente creado por una Checkout Session que guardaste mientras procesabas el webhook `checkout.session.completed`. También puedes establecer un enlace de redirección predeterminado para el portal en el Dashboard. Pasa un valor opcional `return_url` para la página de tu sitio a la que redirigir a tu cliente cuando termine de gestionar tu suscripción: #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' # This is the URL that users are redirected to after they're done # managing their billing. return_url = '{{DOMAIN_URL}}' # Ejemplo: http://example.com customer_id = '{{CUSTOMER_ID}}' # Ejemplo: cus_GBV60HKsE0mb5v session = Stripe::BillingPortal::Session.create({ customer: customer_id, return_url: return_url, }) # Redirect to the URL for the session # redirect session.url, 303 ``` #### Dirigir a los clientes al portal de clientes En tu front end, añade un botón a la página en la dirección `success_url` que proporcione un enlace al portal de clientes: ```html Manage Billing
``` Después de salir del portal de clientes, el cliente vuelve a tu sitio web en la `return_url`. Sigue [monitoreando los eventos](https://docs.stripe.com/billing/subscriptions/webhooks.md) para hacer el seguimiento del estado de la suscripción del cliente. Si configuras el portal de clientes para permitir acciones como la cancelación de una suscripción, asegúrate de supervisar [eventos adicionales](https://docs.stripe.com/customer-management/integrate-customer-portal.md#webhooks). ## Dar acceso If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Cuando la suscripción esté activa, dé a su usuario acceso a su servicio. Para ello, escucha los eventos `customer.subscription.created`, `customer.subscription.updated`, y `customer.subscription.deleted`. Estos eventos pasan un objeto `Subscription` que contiene un campo `status` que indica si la suscripción está activa, vencida o cancelada. Consulta el [ciclo de vida de la suscripción](https://docs.stripe.com/billing/subscriptions/overview.md#subscription-lifecycle) para obtener una lista completa de estados. Para gestionar el acceso a la funcionalidad de su producto, infórmate sobre [la integración de derechos](https://docs.stripe.com/billing/entitlements.md). En tu controlador de webhook: 1. Verifica el estado de la suscripción. Si es `active`, tu usuario ha pagado por su producto. 1. Comprueba el producto al que se ha suscrito tu cliente y concédele acceso a tu servicio. Al comprobar el producto en lugar del precio, podrás cambiar el precio o el período de facturación según sea necesario. 1. Almacena el `product.id`, `subscription.id` y `subscription.status` en tu base de datos junto con `customer.id` que ya guardaste. Consulta este registro cuando tengas que determinar qué funcionalidades habilitar para el usuario en tu aplicación. El estado de la suscripción puede cambiar en cualquier momento de su ciclo de vida, incluso si tu solicitud no hace ninguna llamada directa a Stripe. Por ejemplo, se puede producir un error de renovación debido a una tarjeta de crédito vencida, lo que genera que el estado de la suscripción pase a vencido. O, si usas el [portal de clientes](https://docs.stripe.com/customer-management.md), un usuario puede optar por cancelar la suscripción sin ingresar a tu aplicación directamente. El uso correcto del controlador mantiene el estado de tu solicitud sincronizado con Stripe. ## Prueba la integración ### Prueba métodos de pago Usa la siguiente tabla para probar diferentes métodos y escenarios de pago. | Método de pago | Escenario | Cómo hacer la prueba | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Débito directo BECS | Tu cliente paga correctamente con débito directo BECS. | Completa el formulario con el número de cuenta `900123456` y BSB `000000`. El PaymentIntent confirmado pasa en un principio al estado `processing` y, tres minutos más tarde, a `succeeded`. | | Débito directo BECS | El pago de tu cliente falla con un código de error `account_closed`. | Completa el formulario con el número de cuenta `111111113` y BSB `000000`. | | Tarjeta de crédito | El pago con tarjeta se efectúa correctamente y no requiere autenticación. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4242 4242 4242 4242` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | El pago con tarjeta requiere *autenticación* (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). | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0025 0000 3155` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | La tarjeta es rechazada con el código `insufficient_funds`. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0000 0000 9995` y cualquier fecha de vencimiento, CVC y código postal. | | Débito directo SEPA | Tu cliente paga correctamente con débito directo SEPA. | Completa el formulario con el número de cuenta `AT321904300235473204`. El PaymentIntent confirmado pasa inicialmente al estado “en proceso” y, tres minutos más tarde, a “completado”. | | Débito directo SEPA | El estado de PaymentIntent de tu cliente pasa de `processing` a `requires_payment_method`. | Completa el formulario con el número de cuenta `AT861904300235473202`. | ### Supervisa los acontecimientos Configura webhooks para escuchar los eventos de cambio de suscripción, como actualizaciones y cancelaciones. Puedes ver [eventos de webhook de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md) en el [Dashboard](https://dashboard.stripe.com/test/events) o con el [Stripe CLI](https://docs.stripe.com/webhooks.md#test-webhook). Obtén más información sobre [Comprobación de la integración con Billing](https://docs.stripe.com/billing/testing.md). #### Elements #### Checkout Sessions API #### Esfuerzo de integración Complexity: 3/5 #### Tipo de integración Combina componentes de la interfaz de usuario (IU) en un flujo de pago personalizado #### Personalización de la interfaz de usuario (IU) Personalización a nivel CSS con la [API Appearance](https://docs.stripe.com/elements/appearance-api.md) [Pruébalo ](https://checkout.stripe.dev/) Crea un formulario de pago personalizado con [Stripe Elements](https://docs.stripe.com/payments/elements.md) y la [API Checkout Sessions](https://docs.stripe.com/api/checkout/sessions.md) para vender *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) a un precio fijo. Comprueba cómo esta integración [se compara con otros tipos de integraciones de Stripe](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability). La API Checkout Sessions ofrece soporte integrado para cálculo de impuestos, descuentos, envío y conversión de monedas, lo que reduce la cantidad de código personalizado que debes escribir. Este es el enfoque recomendado para la mayoría de las integraciones. Obtén más información sobre [cuándo usar Checkout Sessions en lugar de PaymentIntents](https://docs.stripe.com/payments/checkout-sessions-and-payment-intents-comparison.md). Si no deseas crear un formulario de pago personalizado, puedes integrarlo en la versión alojada del proceso de compra. Si deseas una versión completa de esa guía de integración, consulta la [Guía de inicio rápido](https://docs.stripe.com/billing/quickstart.md) de Billing. Si no estás listo para programar una integración, puedes configurar suscripciones básicas [de forma manual en el Dashboard](https://docs.stripe.com/no-code/subscriptions.md). También puedes usar [Payment Links](https://docs.stripe.com/payment-links.md) para configurar suscripciones sin programar nada. Obtén más información sobre [cómo diseñar una integración](https://docs.stripe.com/billing/subscriptions/design-an-integration.md) para comprender las decisiones que debes tomar y los recursos que necesitas. ## Tu próximo desarrollo Esta guía te explica cómo: - Modelar tu empresa creando un catálogo de productos. - Crear un proceso de inscripción que genere un cliente. - Crear suscripciones y recopilar información de pago. - Comprobar y monitorear el estado de los pagos y las suscripciones. - Permitir que los clientes cambien de plan o cancelen la suscripción. ### Definiciones de los objetos de la API | Recurso | Definición | | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Cuenta configurada como un cliente](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) | Representa a un cliente en la API Accounts v2 que compra una suscripción. Configura un objeto `Cuenta` como cliente y asócialo a una suscripción para realizar cargos recurrentes y hacerles un seguimiento, y para gestionar los productos a los que se suscribe. Consulta nuestra [guía Usar cuentas como clientes](https://docs.stripe.com/connect/use-accounts-as-customers.md) para obtener más información. | | [Customer](https://docs.stripe.com/api/customers.md) | Representa a un cliente en la API Clientes que compra una suscripción. Usa el objeto `Cliente` asociado a una suscripción para realizar y hacer seguimiento de los cargos recurrentes y administrar los productos a los que se suscriben. | | [Derecho](https://docs.stripe.com/api/entitlements/active-entitlement.md) | Representa el acceso de un cliente a una funcionalidad incluida en un producto de servicio al que está suscrito. Cuando creas una suscripción para la compra recurrente de un producto por parte de un cliente, se crea automáticamente un derecho activo para cada funcionalidad asociada a ese producto. Cuando un cliente accede a tus servicios, utiliza sus derechos activos para habilitar las funcionalidades incluidas en su suscripción. | | [Funcionalidad](https://docs.stripe.com/api/entitlements/feature.md) | Representa una funcionalidad o capacidad a la que tus clientes pueden acceder cuando se suscriben a un producto de servicio. Puedes incluir funciones en un producto creando ProductFeatures. | | [Factura](https://docs.stripe.com/api/invoices.md) | Una declaración de importes que un cliente adeuda y que rastrea los estados de pago desde el borrador hasta su pago o su finalización. Las suscripciones generan facturas automáticamente. | | [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) | Una forma de crear flujos de pago dinámicos. Un PaymentIntent hace un seguimiento del ciclo de vida del flujo del proceso compra del cliente y activa pasos adicionales de autenticación, si así lo exigen las disposiciones normativas, las reglas antifraude personalizadas de Radar o los métodos de pago con redireccionamiento. Las facturas crean PaymentIntents de forma automática. | | [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) | Los métodos de pago que usa un cliente para pagar tus productos. Por ejemplo, puedes guardar una tarjeta de crédito en un objeto `Cuenta` o `Cliente` configurado por el cliente y usarla para hacer pagos recurrentes para ese cliente. Por lo general, se usa con las API Payment Intents o Setup Intents. | | [Precio](https://docs.stripe.com/api/prices.md) | Define el precio por unidad, la moneda y el ciclo de facturación para un producto. | | [Producto](https://docs.stripe.com/api/products.md) | Un bien o servicio que vende tu empresa. Un producto de servicio puede incluir una o más funciones. | | [ProductFeature](https://docs.stripe.com/api/product-feature.md) | Representa la inclusión de una sola funcionalidades en un solo producto. Cada producto está asociado a una ProductFeature para cada funcionalidad que incluye, y cada funcionalidad está asociada a una ProductFeature para cada producto que la incluye. | | [Suscripción](https://docs.stripe.com/api/subscriptions.md) | Representa la compra recurrente programada de un producto por parte de un cliente. Usa una suscripción para cobrar pagos y proporcionar entrega repetida o acceso continuo a un producto. | Veamos un ejemplo de cómo funcionan juntos los productos, las funcionalidades y los derechos. Imagina que quieres configurar un servicio recurrente que ofrezca dos niveles: un producto estándar con funcionalidad básica y un producto avanzado que agregue funcionalidad extendida. 1. Creas dos funcionalidades: `basic_features` y `extended_features`. 1. Creas dos productos: `standard_product` y `advanced_product`. 1. Para el producto estándar, creas una ProductFeature que asocia `basic_features` con `standard_product`. 1. Para el producto avanzado, creas dos ProductFeatures: una que asocia `basic_features` con `advanced_product` y otra que asocia `extended_features` con `advanced_product`. Un cliente, `first_customer`, se suscribe al producto estándar. Cuando creas la suscripción, Stripe crea automáticamente un derecho que asocia `first_customer` con `basic_features`. Otro cliente, `second_customer`, se suscribe al producto avanzado. Al crear la suscripción, Stripe crea automáticamente dos derechos: uno que asocia `second_customer` con `basic_features` y otro que asocia `second_customer` con `extended_features`. Puedes determinar qué funcionalidades aprovisionar para un cliente [recuperando sus derechos activos o recibiendo notificaciones del evento Resumen de derechos activos](https://docs.stripe.com/billing/entitlements.md#entitlements). No tienes que recuperar sus suscripciones, productos y funcionalidades. ## Configura Stripe Instala el cliente de Stripe que prefieras: #### 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' ``` A continuación, instala la CLI de Stripe. La CLI proporciona pruebas de webhook y puedes ejecutarla para realizar llamadas API a Stripe. Esta guía muestra cómo utilizar la CLI para configurar un modelo de precios en una sección posterior. Para obtener más opciones de instalación, consulta [Empezar a usar la CLI de Stripe](https://docs.stripe.com/stripe-cli.md). ## Crear el modelo de tarifas [CLI o Dashboard de Stripe] Los [modelos de precios recurrentes](https://docs.stripe.com/products-prices/pricing-models.md) representan los productos o servicios que vendes, cuánto cuestan, qué monedas aceptas para los pagos y el período de servicio para las suscripciones. Para crear el modelo de precios, crea [productos](https://docs.stripe.com/api/products.md) (lo que vendes) y [precios](https://docs.stripe.com/api/prices.md) (cuánto cuestan y con qué frecuencia cobrar por los productos). En este ejemplo, se utiliza una tarifa con tasa fija con dos opciones de niveles de servicio diferentes: básico y premium. Para cada opción de nivel de servicio, debes crear un producto y un precio recurrente. Si quieres agregar un cargo por única vez, como el costo de instalación, crea un tercer producto con un precio por única vez. Cada producto se factura de forma mensual. El precio del producto básico es de 5 USD. El precio del producto premium es de 15 USD. Consulta la guía de [tarifas con tasa fija](https://docs.stripe.com/subscriptions/pricing-models/flat-rate-pricing.md) para ver un ejemplo con tres niveles. #### Dashboard Ve a la página [Agregar un producto](https://dashboard.stripe.com/test/products/create) y crea dos productos. Agrega un precio a cada producto, cada uno con un período de facturación mensual recurrente: - Producto prémium: servicio prémium con más funcionalidades - Precio: Tarifa plana | 15 USD - Producto básico: servicio básico con las funcionalidades mínimas - Precio: Tarifa plana | 5 USD Después de crear los precios, registra los ID de precio para usarlos en otros pasos. Los ID de precio se ven así: `price_G0FvDp6vZvdwRZ`. Cuando esté todo listo, usa el botón **Copiar en modo activo**, en la parte superior derecha de la página, para clonar el producto y pasarlo de [entorno de prueba a modo activo](https://docs.stripe.com/keys.md#test-live-modes). #### API Puedes usar la API para crear los [productos](https://docs.stripe.com/api/products.md) y los [precios](https://docs.stripe.com/api/prices.md). Crear el producto premium: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Premium Service" \ -d "description=Premium service with extra features" ``` Crear el producto básico: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Basic Service" \ -d "description=Basic service with minimum features" ``` Registra el ID de cada producto. Se ve así: ```json { "id": "prod_H94k5odtwJXMtQ", "object": "product", "active": true, "attributes": [ ], "created": 1587577341, "description": "Premium service with extra features", "images": [ ], "livemode": false, "metadata": { }, "name": "Billing Guide: Premium Service", "statement_descriptor": null, "type": "service", "unit_label": null, "updated": 1587577341 } ``` Usa los ID de producto para crear el precio de cada producto. El número [unit_amount](https://docs.stripe.com/api/prices/object.md#price_object-unit_amount) está en centavos. Por ejemplo, `1500` = 15 USD. Crear el precio superior: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{PREMIUM_PRODUCT_ID}} \ -d unit_amount=1500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Crear el precio básico: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{BASIC_PRODUCT_ID}} \ -d unit_amount=500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Registra el ID de cada precio para poder utilizarlo en los pasos siguientes. Se ve así: ```json { "id": "price_HGd7M3DV3IMXkC", "object": "price", "product": "prod_HGd6W1VUqqXGvr", "type": "recurring", "currency": "usd", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "active": true, "billing_scheme": "per_unit", "created": 1589319695, "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "unit_amount": 1500, "unit_amount_decimal": "1500", "tiers": null, "tiers_mode": null, "transform_quantity": null } ``` ## Crear el cliente [Cliente y servidor] If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Stripe requiere un *Cliente* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) para cada suscripción. En el front-end de tu aplicación, recopila toda la información necesaria de tus usuarios y envíala al back-end. Si necesitas recopilar datos de la dirección, el Address Element te permite reunir una dirección de envío o facturación de tus clientes. Obtén más información sobre el Address Element en la página [Address Element](https://docs.stripe.com/elements/address-element.md). ```html
``` ```javascript const emailInput = document.querySelector('#email'); fetch('/create-customer', { method: 'post', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email: emailInput.value, }), }).then(r => r.json()); ``` Crea el objeto Customer de Stripe en el servidor. > Asegúrate de almacenar el [ID del cliente](https://docs.stripe.com/api/customers/object.md#customer_object-id) para usar en la Checkout Session ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -d email={{CUSTOMER_EMAIL}} \ -d name={{CUSTOMER_NAME}} \ -d "shipping[address][city]=Brothers" \ -d "shipping[address][country]=US" \ -d "shipping[address][line1]=27 Fredrick Ave" \ -d "shipping[address][postal_code]=97712" \ -d "shipping[address][state]=CA" \ -d "shipping[name]={{CUSTOMER_NAME}}" \ -d "address[city]=Brothers" \ -d "address[country]=US" \ -d "address[line1]=27 Fredrick Ave" \ -d "address[postal_code]=97712" \ -d "address[state]=CA" ``` ## Crea una Checkout Session [Servidor] En el back-end de su aplicación, define un punto de conexión que [cree la sesión](https://docs.stripe.com/api/checkout/sessions/create.md) para que tu front-end la llame. Necesitarás el ID de precio de la suscripción que el cliente está contratando; tu front-end pasa este valor. Si creaste un precio único en el [paso 2](https://docs.stripe.com/billing/subscriptions/build-subscriptions.md#create-pricing-model), pasa también ese ID de precio. Después de crear una Checkout Session, asegúrate de pasar el [secreto de cliente](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-client_secret) de vuelta al cliente en la respuesta. > Puedes utilizar [lookup_keys](https://docs.stripe.com/products-prices/manage-prices.md#lookup-keys) para obtener precios en lugar de ID de precios. Consulta la [solicitud de ejemplo](https://github.com/stripe-samples/subscription-use-cases/tree/main/fixed-price-subscriptions) para ver un ejemplo. #### Ruby ```ruby require 'stripe' require 'sinatra' # This test secret API key is a placeholder. Don't include personal details in requests with this key. # To see your test secret API key embedded in code samples, sign in to your Stripe account. # You can also find your test secret API key at https://dashboard.stripe.com/test/apikeys. Stripe.api_key = '<>' Stripe.api_version = '2026-03-25.dahlia' set :static, true set :port, 4242 YOUR_DOMAIN = 'http://localhost:3000' post '/create-checkout-session' do content_type 'application/json' session = Stripe::Checkout::Session.create({ui_mode: 'elements', # Provide the customer ID of the customer you previously created customer: '{{CUSTOMER_ID}}', line_items: [{ # Provide the exact Price ID (for example, price_1234) of the product you want to sell price: '{{PRICE_ID}}', quantity: 1, }], mode: 'subscription', return_url: YOUR_DOMAIN + '/return?session_id={CHECKOUT_SESSION_ID}', }) { clientSecret: session.client_secret }.to_json end ``` Desde tu [Dashboard](https://dashboard.stripe.com/settings/payment_methods), activa los métodos de pago que deseas aceptar de tus clientes. Checkout admite [varios métodos de pago](https://docs.stripe.com/payments/payment-methods/payment-method-support.md#product-support). ## Inicializar Checkout [Cliente] #### HTML + JS Llama a [initCheckoutElementsSdk](https://docs.stripe.com/js/custom_checkout/init) y pasa `clientSecret`. `initCheckoutElementsSdk` resuelve un objeto de [Checkout](https://docs.stripe.com/js/custom_checkout) que contiene datos de la Checkout Session y métodos para actualizarla. Lee el `total` y los `lineItems` de [actions.getSession()](https://docs.stripe.com/js/custom_checkout/session) y muéstralos en tu interfaz de usuario (IU). Esto te permite activar nuevas funcionalidades con cambios mínimos en el código. Por ejemplo, si agregas [precios manuales de monedas](https://docs.stripe.com/payments/custom/localize-prices/manual-currency-prices.md), no es necesario hacer cambios en la interfaz de usuario (IU) si muestras el `total`. ```html
``` ```javascript const clientSecret = fetch('/create-checkout-session', {method: 'POST'}) .then((response) => response.json()) .then((json) => json.client_secret); const checkout = stripe.initCheckoutElementsSdk({clientSecret}); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const session = loadActionsResult.actions.getSession(); const checkoutContainer = document.getElementById('checkout-container'); checkoutContainer.append(JSON.stringify(session.lineItems, null, 2)); checkoutContainer.append(document.createElement('br')); checkoutContainer.append(`Total: ${session.total.total.amount}`); } ``` #### React Integra la solicitud con el componente [CheckoutProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider), pasa `clientSecret` y la instancia `stripe`. ```jsx import React from 'react'; import {CheckoutElementsProvider} from '@stripe/react-stripe-js/checkout'; import CheckoutForm from './CheckoutForm'; const clientSecret = fetch('/create-checkout-session', {method: 'POST'}) .then((response) => response.json()) .then((json) => json.client_secret); const App = () => { return ( ); }; export default App; ``` Accede al objeto [Checkout](https://docs.stripe.com/js/custom_checkout) en el componente del formulario de confirmación de compra con el hook `useCheckout()`. El objeto `Checkout` contiene datos de la sesión de confirmación de compra y métodos para actualizarla. Lee el `total` y los `lineItems` del objeto `Checkout` y muéstralos en tu interfaz de usuario (IU). Esto te permite habilitar funcionalidades con cambios mínimos de código. Por ejemplo, agregar [precios manuales de monedas](https://docs.stripe.com/payments/custom/localize-prices/manual-currency-prices.md) no requiere cambios en la interfaz de usuario (IU) si muestras el `total`. ```jsx import React from 'react'; import {useCheckout} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => {const checkoutState = useCheckout(); if (checkoutState.type === 'loading') { return (
Loading...
); } if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } return (
{JSON.stringify(checkoutState.checkout.lineItems, null, 2)} {/* A formatted total amount */} Total: {checkoutState.checkout.total.total.amount}
); }; ``` ## Recopila datos de pago [Cliente] Recopila los datos de pago del cliente con el [Payment Element](https://docs.stripe.com/payments/payment-element.md). Payment Element es un componente de interfaz de usuario prediseñado que simplifica la recopilación de datos de pago para una variedad de métodos de pago. El Payment Element contiene un iframe que envía la información de pago a Stripe de manera segura mediante una conexión HTTPS. No coloques el Payment Element dentro de otro iframe porque, para algunos métodos de pago, se requiere la redirección a otra página para la confirmación del pago. Si optas por usar un iframe y quieres aceptar Apple Pay o Google Pay, el iframe debe tener el atributo [allow](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allowpaymentrequest) establecido en `«payment*»`. Para que la integración funcione, la dirección de la página del proceso de compra debe empezar con `https://` rather en lugar de `http://` for. Puedes probar tu integración sin usar HTTPS, pero recuerda [habilitarla](https://docs.stripe.com/security/guide.md#tls) cuando todo esté listo para aceptar pagos activos. #### HTML + JS En primer lugar, crea un elemento DOM contenedor para montar el [Payment Element](https://docs.stripe.com/payments/payment-element.md). Luego, crea una instancia del `Payment Element` usando [checkout.createPaymentElement](https://docs.stripe.com/js/custom_checkout/create_payment_element) y móntala llamando a [element.mount](https://docs.stripe.com/js/element/mount), proporcionando un selector CSS o el elemento DOM contenedor. ```html
``` ```javascript const paymentElement = checkout.createPaymentElement(); paymentElement.mount('#payment-element'); ``` Consulta la [documentación Stripe.js](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options) para ver las opciones admitidas. Puedes [personalizar el aspecto](https://docs.stripe.com/payments/checkout/customization/appearance.md) de todos los Elements pasando [elementsOptions.appearance](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-elementsOptions-appearance) al inicializar Checkout en el front-end. #### React Arma el componente [Payment Element](https://docs.stripe.com/payments/payment-element.md) dentro del [CheckoutElementsProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider). ```jsx import React from 'react';import {PaymentElement, useCheckout} from '@stripe/react-stripe-js/checkout'; const CheckoutForm = () => { const checkoutState = useCheckout(); if (checkoutState.type === 'loading') { return (
Loading...
); } if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } return (
{JSON.stringify(checkoutState.checkout.lineItems, null, 2)} {/* A formatted total amount */} Total: {checkoutState.checkout.total.total.amount} ); }; export default CheckoutForm; ``` Consulta la [documentación Stripe.js](https://docs.stripe.com/js/custom_checkout/create_payment_element#custom_checkout_create_payment_element-options) para ver las opciones admitidas. Puedes [personalizar el aspecto](https://docs.stripe.com/payments/checkout/customization/appearance.md) de todos los Elements especificando [elementsOptions.appearance](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider#react_checkout_provider-options-elementsOptions-appearance) en el [CheckoutElementsProvider](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider). ## Envía el pago [Lado del cliente] #### HTML + JS Presenta un botón **Pagar** que llame a [confirmar](https://docs.stripe.com/js/custom_checkout/confirm) desde la instancia de `Checkout` para enviar el pago. ```html
``` ```js const checkout = stripe.initCheckoutElementsSdk({clientSecret}); checkout.on('change', (session) => { document.getElementById('pay-button').disabled = !session.canConfirm; }); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const {actions} = loadActionsResult; const button = document.getElementById('pay-button'); const errors = document.getElementById('confirm-errors'); button.addEventListener('click', () => { // Clear any validation errors errors.textContent = ''; actions.confirm().then((result) => { if (result.type === 'error') { errors.textContent = result.error.message; } }); }); } ``` #### React Renderiza un botón **Pagar** que pase de[confirmar](https://docs.stripe.com/js/custom_checkout/confirm) a[useCheckout](https://docs.stripe.com/js/react_stripe_js/checkout/use_checkout) para enviar el pago. ```jsx import React from 'react'; import {useCheckout} from '@stripe/react-stripe-js/checkout'; const PayButton = () => { const checkoutState = useCheckout(); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); if (checkoutState.type !== "success") { return null; } const handleClick = () => { setLoading(true);checkoutState.checkout.confirm().then((result) => { if (result.type === 'error') { setError(result.error) } setLoading(false); }) }; return (
{error &&
{error.message}
}
) }; export default PayButton; ``` ## Escucha webhooks [Servidor] Para completar la integración, tienes que procesar los *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) que envió Stripe. Estos son eventos que se originan cada vez que un estado dentro de Stripe cambia, por ejemplo, cuando las suscripciones crean facturas nuevas. En tu aplicación, configura un controlador de HTTP para aceptar una solicitud POST que contenga el evento de webhook y verifica la firma del evento: #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/webhook' do # You can use webhooks to receive information about asynchronous payment events. # For more about our webhook events check out https://stripe.com/docs/webhooks. webhook_secret = ENV['STRIPE_WEBHOOK_SECRET'] payload = request.body.read if !webhook_secret.empty? # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured. sig_header = request.env['HTTP_STRIPE_SIGNATURE'] event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, webhook_secret ) rescue JSON::ParserError => e # Invalid payload status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature puts '⚠️ Webhook signature verification failed.' status 400 return end else data = JSON.parse(payload, symbolize_names: true) event = Stripe::Event.construct_from(data) end # Get the type of webhook event sent - used to check the status of PaymentIntents. event_type = event['type'] data = event['data'] data_object = data['object'] if event_type == 'invoice.paid' # Used to provision services after the trial has ended. # The status of the invoice will show up as paid. Store the status in your # database to reference when a user accesses your service to avoid hitting rate # limits. # puts data_object end if event_type == 'invoice.payment_failed' # If the payment fails or the customer doesn't have a valid payment method, # an invoice.payment_failed event is sent, the subscription becomes past_due. # Use this webhook to notify your user that their payment has # failed and to retrieve new card details. # puts data_object end if event_type == 'customer.subscription.deleted' # handle subscription canceled automatically based # upon your subscription settings. Or if the user cancels it. # puts data_object end content_type 'application/json' { status: 'success' }.to_json end ``` Durante el desarrollo, utiliza la CLI de Stripe para [observar los webhooks y reenviarlos a tu solicitud](https://docs.stripe.com/webhooks.md#test-webhook). Ejecuta lo siguiente en un terminal nuevo mientras se ejecuta tu aplicación de desarrollo: #### curl ```bash stripe listen --forward-to localhost:4242/webhook ``` Para la producción, configura una URL de punto de conexión webhook en el Dashboard o utiliza la [API de puntos de conexión webhook](https://docs.stripe.com/api/webhook_endpoints.md) . Necesitas escuchar algunos eventos para completar los pasos restantes de esta guía. Consulta [Eventos de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md#events) para obtener más detalles sobre los webhooks específicos de suscripción. ## Brindar acceso a tu servicio [Cliente y servidor] Ahora que la suscripción está activa, dale a tu usuario acceso a tu servicio. Para ello, escucha los eventos `customer.subscription.created`, `customer.subscription.updated`, y `customer.subscription.deleted`. Estos eventos pasan un objeto Subscription que contiene un campo `status` que indica si la suscripción está activa, vencida o cancelada. Consulta [el ciclo de vida de la suscripción](https://docs.stripe.com/billing/subscriptions/overview.md#subscription-lifecycle) para obtener una lista completa de estados. En tu controlador de webhook: 1. Verifica el estado de la suscripción. Si es `activo`, entonces tu usuario ha pagado por su producto. 1. Revisa el producto al que se suscribió el cliente y bríndale acceso al servicio. Es mejor revisar el producto que el precio porque te da más flexibilidad en caso de que tengas que cambiar el precio o el período de facturación. 1. Almacena el `product.id`, `subscription.id` y el `subscription.status` en tu base de datos junto con `customer.id` que ya guardaste. Consulta este registro cuando tengas que determinar qué funcionalidades habilitar para el usuario en tu aplicación. El estado de la suscripción puede cambiar en cualquier momento de su ciclo de vida, incluso si tu solicitud no hace ninguna llamada directa a Stripe. Por ejemplo, se puede producir un error de renovación debido a una tarjeta de crédito vencida, lo que genera que el estado de la suscripción pase a vencido. O, si usas el [portal de clientes](https://docs.stripe.com/customer-management.md), un usuario puede optar por cancelar la suscripción sin ingresar a tu aplicación directamente. El uso correcto del controlador mantiene el estado de tu solicitud sincronizado con Stripe. ## Cancelación de la suscripción [Cliente y servidor] Con frecuencia, se les permite a los clientes cancelar su suscripción. En este ejemplo, se agrega la opción de cancelación en la página de configuración de la cuenta. ![Ejemplo de interfaz de cancelación de suscripción.](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-subscriptions-guide-account-settings.6559626ba4b434826a67abfea165e097.png) Configuración de la cuenta con la posibilidad de cancelar la suscripción ```javascript function cancelSubscription(subscriptionId) { return fetch('/cancel-subscription', { method: 'post', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ subscriptionId: subscriptionId, }), }) .then(response => { return response.json(); }) .then(cancelSubscriptionResponse => { // Display to the user that the subscription has been canceled. }); } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/cancel-subscription' do content_type 'application/json' data = JSON.parse request.body.read deleted_subscription = Stripe::Subscription.cancel(data['subscriptionId']) deleted_subscription.to_json end ``` En tu aplicación, se recibe un evento `customer.subscription.deleted`. Una vez que se cancela la suscripción, actualiza tu base de datos para eliminar el ID de suscripción a Stripe que estaba almacenado y limitar el acceso al servicio. Cuando se cancela una suscripción, no se puede reactivar. En su lugar, recopila la información de facturación actualizada de tu cliente, actualiza su método de pago predeterminado y crea una nueva suscripción con su registro de cliente existente. ## Prueba la integración ### Prueba métodos de pago Usa la siguiente tabla para probar diferentes métodos y escenarios de pago. | Método de pago | Escenario | Cómo hacer la prueba | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Débito directo BECS | Tu cliente paga correctamente con débito directo BECS. | Completa el formulario con el número de cuenta `900123456` y BSB `000000`. El PaymentIntent confirmado pasa en un principio al estado `processing` y, tres minutos más tarde, a `succeeded`. | | Débito directo BECS | El pago de tu cliente falla con un código de error `account_closed`. | Completa el formulario con el número de cuenta `111111113` y BSB `000000`. | | Tarjeta de crédito | El pago con tarjeta se efectúa correctamente y no requiere autenticación. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4242 4242 4242 4242` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | El pago con tarjeta requiere *autenticación* (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). | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0025 0000 3155` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | La tarjeta es rechazada con el código `insufficient_funds`. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0000 0000 9995` y cualquier fecha de vencimiento, CVC y código postal. | | Débito directo SEPA | Tu cliente paga correctamente con débito directo SEPA. | Completa el formulario con el número de cuenta `AT321904300235473204`. El PaymentIntent confirmado pasa inicialmente al estado “en proceso” y, tres minutos más tarde, a “completado”. | | Débito directo SEPA | El estado de PaymentIntent de tu cliente pasa de `processing` a `requires_payment_method`. | Completa el formulario con el número de cuenta `AT861904300235473202`. | ### Supervisa los acontecimientos Configura webhooks para escuchar los eventos de cambio de suscripción, como actualizaciones y cancelaciones. Más información sobre [webhooks de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md). Puedes ver los eventos en el [Dashboard](https://dashboard.stripe.com/test/events) o con [Stripe CLI](https://docs.stripe.com/webhooks.md#test-webhook). Para más detalles, consulta [Comprobación de la integración con Billing](https://docs.stripe.com/billing/testing.md). ## Optional: Permitir que los clientes cambien de plan [Cliente y servidor] Para permitirles a los clientes cambiar de suscripción, recopila el ID de precio de la opción a la que quieren pasar. A continuación, envía el nuevo ID de precio desde el front-end a un punto de conexión del back-end. En el ejemplo, también se especifica el ID de suscripción, pero puedes recuperarlo de tu base de datos para el usuario que ha iniciado sesión. ```javascript function updateSubscription(priceId, subscriptionId) { return fetch('/update-subscription', { method: 'post', headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ subscriptionId: subscriptionId, newPriceId: priceId, }), }) .then(response => { return response.json(); }) .then(response => { return response; }); } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada especificando el ID de suscripción y el nuevo ID de precio. La suscripción ahora es una suscripción prémium que cuesta USD 15 por mes en lugar de una suscripción básica de USD 5 por mes. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/update-subscription' do content_type 'application/json' data = JSON.parse request.body.read subscription = Stripe::Subscription.retrieve(data['subscriptionId']) updated_subscription = Stripe::Subscription.update( data['subscriptionId'], cancel_at_period_end: false, items: [ { id: subscription.items.data[0].id, price: data['newPriceId'] } ] ) updated_subscription.to_json end ``` En tu aplicación, se recibe un evento `customer.subscription.updated`. ## Optional: Previsualizar un cambio de precio [Cliente y servidor] Cuando tu cliente cambia de suscripción, a menudo se produce un ajuste del importe que debe, conocido como [prorrateo](https://docs.stripe.com/billing/subscriptions/prorations.md). Puedes utilizar el [punto de conexión de creación de factura preliminar](https://docs.stripe.com/api/invoices/create_preview.md) para mostrar el importe ajustado a tus clientes. En el front-end, pasa los detalles de creación de vista previa de la factura a un punto de conexión de back-end. ```javascript function createPreviewInvoice( customerId, subscriptionId, newPriceId, trialEndDate ) { return fetch('/create-preview-invoice', { method: 'post', headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ customerId: customerId, subscriptionId: subscriptionId, newPriceId: newPriceId, }), }) .then(response => { return response.json(); }) .then((invoice) => { return invoice; }); } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/create-preview-invoice' do content_type 'application/json' data = JSON.parse request.body.read subscription = Stripe::Subscription.retrieve(data['subscriptionId']) invoice = Stripe::Invoice.create_preview( customer: data['customerId'], subscription: data['subscriptionId'], subscription_details: { items: [ { id: subscription.items.data[0].id, deleted: true }, { price: data['newPriceId'], deleted: false } ] } ) invoice.to_json end ``` ## Optional: Mostrar el método de pago del cliente [Cliente y servidor] Mostrar la marca y los últimos 4 dígitos de la tarjeta le permite saber al cliente qué tarjeta se está utilizando o si es necesario actualizar el método de pago. En el front end, envía el identificador del método de pago a un punto de conexión que recupere los detalles del método de pago. ```javascript function retrieveCustomerPaymentMethod(paymentMethodId) { return fetch('/retrieve-customer-payment-method', { method: 'post', headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ paymentMethodId: paymentMethodId, }), }) .then((response) => { return response.json(); }) .then((response) => { return response; }); } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/retrieve-customer-payment-method' do content_type 'application/json' data = JSON.parse request.body.read payment_method = Stripe::PaymentMethod.retrieve(data['paymentMethodId']) payment_method.to_json end ``` Ejemplo de respuesta: ```json { "id": "pm_1GcbHY2eZvKYlo2CoqlVxo42", "object": "payment_method", "billing_details": { "address": { "city": null, "country": null, "line1": null, "line2": null, "postal_code": null, "state": null }, "email": null, "name": null, "phone": null }, "card": { "brand": "visa", "checks": { "address_line1_check": null, "address_postal_code_check": null, "cvc_check": "pass" }, "country": "US", "exp_month": 8, "exp_year": 2021, "fingerprint": "Xt5EWLLDS7FJjR1c", "funding": "credit", "generated_from": null, "last4": "4242", "three_d_secure_usage": { "supported": true }, "wallet": null }, "created": 1588010536, "customer": "cus_HAxB7dVQxhoKLh", "livemode": false, "metadata": {}, "type": "card" } ``` > Te recomendamos guardar `paymentMethod.id` y `last4` en tu base de datos, por ejemplo, `paymentMethod.id` como `stripeCustomerPaymentMethodId` en tu colección o tabla de `users`. Si lo necesitas, también tienes la opción de guardar `exp_month`, `exp_year`, `fingerprint` y `billing_details`. Esto sirve para limitar el número de llamadas a Stripe, mejorar el rendimiento y evitar una posible limitación de la frecuencia. ## Cuéntales a tus clientes qué es Stripe Stripe recopila información sobre las interacciones de los clientes con Elements para proporcionarte servicios, mejorarlos y prevenir el fraude. Esto incluye el uso de cookies y direcciones IP para identificar qué Elements vio un cliente durante una sola sesión de finalización de compra. Tienes la responsabilidad de divulgar y obtener todos los derechos y consentimientos necesarios para que Stripe use los datos para dichos fines. Si deseas obtener más información, visita nuestro [centro de privacidad](https://stripe.com/legal/privacy-center#as-a-business-user-what-notice-do-i-provide-to-my-end-customers-about-stripe). #### API Payment Intents #### Esfuerzo de integración Complexity: 4/5 #### Tipo de integración Combina componentes de la interfaz de usuario (IU) en un flujo de pago personalizado #### Personalización de la interfaz de usuario (IU) Personalización a nivel CSS con la [API Appearance](https://docs.stripe.com/elements/appearance-api.md) If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Crea un formulario de pago personalizado con [Stripe Elements](https://docs.stripe.com/payments/elements.md) y la [API Payment Intents](https://docs.stripe.com/api/payment_intents.md) para vender *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) a un precio fijo. Comprueba cómo esta integración [se compara con otros tipos de integraciones de Stripe](https://docs.stripe.com/payments/online-payments.md#compare-features-and-availability). La API Payment Intents es una API de nivel más bajo que puedes usar para crear tu propio flujo de pago o de confirmación de compra, pero requiere significativamente más código y mantenimiento constante. Recomendamos [Payment Element con Checkout Sessions](https://docs.stripe.com/payments/quickstart-checkout-sessions.md) para la mayoría de las integraciones, ya que cubre flujos de pago similares a los de Payment Intents. Obtén más información sobre [cuándo usar Checkout Sessions en lugar de PaymentIntents](https://docs.stripe.com/payments/checkout-sessions-and-payment-intents-comparison.md). Si no deseas crear un formulario de pago personalizado, puedes integrarlo en la versión alojada del proceso de compra. Si deseas una versión completa de esa guía de integración, consulta la [Guía de inicio rápido de Billing](https://docs.stripe.com/billing/quickstart.md). Si no estás listo para programar una integración, puedes configurar suscripciones básicas [de forma manual en el Dashboard](https://docs.stripe.com/no-code/subscriptions.md). También puedes usar [Payment Links](https://docs.stripe.com/payment-links.md) para configurar suscripciones sin programar nada. Obtén más información sobre [cómo diseñar una integración](https://docs.stripe.com/billing/subscriptions/design-an-integration.md) para comprender las decisiones que debes tomar y los recursos que necesitas. ## Tu próximo desarrollo Esta guía te explica cómo: - Crea un catálogo de productos. - Crear un proceso de inscripción que genere un cliente. - Crear suscripciones y recopilar información de pago. - Comprobar y monitorear el estado de los pagos y las suscripciones. - Permitir que los clientes cambien de plan o cancelen la suscripción. - Aprende a utilizar el [modo de facturación flexible](https://docs.stripe.com/billing/subscriptions/billing-mode.md) para acceder a un comportamiento de facturación mejorado y a funcionalidades adicionales. ## Cómo construir en Stripe [Subscriptions](https://docs.stripe.com/api/subscriptions.md) simplifica tu facturación creando automáticamente *Facturas* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) y [PaymentIntents](https://docs.stripe.com/api/payment_intents.md) por ti. Para crear y activar una suscripción, necesitas crear primero un *Producto para definir lo que vendes, y un *Precio, que determina el importe por cobrar y la frecuencia. También necesitas un [Cliente](https://docs.stripe.com/api/customers.md) para almacenar los *PaymentMethods* utilizados para realizar cada pago recurrente.** #### Accounts v2 Diagrama que muestra objetos de facturación comunes y sus relaciones (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions) #### Customer v1 Diagrama que muestra objetos de facturación comunes y sus relaciones (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions) ### Definiciones de los objetos de la API | Recurso | Definición | | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Cuenta configurada como un cliente](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) | Representa a un cliente en la API Accounts v2 que compra una suscripción. Configura un objeto `Cuenta` como cliente y asócialo a una suscripción para realizar cargos recurrentes y hacerles un seguimiento, y para gestionar los productos a los que se suscribe. Consulta nuestra [guía Usar cuentas como clientes](https://docs.stripe.com/connect/use-accounts-as-customers.md) para obtener más información. | | [Customer](https://docs.stripe.com/api/customers.md) | Representa a un cliente en la API Clientes que compra una suscripción. Usa el objeto `Cliente` asociado a una suscripción para realizar y hacer seguimiento de los cargos recurrentes y administrar los productos a los que se suscriben. | | [Derecho](https://docs.stripe.com/api/entitlements/active-entitlement.md) | Representa el acceso de un cliente a una funcionalidad incluida en un producto de servicio al que está suscrito. Cuando creas una suscripción para la compra recurrente de un producto por parte de un cliente, se crea automáticamente un derecho activo para cada funcionalidad asociada a ese producto. Cuando un cliente accede a tus servicios, utiliza sus derechos activos para habilitar las funcionalidades incluidas en su suscripción. | | [Funcionalidad](https://docs.stripe.com/api/entitlements/feature.md) | Representa una funcionalidad o capacidad a la que tus clientes pueden acceder cuando se suscriben a un producto de servicio. Puedes incluir funciones en un producto creando ProductFeatures. | | [Factura](https://docs.stripe.com/api/invoices.md) | Una declaración de importes que un cliente adeuda y que rastrea los estados de pago desde el borrador hasta su pago o su finalización. Las suscripciones generan facturas automáticamente. | | [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) | Una forma de crear flujos de pago dinámicos. Un PaymentIntent hace un seguimiento del ciclo de vida del flujo del proceso compra del cliente y activa pasos adicionales de autenticación, si así lo exigen las disposiciones normativas, las reglas antifraude personalizadas de Radar o los métodos de pago con redireccionamiento. Las facturas crean PaymentIntents de forma automática. | | [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) | Los métodos de pago que usa un cliente para pagar tus productos. Por ejemplo, puedes guardar una tarjeta de crédito en un objeto `Cuenta` o `Cliente` configurado por el cliente y usarla para hacer pagos recurrentes para ese cliente. Por lo general, se usa con las API Payment Intents o Setup Intents. | | [Precio](https://docs.stripe.com/api/prices.md) | Define el precio por unidad, la moneda y el ciclo de facturación para un producto. | | [Producto](https://docs.stripe.com/api/products.md) | Un bien o servicio que vende tu empresa. Un producto de servicio puede incluir una o más funciones. | | [ProductFeature](https://docs.stripe.com/api/product-feature.md) | Representa la inclusión de una sola funcionalidades en un solo producto. Cada producto está asociado a una ProductFeature para cada funcionalidad que incluye, y cada funcionalidad está asociada a una ProductFeature para cada producto que la incluye. | | [Suscripción](https://docs.stripe.com/api/subscriptions.md) | Representa la compra recurrente programada de un producto por parte de un cliente. Usa una suscripción para cobrar pagos y proporcionar entrega repetida o acceso continuo a un producto. | Veamos un ejemplo de cómo funcionan juntos los productos, las funcionalidades y los derechos. Imagina que quieres configurar un servicio recurrente que ofrezca dos niveles: un producto estándar con funcionalidad básica y un producto avanzado que agregue funcionalidad extendida. 1. Creas dos funcionalidades: `basic_features` y `extended_features`. 1. Creas dos productos: `standard_product` y `advanced_product`. 1. Para el producto estándar, creas una ProductFeature que asocia `basic_features` con `standard_product`. 1. Para el producto avanzado, creas dos ProductFeatures: una que asocia `basic_features` con `advanced_product` y otra que asocia `extended_features` con `advanced_product`. Un cliente, `first_customer`, se suscribe al producto estándar. Cuando creas la suscripción, Stripe crea automáticamente un derecho que asocia `first_customer` con `basic_features`. Otro cliente, `second_customer`, se suscribe al producto avanzado. Al crear la suscripción, Stripe crea automáticamente dos derechos: uno que asocia `second_customer` con `basic_features` y otro que asocia `second_customer` con `extended_features`. Puedes determinar qué funcionalidades aprovisionar para un cliente [recuperando sus derechos activos o recibiendo notificaciones del evento Resumen de derechos activos](https://docs.stripe.com/billing/entitlements.md#entitlements). No tienes que recuperar sus suscripciones, productos y funcionalidades. ## Configura Stripe Instala el cliente de Stripe que prefieras: #### 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' ``` A continuación, instala la CLI de Stripe. La CLI proporciona pruebas de webhooks y puedes ejecutarla para realizar llamadas API a Stripe. Esta guía muestra cómo utilizar la CLI para configurar un modelo de precios en una sección posterior. Para obtener más opciones de instalación, consulta [Empezar a usar la CLI de Stripe](https://docs.stripe.com/stripe-cli.md). ## Crear el modelo de tarifas [CLI o Dashboard de Stripe] Los [modelos de precios recurrentes](https://docs.stripe.com/products-prices/pricing-models.md) representan los productos o servicios que vendes, cuánto cuestan, qué monedas aceptas para los pagos y el período de servicio para las suscripciones. Para crear el modelo de precios, crea [productos](https://docs.stripe.com/api/products.md) (lo que vendes) y [precios](https://docs.stripe.com/api/prices.md) (cuánto cuestan y con qué frecuencia cobrar por los productos). En este ejemplo, se utiliza una tarifa con tasa fija con dos opciones de niveles de servicio diferentes: básico y premium. Para cada opción de nivel de servicio, debes crear un producto y un precio recurrente. Si quieres agregar un cargo por única vez, como el costo de instalación, crea un tercer producto con un precio por única vez. Cada producto se factura de forma mensual. El precio del producto básico es de 5 USD. El precio del producto premium es de 15 USD. Consulta la guía de [tarifas con tasa fija](https://docs.stripe.com/subscriptions/pricing-models/flat-rate-pricing.md) para ver un ejemplo con tres niveles. #### Dashboard Ve a la página [Agregar un producto](https://dashboard.stripe.com/test/products/create) y crea dos productos. Agrega un precio a cada producto, cada uno con un período de facturación mensual recurrente: - Producto prémium: servicio prémium con más funcionalidades - Precio: Tarifa plana | 15 USD - Producto básico: servicio básico con las funcionalidades mínimas - Precio: Tarifa plana | 5 USD Después de crear los precios, registra los ID de precio para usarlos en otros pasos. Los ID de precio se ven así: `price_G0FvDp6vZvdwRZ`. Cuando esté todo listo, usa el botón **Copiar en modo activo**, en la parte superior derecha de la página, para clonar el producto y pasarlo de [entorno de prueba a modo activo](https://docs.stripe.com/keys.md#test-live-modes). #### API Puedes usar la API para crear los [productos](https://docs.stripe.com/api/products.md) y los [precios](https://docs.stripe.com/api/prices.md). Crear el producto premium: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Premium Service" \ -d "description=Premium service with extra features" ``` Crear el producto básico: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Basic Service" \ -d "description=Basic service with minimum features" ``` Registra el ID de cada producto. Se ve así: ```json { "id": "prod_H94k5odtwJXMtQ", "object": "product", "active": true, "attributes": [ ], "created": 1587577341, "description": "Premium service with extra features", "images": [ ], "livemode": false, "metadata": { }, "name": "Billing Guide: Premium Service", "statement_descriptor": null, "type": "service", "unit_label": null, "updated": 1587577341 } ``` Usa los ID de producto para crear el precio de cada producto. El número [unit_amount](https://docs.stripe.com/api/prices/object.md#price_object-unit_amount) está en centavos. Por ejemplo, `1500` = 15 USD. Crear el precio superior: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{PREMIUM_PRODUCT_ID}} \ -d unit_amount=1500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Crear el precio básico: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{BASIC_PRODUCT_ID}} \ -d unit_amount=500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Registra el ID de cada precio para poder utilizarlo en los pasos siguientes. Se ve así: ```json { "id": "price_HGd7M3DV3IMXkC", "object": "price", "product": "prod_HGd6W1VUqqXGvr", "type": "recurring", "currency": "usd", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "active": true, "billing_scheme": "per_unit", "created": 1589319695, "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "unit_amount": 1500, "unit_amount_decimal": "1500", "tiers": null, "tiers_mode": null, "transform_quantity": null } ``` ## Crear el cliente [Cliente y servidor] If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Stripe requiere un *Cliente* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) para cada suscripción. En el front-end de tu aplicación, recopila toda la información necesaria de tus usuarios y envíala al back-end. Si necesitas recopilar datos de la dirección, el Address Element te permite reunir una dirección de envío o facturación de tus clientes. Obtén más información sobre el Address Element en la página [Address Element](https://docs.stripe.com/elements/address-element.md). ```html
``` ```javascript const emailInput = document.querySelector('#email'); fetch('/create-customer', { method: 'post', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email: emailInput.value, }), }).then(r => r.json()); ``` Crea el objeto Customer de Stripe en el servidor. > Asegúrate de almacenar el [ID del cliente](https://docs.stripe.com/api/customers/object.md#customer_object-id) para usar en la Checkout Session ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -d email={{CUSTOMER_EMAIL}} \ -d name={{CUSTOMER_NAME}} \ -d "shipping[address][city]=Brothers" \ -d "shipping[address][country]=US" \ -d "shipping[address][line1]=27 Fredrick Ave" \ -d "shipping[address][postal_code]=97712" \ -d "shipping[address][state]=CA" \ -d "shipping[name]={{CUSTOMER_NAME}}" \ -d "address[city]=Brothers" \ -d "address[country]=US" \ -d "address[line1]=27 Fredrick Ave" \ -d "address[postal_code]=97712" \ -d "address[state]=CA" ``` ## Crear la suscripción [Cliente y servidor] > Si deseas renderizar el Payment Element sin crear primero una suscripción, consulta [Recopilación de datos de pago antes de crear una intención](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=subscription). Permite que tu cliente elija un plan y, a continuación, crea la suscripción. En el ejemplo de esta guía, el cliente elige entre un plan Básico o un plan Premium. En el front end, pasa el ID del precio seleccionado y el ID del registro del cliente al back end. ```javascript fetch('/create-subscription', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ priceId: priceId, customerId: customerId, }), }) ``` En el back end, cree la suscripción con un estado `incomplete` utilizando `payment_behavior=default_incomplete`. A continuación, devuelve el `client_secret` del primer [PaymentIntent](https://docs.stripe.com/payments/payment-intents.md) de la suscripción al front end para completar el pago. Para ello, expande el [confirmation_secret](https://docs.stripe.com/api/invoices/object.md#invoice_object-confirmation_secret) en la última factura de la suscripción. Para habilitar [el comportamiento de suscripción mejorado](https://docs.stripe.com/billing/subscriptions/billing-mode.md), establece `billing_mode[type]` en `flexible`. Debes utilizar la versión de la API de Stripe [2025-06-30.basil](https://docs.stripe.com/changelog/basil.md#2025-06-30.basil) o posterior. Establece [save_default_payment_method](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-payment_settings-save_default_payment_method) en `on_subscription` para guardar el método de pago como predeterminado para una suscripción cuando un pago tiene éxito. Guardar un método de pago como predeterminado aumenta la tasa de éxito de futuros pagos de suscripciones. En el siguiente ejemplo, se crea una `Subscription` y se expande el `confirmation_secret` de su última factura en la respuesta. Esto te permite pasar el secreto al front-end para confirmar el pago. #### Accounts v2 ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "items[0][price]={{PRICE_ID}}" \ -d payment_behavior=default_incomplete \ -d "payment_settings[save_default_payment_method]=on_subscription" \ -d "billing_mode[type]=flexible" \ -d "expand[0]=latest_invoice.confirmation_secret" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d "customer={{CUSTOMER_ID}}" \ -d "items[0][price]={{PRICE_ID}}" \ -d payment_behavior=default_incomplete \ -d "payment_settings[save_default_payment_method]=on_subscription" \ -d "billing_mode[type]=flexible" \ -d "expand[0]=latest_invoice.confirmation_secret" ``` > Si estás utilizando un *precio en múltiples monedas* (A single Price object can support multiple currencies. Each purchase uses one of the supported currencies for the Price, depending on how you use the Price in your integration), utiliza el parámetro [moneda](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-currency) para indicarle a la suscripción cuál de las monedas admitidas debe utilizar. Si omites el parámetro `currency`, la suscripción utilizará la moneda por defecto. La suscripción ahora está `inactive` y a la espera de pago. El ejemplo de respuesta que figura a continuación destaca los campos mínimos que deben almacenarse, pero puedes almacenar los campos a los que tu solicitud accede con frecuencia. #### Accounts v2 ```json {"id": "sub_JgRjFjhKbtD2qz", "object": "subscription", "application_fee_percent": null, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": "null" }, "billing_cycle_anchor": 1623873347, "billing_cycle_anchor_config": null, "cancel_at": null, "cancel_at_period_end": false, "canceled_at": null, "cancellation_details": { "comment": null, "feedback": null, "reason": null }, "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd","customer_account": identifier("customerAccount"), "days_until_due": null, "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "discounts": [], "ended_at": null, "invoice_customer_balance_settings": { "account_tax_ids": null, "issuer": { "type": "self" } }, "items": { "object": "list", "data": [ { "id": "si_JgRjmS4Ur1khEx", "object": "subscription_item", "created": 1623873347,"current_period_end": 1626465347, "current_period_start": 1623873347, "discounts": [], "metadata": { }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "subscription": "sub_JgRjFjhKbtD2qz", "tax_rates": [ ] } ], "has_more": false, "total_count": 1, "url": "/v1/subscription_items?subscription=sub_JgRjFjhKbtD2qz" }, "latest_invoice": { "id": "in_1J34pzGPZ1iASj5zB87qdBNZ", "object": "invoice", "account_country": "US", "account_name": "Angelina's Store", "account_tax_ids": null, "amount_due": 2000, "amount_overpaid": 0, "amount_paid": 0, "amount_remaining": 2000, "amount_shipping": 0, "attempt_count": 0, "attempted": false, "auto_advance": false, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": null, "status": null }, "automatically_finalizes_at": null, "billing_reason": "subscription_update", "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd", "custom_fields": null, "customer_account": identifier("customerAccount"), "customer_address": null, "customer_email": "angelina@stripe.com", "customer_name": null, "customer_phone": null, "customer_shipping": { "address": { "city": "", "country": "US", "line1": "Berry", "line2": "", "postal_code": "", "state": "" }, "name": "", "phone": null }, "customer_tax_exempt": "none", "customer_tax_ids": [ ], "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "description": null, "discounts": [], "due_date": null, "effective_at": "1623873347", "ending_balance": 0, "footer": null, "from_invoice": null, "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp", "invoice_pdf": "https://pay.stripe.com/invoice/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp/pdf", "last_finalization_error": null, "latest_revision": null, "lines": { "object": "list", "data": [ { "id": "il_1N2CjMBwKQ696a5NeOawRQP2", "object": "line_item", "amount": 2000, "currency": "usd", "description": "1 × Gold Special (at $20.00 / month)", "discount_amounts": [ ], "discountable": true, "discounts": [ ], "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "livemode": false, "metadata": { }, "parent": { "invoice_item_details": null, "subscription_item_details": { "invoice_item": null, "proration": false, "proration_details": { "credited_items": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subscription_item": "si_JgRjmS4Ur1khEx" }, "type": "subscription_item_details" }, "period": { "end": 1626465347, "start": 1623873347 }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "taxes": [] } ], "has_more": false, "total_count": 1, "url": "/v1/invoices/in_1J34pzGPZ1iASj5zB87qdBNZ/lines" }, "livemode": false, "metadata": { }, "next_payment_attempt": null, "number": "C008FC2-0354", "on_behalf_of": null, "parent": { "quote_details": null, "subscription_details": { "metadata": {}, "pause_collection": null, "subscription": "sub_JgRjFjhKbtD2qz" } }, "payment_intent": { "id": "pi_1J34pzGPZ1iASj5zI2nOAaE6", "object": "payment_intent", "allowed_source_types": [ "card" ], "amount": 2000, "amount_capturable": 0, "amount_received": 0, "application": null, "application_fee_amount": null, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic", "charges": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/charges?payment_intent=pi_1J34pzGPZ1iASj5zI2nOAaE6" }, "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu", "confirmation_method": "automatic", "created": 1623873347, "currency": "usd", "customer": "cus_CMqDWO2xODTZqt", "description": "Subscription creation", "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "last_payment_error": null, "livemode": false, "metadata": { }, "next_action": null, "next_source_action": null, "on_behalf_of": null, "payment_method": null, "payment_method_options": { "card": { "installments": null, "network": null, "request_three_d_secure": "automatic" } }, "payment_method_types": [ "card" ], "receipt_email": null, "review": null, "setup_future_usage": "off_session", "shipping": null, "source": "card_1By6iQGPZ1iASj5z7ijKBnXJ", "statement_descriptor": null, "statement_descriptor_suffix": null, "status": "requires_confirmation", "transfer_data": null, "transfer_group": null }, "payment_settings": { "payment_method_options": null, "payment_method_types": null, "save_default_payment_method": "on_subscription" }, "period_end": 1623873347, "period_start": 1623873347, "post_payment_credit_notes_amount": 0, "pre_payment_credit_notes_amount": 0, "receipt_number": null, "starting_balance": 0, "statement_descriptor": null, "status": "open", "status_transitions": { "finalized_at": 1623873347, "marked_uncollectible_at": null, "paid_at": null, "voided_at": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subtotal": 2000, "tax": null, "tax_percent": null, "total": 2000, "total_discount_amounts": [], "total_tax_amounts": [], "transfer_data": null, "webhooks_delivered_at": 1623873347 }, "livemode": false, "metadata": { }, "next_pending_invoice_item_invoice": null, "pause_collection": null, "pending_invoice_item_interval": null, "pending_setup_intent": null, "pending_update": null, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "quantity": 1, "schedule": null, "start": 1623873347, "start_date": 1623873347, "status": "incomplete", "tax_percent": null, "transfer_data": null, "trial_end": null, "trial_start": null } ``` #### Customers v1 ```json {"id": "sub_JgRjFjhKbtD2qz", "object": "subscription", "application_fee_percent": null, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": "null" }, "billing_cycle_anchor": 1623873347, "billing_cycle_anchor_config": null, "cancel_at": null, "cancel_at_period_end": false, "canceled_at": null, "cancellation_details": { "comment": null, "feedback": null, "reason": null }, "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd","customer": identifier("customer"), "days_until_due": null, "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "discounts": [], "ended_at": null, "invoice_customer_balance_settings": { "account_tax_ids": null, "issuer": { "type": "self" } }, "items": { "object": "list", "data": [ { "id": "si_JgRjmS4Ur1khEx", "object": "subscription_item", "created": 1623873347,"current_period_end": 1626465347, "current_period_start": 1623873347, "discounts": [], "metadata": { }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "subscription": "sub_JgRjFjhKbtD2qz", "tax_rates": [ ] } ], "has_more": false, "total_count": 1, "url": "/v1/subscription_items?subscription=sub_JgRjFjhKbtD2qz" }, "latest_invoice": { "id": "in_1J34pzGPZ1iASj5zB87qdBNZ", "object": "invoice", "account_country": "US", "account_name": "Angelina's Store", "account_tax_ids": null, "amount_due": 2000, "amount_overpaid": 0, "amount_paid": 0, "amount_remaining": 2000, "amount_shipping": 0, "attempt_count": 0, "attempted": false, "auto_advance": false, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": null, "status": null }, "automatically_finalizes_at": null, "billing_reason": "subscription_update", "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd", "custom_fields": null, "customer": identifier("customer"), "customer_address": null, "customer_email": "angelina@stripe.com", "customer_name": null, "customer_phone": null, "customer_shipping": { "address": { "city": "", "country": "US", "line1": "Berry", "line2": "", "postal_code": "", "state": "" }, "name": "", "phone": null }, "customer_tax_exempt": "none", "customer_tax_ids": [ ], "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "description": null, "discounts": [], "due_date": null, "effective_at": "1623873347", "ending_balance": 0, "footer": null, "from_invoice": null, "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp", "invoice_pdf": "https://pay.stripe.com/invoice/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp/pdf", "last_finalization_error": null, "latest_revision": null, "lines": { "object": "list", "data": [ { "id": "il_1N2CjMBwKQ696a5NeOawRQP2", "object": "line_item", "amount": 2000, "currency": "usd", "description": "1 × Gold Special (at $20.00 / month)", "discount_amounts": [ ], "discountable": true, "discounts": [ ], "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "livemode": false, "metadata": { }, "parent": { "invoice_item_details": null, "subscription_item_details": { "invoice_item": null, "proration": false, "proration_details": { "credited_items": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subscription_item": "si_JgRjmS4Ur1khEx" }, "type": "subscription_item_details" }, "period": { "end": 1626465347, "start": 1623873347 }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "taxes": [] } ], "has_more": false, "total_count": 1, "url": "/v1/invoices/in_1J34pzGPZ1iASj5zB87qdBNZ/lines" }, "livemode": false, "metadata": { }, "next_payment_attempt": null, "number": "C008FC2-0354", "on_behalf_of": null, "parent": { "quote_details": null, "subscription_details": { "metadata": {}, "pause_collection": null, "subscription": "sub_JgRjFjhKbtD2qz" } }, "payment_intent": { "id": "pi_1J34pzGPZ1iASj5zI2nOAaE6", "object": "payment_intent", "allowed_source_types": [ "card" ], "amount": 2000, "amount_capturable": 0, "amount_received": 0, "application": null, "application_fee_amount": null, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic", "charges": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/charges?payment_intent=pi_1J34pzGPZ1iASj5zI2nOAaE6" }, "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu", "confirmation_method": "automatic", "created": 1623873347, "currency": "usd", "customer": "cus_CMqDWO2xODTZqt", "description": "Subscription creation", "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "last_payment_error": null, "livemode": false, "metadata": { }, "next_action": null, "next_source_action": null, "on_behalf_of": null, "payment_method": null, "payment_method_options": { "card": { "installments": null, "network": null, "request_three_d_secure": "automatic" } }, "payment_method_types": [ "card" ], "receipt_email": null, "review": null, "setup_future_usage": "off_session", "shipping": null, "source": "card_1By6iQGPZ1iASj5z7ijKBnXJ", "statement_descriptor": null, "statement_descriptor_suffix": null, "status": "requires_confirmation", "transfer_data": null, "transfer_group": null }, "payment_settings": { "payment_method_options": null, "payment_method_types": null, "save_default_payment_method": "on_subscription" }, "period_end": 1623873347, "period_start": 1623873347, "post_payment_credit_notes_amount": 0, "pre_payment_credit_notes_amount": 0, "receipt_number": null, "starting_balance": 0, "statement_descriptor": null, "status": "open", "status_transitions": { "finalized_at": 1623873347, "marked_uncollectible_at": null, "paid_at": null, "voided_at": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subtotal": 2000, "tax": null, "tax_percent": null, "total": 2000, "total_discount_amounts": [], "total_tax_amounts": [], "transfer_data": null, "webhooks_delivered_at": 1623873347 }, "livemode": false, "metadata": { }, "next_pending_invoice_item_invoice": null, "pause_collection": null, "pending_invoice_item_interval": null, "pending_setup_intent": null, "pending_update": null, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "quantity": 1, "schedule": null, "start": 1623873347, "start_date": 1623873347, "status": "incomplete", "tax_percent": null, "transfer_data": null, "trial_end": null, "trial_start": null } ``` ## Recopila datos de pago [Cliente] Utiliza [Stripe Elements](https://docs.stripe.com/payments/elements.md) para cobrar los datos de pago y activar la suscripción. Puedes personalizar Elements para que se adapte al aspecto de tu solicitud. El [Payment Element](https://docs.stripe.com/payments/payment-element.md) admite [Link](https://docs.stripe.com/payments/link.md), tarjetas de crédito, débito directo SEPA y débito directo BECS para suscripciones. Puedes mostrar los métodos de pago habilitados y recopilar de forma segura los datos de pago según la selección de tu cliente. ### Configurar Stripe Elements El Payment Element se encuentra disponible automáticamente como funcionalidad de Stripe.js. Incluye el script de Stripe.js en tu página de confirmación de compra agregándolo al `head` de tu archivo HTML. Siempre debes cargar Stripe.js directamente desde js.stripe.com para cumplir con la normativa PCI. No incluyas el script en un paquete ni alojes una copia en tus sistemas. ```html Checkout ``` Crea una instancia de Stripe con el siguiente JavaScript en tu página de pago: ```javascript // Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe('<>'); ``` ### Agrega el Payment Element a tu página El Payment Element necesita un lugar donde residir en tu página de pago. Crea un nodo DOM vacío (contenedor) con una ID única en tu formulario de pago. ```html
``` Una vez cargado el formulario, cree una instancia de Payment Element y móntalo en el nodo DOM contenedor. Cuando [creaste la suscripción](https://docs.stripe.com/billing/subscriptions/build-subscriptions.md#create-subscription), pasaste el valor `client_secret` al front-end. Pasa este valor como una opción cuando crees una instancia de Elements. ```javascript const options = { clientSecret: '{{CLIENT_SECRET}}', // Fully customizable with appearance API. appearance: {/*...*/}, }; // Set up Stripe.js and Elements to use in the payment form, passing the client secret obtained in step 5 const elements = stripe.elements(options); const paymentElementOptions = { layout: "tabs", }; // Create and mount the Payment Element const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element'); ``` El elemento de pago muestra un formulario dinámico que le permite a tu cliente seleccionar un método de pago. El formulario recopila automáticamente todos los datos de pago necesarios para el método de pago que seleccionen. #### Configuraciones opcionales del Payment Element Opcionalmente, puedes hacer lo siguiente: - Personaliza el Payment Element para que se ajuste al diseño de tu sitio web pasando el [objeto de apariencia](https://docs.stripe.com/js/elements_object/create#stripe_elements-options-appearance) a `opciones` cuando estés por crear una instancia de Elements. - Configura la interfaz de Apple Pay para que devuelva un [token de comerciante](https://docs.stripe.com/apple-pay/merchant-tokens.md?pay-element=web-pe) para admitir pagos recurrentes, recargas automáticas y pagos aplazados. ### Completar pago Utiliza `stripe.confirmPayment` para completar el pago utilizando los datos del elemento de pago y activar la suscripción. Esto crea un método de pago, confirma la primera intención de pago de la suscripción incompleta y realiza el cargo. Si se requiere 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) (SCA) para el pago, el elemento de pago se encarga del proceso de autenticación antes de confirmar la intención de pago. Proporciona una dirección [return_url](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-return_url) para indicar a dónde redirige Stripe al usuario después de completar el pago. Tu usuario podría redirigirse primero a un sitio intermedio, como una página de autorización bancaria, antes de redirigirse a la `return_url`. Los pagos con tarjeta redirigen inmediatamente a la `return_url` cuando el pago se realiza correctamente. ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: "https://example.com/order/123/complete", } }); if (error) { // This point is reached only if there's an immediate error when // confirming the payment. Show an error to your customer (for example, payment // details incomplete) const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; } else { // Your customer redirects to your `return_url`. For some payment // methods, such as iDEAL, your customer redirects to an intermediate // site first to authorize the payment, and then redirects to the `return_url`. } }); ``` Cuando tu cliente envía un pago, Stripe lo redirige a `return_url` e incluye los siguientes parámetros de consulta de URL. La página de retorno puede usarlos para obtener el estado del PaymentIntent a fin de mostrarle el estado del pago al cliente. Cuando especificas la `return_url`, también puedes adjuntar tus propios parámetros de consulta para usarlos en la página de retorno. | Parámetro | Descripción | | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `payment_intent` | El identificador único del `PaymentIntent`. | | `payment_intent_client_secret` | El [secreto de cliente](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) del objeto `PaymentIntent`. Para las integraciones de suscripciones, este client_secret también se expone en el objeto `Invoice` a través de [`confirmation_secret`](https://docs.stripe.com/api/invoices/object.md#invoice_object-confirmation_secret) | Cuando el cliente es redirigido a tu sitio, puedes usar el `payment_intent_client_secret` para consultar el PaymentIntent y mostrarle el estado de la transacción a tu cliente. > Si tienes herramientas que hacen el seguimiento de la sesión de navegador del cliente, es posible que tengas que agregar el dominio `stripe.com` a la lista de exclusión de referentes. Los redireccionamientos hacen que algunas herramientas creen nuevas sesiones que te impiden hacer el seguimiento de toda la sesión. Utiliza uno de los parámetros de consulta para recuperar el PaymentIntent. Inspecciona el estado [del PaymentIntent](https://docs.stripe.com/payments/paymentintents/lifecycle.md) para decidir qué mostrar a tus clientes. También puedes añadir tus propios parámetros de consulta al proporcionar la `return_url`, que persisten a través del proceso de redirección. ```javascript // Initialize Stripe.js using your publishable key const stripe = Stripe('<>'); // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe.retrievePaymentIntent(clientSecret).then(({paymentIntent}) => { const message = document.querySelector('#message') // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods [immediately succeed or fail][0] upon // confirmation, while others first enter a `processing` status. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': message.innerText = 'Success! Payment received.'; break; case 'processing': message.innerText = "Payment processing. We'll update you when payment is received."; break; case 'requires_payment_method': message.innerText = 'Payment failed. Please try another payment method.'; // Redirect your user back to your payment page to attempt collecting // payment again break; default: message.innerText = 'Something went wrong.'; break; } }); ``` ## Escucha webhooks [Servidor] Para completar la integración, tienes que procesar los *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) que envió Stripe. Estos son eventos que se originan cada vez que un estado dentro de Stripe cambia, por ejemplo, cuando las suscripciones crean facturas nuevas. En tu aplicación, configura un controlador de HTTP para aceptar una solicitud POST que contenga el evento de webhook y verifica la firma del evento: #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/webhook' do # You can use webhooks to receive information about asynchronous payment events. # For more about our webhook events, see https://stripe.com/docs/webhooks. webhook_secret = ENV['STRIPE_WEBHOOK_SECRET'] payload = request.body.read if !webhook_secret.empty? # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured. sig_header = request.env['HTTP_STRIPE_SIGNATURE'] event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, webhook_secret ) rescue JSON::ParserError => e # Invalid payload status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature puts '⚠️ Webhook signature verification failed.' status 400 return end else data = JSON.parse(payload, symbolize_names: true) event = Stripe::Event.construct_from(data) end # Get the type of webhook event sent - used to check the status of PaymentIntents. event_type = event['type'] data = event['data'] data_object = data['object'] if event_type == 'invoice.paid' # Used to provision services after the trial has ended. # The status of the invoice shows up as paid. Store the status in your # database to reference when a user accesses your service to avoid hitting rate # limits. # puts data_object end if event_type == 'invoice.payment_failed' # If the payment fails or the customer doesn't have a valid payment method, # an invoice.payment_failed event is sent and the subscription becomes past_due. # Use this webhook to notify your user that their payment has # failed and to retrieve new card details. # puts data_object end if event_type == 'customer.subscription.deleted' # handle subscription canceled automatically based # upon your subscription settings. Or if the user cancels it. # puts data_object end content_type 'application/json' { status: 'success' }.to_json end ``` Durante el desarrollo, utiliza la CLI de Stripe para [observar los webhooks y reenviarlos a tu solicitud](https://docs.stripe.com/webhooks.md#test-webhook). Ejecuta lo siguiente en un terminal nuevo mientras se ejecuta tu aplicación de desarrollo: #### curl ```bash stripe listen --forward-to localhost:4242/webhook ``` Para la producción, configura un punto de conexión webhook en [Workbench](https://docs.stripe.com/workbench.md), o utiliza la API [Webhook Endpoints](https://docs.stripe.com/api/webhook_endpoints.md). Escucha algunos eventos para completar los pasos restantes de esta guía. Consulta [Eventos de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md#events) y obtén más detalles sobre los webhooks específicos de la suscripción. ## Brindar acceso a tu servicio [Cliente y servidor] Ahora que la suscripción está activa, dale a tu usuario acceso a tu servicio. Para ello, escucha los eventos `customer.subscription.created`, `customer.subscription.updated`, y `customer.subscription.deleted`. Estos eventos pasan un objeto `Subscription` que contiene un campo `estado` que indica si la suscripción está activa, vencida o cancelada. Consulta [el ciclo de vida de la suscripción](https://docs.stripe.com/billing/subscriptions/overview.md#subscription-lifecycle) para obtener una lista completa de estados. En tu controlador de webhook: 1. Verifica el estado de la suscripción. Si es `active`, tu usuario ha pagado por su producto. 1. Revisa el producto al que se suscribió el cliente y bríndale acceso al servicio. Es mejor revisar el producto que el precio porque te da más flexibilidad en caso de que tengas que cambiar el precio o el período de facturación. 1. Almacena el `product.id`, `subscription.id` y el `subscription.status` en tu base de datos junto con `customer.id` que ya guardaste. Consulta este registro cuando tengas que determinar qué funcionalidades habilitar para el usuario en tu aplicación. El estado de la suscripción puede cambiar en cualquier momento de su ciclo de vida, incluso si tu solicitud no hace ninguna llamada directa a Stripe. Por ejemplo, se puede producir un error de renovación debido a una tarjeta de crédito vencida, lo que genera que el estado de la suscripción pase a `vencido`. O, si usas el [portal de clientes](https://docs.stripe.com/customer-management.md), un usuario puede optar por cancelar la suscripción sin ingresar a tu aplicación directamente. El uso correcto del controlador mantiene el estado de tu solicitud sincronizado con Stripe. ## Cancelación de la suscripción [Cliente y servidor] Puedes permitir que los clientes cancelen sus suscripciones. El ejemplo siguiente añade una opción de cancelación a la página de configuración de la cuenta. ![Ejemplo de interfaz de cancelación de suscripción](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-subscriptions-guide-account-settings.6559626ba4b434826a67abfea165e097.png) Configuración de la cuenta con la posibilidad de cancelar la suscripción ```javascript function cancelSubscription(subscriptionId) { return fetch('/cancel-subscription', { method: 'post', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ subscriptionId: subscriptionId, }), }) .then(response => { return response.json(); }) .then(cancelSubscriptionResponse => { // Display to the user that the subscription has been canceled. }); } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/cancel-subscription' do content_type 'application/json' data = JSON.parse request.body.read deleted_subscription = Stripe::Subscription.cancel(data['subscriptionId']) deleted_subscription.to_json end ``` En tu aplicación, se recibe un evento `customer.subscription.deleted`. Una vez que se cancela la suscripción, actualiza tu base de datos para eliminar el ID de suscripción de Stripe que estaba almacenado y limitar el acceso al servicio. Cuando se cancela una suscripción, no se puede reactivar. En su lugar, recopila la información de facturación actualizada de tu cliente, actualiza su método de pago predeterminado y crea una nueva suscripción con tu registro de cliente existente. ## Prueba la integración ### Prueba métodos de pago Usa la siguiente tabla para probar diferentes métodos y escenarios de pago. | Método de pago | Escenario | Cómo hacer la prueba | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Débito directo BECS | Tu cliente paga correctamente con débito directo BECS. | Completa el formulario con el número de cuenta `900123456` y BSB `000000`. El PaymentIntent confirmado pasa en un principio al estado `processing` y, tres minutos más tarde, a `succeeded`. | | Débito directo BECS | El pago de tu cliente falla con un código de error `account_closed`. | Completa el formulario con el número de cuenta `111111113` y BSB `000000`. | | Tarjeta de crédito | El pago con tarjeta se efectúa correctamente y no requiere autenticación. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4242 4242 4242 4242` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | El pago con tarjeta requiere *autenticación* (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). | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0025 0000 3155` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | La tarjeta es rechazada con el código `insufficient_funds`. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0000 0000 9995` y cualquier fecha de vencimiento, CVC y código postal. | | Débito directo SEPA | Tu cliente paga correctamente con débito directo SEPA. | Completa el formulario con el número de cuenta `AT321904300235473204`. El PaymentIntent confirmado pasa inicialmente al estado “en proceso” y, tres minutos más tarde, a “completado”. | | Débito directo SEPA | El estado de PaymentIntent de tu cliente pasa de `processing` a `requires_payment_method`. | Completa el formulario con el número de cuenta `AT861904300235473202`. | ### Supervisa los acontecimientos Configura webhooks para escuchar los eventos de cambio de suscripción, como actualizaciones y cancelaciones. Más información sobre [webhooks de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md). Puedes ver los eventos en el [Dashboard](https://dashboard.stripe.com/test/events) o con [Stripe CLI](https://docs.stripe.com/webhooks.md#test-webhook). Para más detalles, consulta [Comprobación de la integración con Billing](https://docs.stripe.com/billing/testing.md). ## Optional: Permitir que los clientes cambien de plan [Cliente y servidor] Para permitir que tus clientes cambien su suscripción, recopila el ID de precio de la opción a la que desean cambiar. A continuación, envía el nuevo ID de precio desde el front-end a un punto final del back-end. El ejemplo siguiente también pasa el ID de suscripción, pero puedes recuperarlo de tu base de datos para el usuario que ha iniciado sesión. ```javascript function updateSubscription(priceId, subscriptionId) { return fetch('/update-subscription', { method: 'post', headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ subscriptionId: subscriptionId, newPriceId: priceId, }), }) .then(response => { return response.json(); }) .then(response => { return response; }); } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada especificando el ID de suscripción y el nuevo ID de precio. La suscripción ahora es una suscripción Premium que cuesta USD 15 por mes en lugar de una suscripción básica de USD 5 por mes. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/update-subscription' do content_type 'application/json' data = JSON.parse request.body.read subscription = Stripe::Subscription.retrieve(data['subscriptionId']) updated_subscription = Stripe::Subscription.update( data['subscriptionId'], cancel_at_period_end: false, items: [ { id: subscription.items.data[0].id, price: data['newPriceId'] } ] ) updated_subscription.to_json end ``` En tu aplicación, se recibe un evento `customer.subscription.updated`. ## Optional: Previsualizar un cambio de precio [Cliente y servidor] Cuando tu cliente cambia de suscripción, a menudo se produce un ajuste del importe que debe, conocido como [prorrateo](https://docs.stripe.com/billing/subscriptions/prorations.md). Puedes utilizar el [punto de conexión de creación de factura preliminar](https://docs.stripe.com/api/invoices/create_preview.md) para mostrar el importe ajustado a tus clientes. En el front-end, pasa los detalles de `create preview invoice` a un punto de conexión de back-end. ```javascript function createPreviewInvoice( customerId, subscriptionId, newPriceId, trialEndDate ) { return fetch('/create-preview-invoice', { method: 'post', headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ customerId: customerId, subscriptionId: subscriptionId, newPriceId: newPriceId, }), }) .then(response => { return response.json(); }) .then((invoice) => { return invoice; }); } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/create-preview-invoice' do content_type 'application/json' data = JSON.parse request.body.read subscription = Stripe::Subscription.retrieve(data['subscriptionId']) invoice = Stripe::Invoice.create_preview( customer: data['customerId'], subscription: data['subscriptionId'], subscription_details: { items: [ { id: subscription.items.data[0].id, deleted: true }, { price: data['newPriceId'], deleted: false } ] } ) invoice.to_json end ``` ## Optional: Mostrar el método de pago del cliente [Cliente y servidor] Mostrar la marca y los últimos 4 dígitos de la tarjeta le permite saber al cliente qué tarjeta se está utilizando o si es necesario actualizar el método de pago. En el front end, envía el identificador del método de pago a un punto de conexión que recupere los detalles del método de pago. ```javascript function retrieveCustomerPaymentMethod(paymentMethodId) { return fetch('/retrieve-customer-payment-method', { method: 'post', headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ paymentMethodId: paymentMethodId, }), }) .then((response) => { return response.json(); }) .then((response) => { return response; }); } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/retrieve-customer-payment-method' do content_type 'application/json' data = JSON.parse request.body.read payment_method = Stripe::PaymentMethod.retrieve(data['paymentMethodId']) payment_method.to_json end ``` Ejemplo de respuesta: ```json { "id": "pm_1GcbHY2eZvKYlo2CoqlVxo42", "object": "payment_method", "billing_details": { "address": { "city": null, "country": null, "line1": null, "line2": null, "postal_code": null, "state": null }, "email": null, "name": null, "phone": null }, "card": { "brand": "visa", "checks": { "address_line1_check": null, "address_postal_code_check": null, "cvc_check": "pass" }, "country": "US", "exp_month": 8, "exp_year": 2021, "fingerprint": "Xt5EWLLDS7FJjR1c", "funding": "credit", "generated_from": null, "last4": "4242", "three_d_secure_usage": { "supported": true }, "wallet": null }, "created": 1588010536, "customer": "cus_HAxB7dVQxhoKLh", "livemode": false, "metadata": {}, "type": "card" } ``` > Te recomendamos guardar `paymentMethod.id` y `last4` en tu base de datos, por ejemplo, `paymentMethod.id` como `stripeCustomerPaymentMethodId` en tu colección o tabla de `users`. Si lo necesitas, también tienes la opción de guardar `exp_month`, `exp_year`, `fingerprint` y `billing_details`. Esto sirve para limitar el número de llamadas a Stripe, mejorar el rendimiento y evitar una posible limitación de la frecuencia. ## Cuéntales a tus clientes qué es Stripe Stripe recopila información sobre las interacciones de los clientes con Elements para proporcionarte servicios, mejorarlos y prevenir el fraude. Esto incluye el uso de cookies y direcciones IP para identificar qué Elements vio un cliente durante una sola sesión de finalización de compra. Tienes la responsabilidad de divulgar y obtener todos los derechos y consentimientos necesarios para que Stripe use los datos para dichos fines. Si deseas obtener más información, visita nuestro [centro de privacidad](https://stripe.com/legal/privacy-center#as-a-business-user-what-notice-do-i-provide-to-my-end-customers-about-stripe). #### Móvil #### iOS Aprende a vender *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) de precio fijo. Usarás [Payment Element para dispositivos móviles](https://docs.stripe.com/payments/accept-a-payment.md) para crear un formulario de pago personalizado que puedes integrar en tu aplicación. ![Página de suscripción de precio fijo con Payment Element móvil](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-collect-payment-details-mobile.b11cdc8fa8952d753238df4df3375fa6.png) > Si vendes productos o servicios digitales que se consumen dentro de tu aplicación (por ejemplo, suscripciones, monedas de juegos, niveles de juegos, acceso a contenido prémium o desbloqueo de una versión completa), debes usar las API de compra desde la aplicación de Apple. Esta regla tiene algunas excepciones, como los servicios personales uno a uno y las [aplicaciones basadas en regiones específicas](https://support.stripe.com/questions/changes-to-mobile-app-store-rules). Consulta las [pautas de revisión de la App Store](https://developer.apple.com/app-store/review/guidelines/#payments) para obtener más información. ## Crear tu suscripción Esta guía te explica cómo: - Modelar tu empresa creando un catálogo de productos. - Crear un proceso de registro para agregar clientes. - Crear suscripciones y recopilar información de pago. - Comprueba y supervisa el estado de los pagos y las suscripciones. - Permitir que los clientes cambien de plan o cancelen la suscripción. - Aprenda a usar el [modo facturación flexible](https://docs.stripe.com/billing/subscriptions/billing-mode.md) para acceder a un comportamiento de facturación mejorado y funcionalidades adicionales. ## Cómo modelar la suscripción en Stripe [Subscriptions](https://docs.stripe.com/api/subscriptions.md) simplifica tu facturación y crea automáticamente *Facturas* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) y [PaymentIntents](https://docs.stripe.com/api/payment_intents.md) por ti. Para crear y activar una suscripción, necesitas crear primero un *Producto para modelar lo que se vende, y un *Precio, que determina el intervalo y el importe por cobrar. También necesitas un [Cliente](https://docs.stripe.com/api/customers.md) para almacenar los *PaymentMethods* utilizados para realizar cada pago recurrente.** #### Accounts v2 Diagrama que muestra objetos de facturación comunes y sus relaciones (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions) #### Customer v1 Diagrama que muestra objetos de facturación comunes y sus relaciones (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions) ### Definiciones de los objetos de la API | Recurso | Definición | | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Cuenta configurada como un cliente](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) | Representa a un cliente en la API Accounts v2 que compra una suscripción. Configura un objeto `Cuenta` como cliente y asócialo a una suscripción para realizar cargos recurrentes y hacerles un seguimiento, y para gestionar los productos a los que se suscribe. Consulta nuestra [guía Usar cuentas como clientes](https://docs.stripe.com/connect/use-accounts-as-customers.md) para obtener más información. | | [Customer](https://docs.stripe.com/api/customers.md) | Representa a un cliente en la API Clientes que compra una suscripción. Usa el objeto `Cliente` asociado a una suscripción para realizar y hacer seguimiento de los cargos recurrentes y administrar los productos a los que se suscriben. | | [Derecho](https://docs.stripe.com/api/entitlements/active-entitlement.md) | Representa el acceso de un cliente a una funcionalidad incluida en un producto de servicio al que está suscrito. Cuando creas una suscripción para la compra recurrente de un producto por parte de un cliente, se crea automáticamente un derecho activo para cada funcionalidad asociada a ese producto. Cuando un cliente accede a tus servicios, utiliza sus derechos activos para habilitar las funcionalidades incluidas en su suscripción. | | [Funcionalidad](https://docs.stripe.com/api/entitlements/feature.md) | Representa una funcionalidad o capacidad a la que tus clientes pueden acceder cuando se suscriben a un producto de servicio. Puedes incluir funciones en un producto creando ProductFeatures. | | [Factura](https://docs.stripe.com/api/invoices.md) | Una declaración de importes que un cliente adeuda y que rastrea los estados de pago desde el borrador hasta su pago o su finalización. Las suscripciones generan facturas automáticamente. | | [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) | Una forma de crear flujos de pago dinámicos. Un PaymentIntent hace un seguimiento del ciclo de vida del flujo del proceso compra del cliente y activa pasos adicionales de autenticación, si así lo exigen las disposiciones normativas, las reglas antifraude personalizadas de Radar o los métodos de pago con redireccionamiento. Las facturas crean PaymentIntents de forma automática. | | [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) | Los métodos de pago que usa un cliente para pagar tus productos. Por ejemplo, puedes guardar una tarjeta de crédito en un objeto `Cuenta` o `Cliente` configurado por el cliente y usarla para hacer pagos recurrentes para ese cliente. Por lo general, se usa con las API Payment Intents o Setup Intents. | | [Precio](https://docs.stripe.com/api/prices.md) | Define el precio por unidad, la moneda y el ciclo de facturación para un producto. | | [Producto](https://docs.stripe.com/api/products.md) | Un bien o servicio que vende tu empresa. Un producto de servicio puede incluir una o más funciones. | | [ProductFeature](https://docs.stripe.com/api/product-feature.md) | Representa la inclusión de una sola funcionalidades en un solo producto. Cada producto está asociado a una ProductFeature para cada funcionalidad que incluye, y cada funcionalidad está asociada a una ProductFeature para cada producto que la incluye. | | [Suscripción](https://docs.stripe.com/api/subscriptions.md) | Representa la compra recurrente programada de un producto por parte de un cliente. Usa una suscripción para cobrar pagos y proporcionar entrega repetida o acceso continuo a un producto. | Veamos un ejemplo de cómo funcionan juntos los productos, las funcionalidades y los derechos. Imagina que quieres configurar un servicio recurrente que ofrezca dos niveles: un producto estándar con funcionalidad básica y un producto avanzado que agregue funcionalidad extendida. 1. Creas dos funcionalidades: `basic_features` y `extended_features`. 1. Creas dos productos: `standard_product` y `advanced_product`. 1. Para el producto estándar, creas una ProductFeature que asocia `basic_features` con `standard_product`. 1. Para el producto avanzado, creas dos ProductFeatures: una que asocia `basic_features` con `advanced_product` y otra que asocia `extended_features` con `advanced_product`. Un cliente, `first_customer`, se suscribe al producto estándar. Cuando creas la suscripción, Stripe crea automáticamente un derecho que asocia `first_customer` con `basic_features`. Otro cliente, `second_customer`, se suscribe al producto avanzado. Al crear la suscripción, Stripe crea automáticamente dos derechos: uno que asocia `second_customer` con `basic_features` y otro que asocia `second_customer` con `extended_features`. Puedes determinar qué funcionalidades aprovisionar para un cliente [recuperando sus derechos activos o recibiendo notificaciones del evento Resumen de derechos activos](https://docs.stripe.com/billing/entitlements.md#entitlements). No tienes que recuperar sus suscripciones, productos y funcionalidades. ## Configura Stripe 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 **StripePaymentSheet** 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 'StripePaymentSheet' ``` 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 StripePaymentSheet ``` #### 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/StripePaymentSheet/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 **StripePaymentSheet.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/StripePaymentSheet/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 UIKitimportStripePaymentSheet @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. A continuación, instala la CLI de Stripe. La CLI proporciona pruebas de webhook y puedes ejecutarla para realizar llamadas API a Stripe. Esta guía muestra cómo utilizar la CLI para configurar un modelo de precios en una sección posterior. Para obtener más opciones de instalación, consulta [Empezar a usar la CLI de Stripe](https://docs.stripe.com/stripe-cli.md). ## Crear el modelo de tarifas [CLI o Dashboard de Stripe] Los [modelos de precios recurrentes](https://docs.stripe.com/products-prices/pricing-models.md) representan los productos o servicios que vendes, cuánto cuestan, qué monedas aceptas para los pagos y el período de servicio para las suscripciones. Para crear el modelo de precios, crea [productos](https://docs.stripe.com/api/products.md) (lo que vendes) y [precios](https://docs.stripe.com/api/prices.md) (cuánto cuestan y con qué frecuencia cobrar por los productos). En este ejemplo, se utiliza una tarifa con tasa fija con dos opciones de niveles de servicio diferentes: básico y premium. Para cada opción de nivel de servicio, debes crear un producto y un precio recurrente. Si quieres agregar un cargo por única vez, como el costo de instalación, crea un tercer producto con un precio por única vez. Cada producto se factura de forma mensual. El precio del producto básico es de 5 USD. El precio del producto premium es de 15 USD. Consulta la guía de [tarifas con tasa fija](https://docs.stripe.com/subscriptions/pricing-models/flat-rate-pricing.md) para ver un ejemplo con tres niveles. #### Dashboard Ve a la página [Agregar un producto](https://dashboard.stripe.com/test/products/create) y crea dos productos. Agrega un precio a cada producto, cada uno con un período de facturación mensual recurrente: - Producto prémium: servicio prémium con más funcionalidades - Precio: Tarifa plana | 15 USD - Producto básico: servicio básico con las funcionalidades mínimas - Precio: Tarifa plana | 5 USD Después de crear los precios, registra los ID de precio para usarlos en otros pasos. Los ID de precio se ven así: `price_G0FvDp6vZvdwRZ`. Cuando esté todo listo, usa el botón **Copiar en modo activo**, en la parte superior derecha de la página, para clonar el producto y pasarlo de [entorno de prueba a modo activo](https://docs.stripe.com/keys.md#test-live-modes). #### API Puedes usar la API para crear los [productos](https://docs.stripe.com/api/products.md) y los [precios](https://docs.stripe.com/api/prices.md). Crear el producto premium: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Premium Service" \ -d "description=Premium service with extra features" ``` Crear el producto básico: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Basic Service" \ -d "description=Basic service with minimum features" ``` Registra el ID de cada producto. Se ve así: ```json { "id": "prod_H94k5odtwJXMtQ", "object": "product", "active": true, "attributes": [ ], "created": 1587577341, "description": "Premium service with extra features", "images": [ ], "livemode": false, "metadata": { }, "name": "Billing Guide: Premium Service", "statement_descriptor": null, "type": "service", "unit_label": null, "updated": 1587577341 } ``` Usa los ID de producto para crear el precio de cada producto. El número [unit_amount](https://docs.stripe.com/api/prices/object.md#price_object-unit_amount) está en centavos. Por ejemplo, `1500` = 15 USD. Crear el precio superior: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{PREMIUM_PRODUCT_ID}} \ -d unit_amount=1500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Crear el precio básico: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{BASIC_PRODUCT_ID}} \ -d unit_amount=500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Registra el ID de cada precio para poder utilizarlo en los pasos siguientes. Se ve así: ```json { "id": "price_HGd7M3DV3IMXkC", "object": "price", "product": "prod_HGd6W1VUqqXGvr", "type": "recurring", "currency": "usd", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "active": true, "billing_scheme": "per_unit", "created": 1589319695, "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "unit_amount": 1500, "unit_amount_decimal": "1500", "tiers": null, "tiers_mode": null, "transform_quantity": null } ``` ## Crear el cliente [Cliente y servidor] Stripe requiere un *cliente* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) para cada suscripción. En el front-end de tu aplicación, recopila toda la información necesaria de tus usuarios y envíala al back-end. > #### Use the Accounts v2 API to represent customers > > If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Si necesitas recopilar datos de la dirección, el Address Element te permite recopilar una dirección de envío o facturación para tus clientes. Para obtener más información sobre el Address Element, visita la página de [Address Element](https://docs.stripe.com/elements/address-element.md). ```swift struct RegisterView: View { @State var email = "" var body: some View { VStack { TextField(text: $email) { Text("Email") } Button { Task { var request = URLRequest(url: URL(string: "http://localhost:4242/create-customer")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try! JSONEncoder().encode(["email": email]) let (data, _) = try! await URLSession.shared.data(for: request) let responseJSON = try! JSONSerialization.jsonObject(with: data) as! [String: Any] // Return the customer ID here print(responseJSON["customer"]) } } label: { Text("Submit") } } } } ``` Crea el “Customer Object” de Stripe en el servidor. ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -d email={{CUSTOMER_EMAIL}} \ -d name={{CUSTOMER_NAME}} \ -d "shipping[address][city]=Brothers" \ -d "shipping[address][country]=US" \ -d "shipping[address][line1]=27 Fredrick Ave" \ -d "shipping[address][postal_code]=97712" \ -d "shipping[address][state]=CA" \ -d "shipping[name]={{CUSTOMER_NAME}}" \ -d "address[city]=Brothers" \ -d "address[country]=US" \ -d "address[line1]=27 Fredrick Ave" \ -d "address[postal_code]=97712" \ -d "address[state]=CA" ``` ## Crear la suscripción [Cliente y servidor] > Si quieres procesar el Payment Element antes de crear una suscripción, consulta [Recopilar los datos de pago antes de crear un Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=subscription). Permite que tu nuevo cliente elija un plan y luego cree la suscripción. En esta guía, elegirá entre un plan Básico y un plan Prémium. En tu aplicación, envía el ID de precio seleccionado y el ID del registro del cliente al back-end. ```swift func createSubscription(priceId: String, customerId: String) async -> SubscriptionsResponse { var request = URLRequest(url: URL(string: "http://localhost:4242/create-subscription")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try! JSONEncoder().encode(["customerId": customerId, "priceId": priceId]) let (responseData, _) = try! await URLSession.shared.data(for: request) // SubscriptionsResponse is a Decodable struct conforming to the expected response from your backend. // It should include the client_secret, as discussed below. let subscriptionsResponse = try! JSONDecoder().decode(SubscriptionsResponse.self, from: responseData) return subscriptionsResponse } ``` En el back-end, crea una suscripción con estado `incomplete` usando `payment_behavior=default_incomplete`. Luego, devuelve el `client_secret` desde el primer [payment intent](https://docs.stripe.com/payments/payment-intents.md) de la suscripción al front-end para completar el pago expandiendo el [`confirmation_secret`](https://docs.stripe.com/api/invoices/object.md#invoice_object-confirmation_secret) en la factura más reciente de la suscripción. Para habilitar el [comportamiento de suscripción mejorado](https://docs.stripe.com/billing/subscriptions/billing-mode.md), establece `billing_mode[type]` en `flexible`. Debes utilizar la versión de la API de Stripe [2025-06-30.basil](https://docs.stripe.com/changelog/basil.md#2025-06-30.basil) o posterior. Establece [save_default_payment_method](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-payment_settings-save_default_payment_method) en `on_subscription` para guardar el método de pago como predeterminado para una suscripción cuando un pago se realiza correctamente. Guardar un método de pago predeterminado aumenta la tasa de éxito de futuros pagos de suscripción. En el siguiente ejemplo, se crea una `Subscription` y se expande el `confirmation_secret` de su última factura en la respuesta. Esto te permite pasar el secreto al front-end para confirmar el pago. #### Accounts v2 ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "items[0][price]={{PRICE_ID}}" \ -d payment_behavior=default_incomplete \ -d "payment_settings[save_default_payment_method]=on_subscription" \ -d "billing_mode[type]=flexible" \ -d "expand[0]=latest_invoice.confirmation_secret" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d "customer={{CUSTOMER_ID}}" \ -d "items[0][price]={{PRICE_ID}}" \ -d payment_behavior=default_incomplete \ -d "payment_settings[save_default_payment_method]=on_subscription" \ -d "billing_mode[type]=flexible" \ -d "expand[0]=latest_invoice.confirmation_secret" ``` > Si usas un *precio en múltiples monedas* (A single Price object can support multiple currencies. Each purchase uses one of the supported currencies for the Price, depending on how you use the Price in your integration), usa el parámetro [currency](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-currency) para indicarle a la suscripción cuál de las monedas del precio debe usar. (Si omites el parámetro `currency`, la suscripción utilizará la moneda predeterminada del precio). La suscripción ahora está `inactiva` y a la espera de pago. El ejemplo de respuesta que figura a continuación destaca los campos mínimos que deben almacenarse, pero puedes almacenar los campos a los que tu solicitud accede con frecuencia. #### Accounts v2 ```json {"id": "sub_JgRjFjhKbtD2qz", "object": "subscription", "application_fee_percent": null, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": "null" }, "billing_cycle_anchor": 1623873347, "billing_cycle_anchor_config": null, "cancel_at": null, "cancel_at_period_end": false, "canceled_at": null, "cancellation_details": { "comment": null, "feedback": null, "reason": null }, "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd","customer_account": identifier("customerAccount"), "days_until_due": null, "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "discounts": [], "ended_at": null, "invoice_customer_balance_settings": { "account_tax_ids": null, "issuer": { "type": "self" } }, "items": { "object": "list", "data": [ { "id": "si_JgRjmS4Ur1khEx", "object": "subscription_item", "created": 1623873347,"current_period_end": 1626465347, "current_period_start": 1623873347, "discounts": [], "metadata": { }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "subscription": "sub_JgRjFjhKbtD2qz", "tax_rates": [ ] } ], "has_more": false, "total_count": 1, "url": "/v1/subscription_items?subscription=sub_JgRjFjhKbtD2qz" }, "latest_invoice": { "id": "in_1J34pzGPZ1iASj5zB87qdBNZ", "object": "invoice", "account_country": "US", "account_name": "Angelina's Store", "account_tax_ids": null, "amount_due": 2000, "amount_overpaid": 0, "amount_paid": 0, "amount_remaining": 2000, "amount_shipping": 0, "attempt_count": 0, "attempted": false, "auto_advance": false, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": null, "status": null }, "automatically_finalizes_at": null, "billing_reason": "subscription_update", "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd", "custom_fields": null, "customer_account": identifier("customerAccount"), "customer_address": null, "customer_email": "angelina@stripe.com", "customer_name": null, "customer_phone": null, "customer_shipping": { "address": { "city": "", "country": "US", "line1": "Berry", "line2": "", "postal_code": "", "state": "" }, "name": "", "phone": null }, "customer_tax_exempt": "none", "customer_tax_ids": [ ], "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "description": null, "discounts": [], "due_date": null, "effective_at": "1623873347", "ending_balance": 0, "footer": null, "from_invoice": null, "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp", "invoice_pdf": "https://pay.stripe.com/invoice/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp/pdf", "last_finalization_error": null, "latest_revision": null, "lines": { "object": "list", "data": [ { "id": "il_1N2CjMBwKQ696a5NeOawRQP2", "object": "line_item", "amount": 2000, "currency": "usd", "description": "1 × Gold Special (at $20.00 / month)", "discount_amounts": [ ], "discountable": true, "discounts": [ ], "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "livemode": false, "metadata": { }, "parent": { "invoice_item_details": null, "subscription_item_details": { "invoice_item": null, "proration": false, "proration_details": { "credited_items": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subscription_item": "si_JgRjmS4Ur1khEx" }, "type": "subscription_item_details" }, "period": { "end": 1626465347, "start": 1623873347 }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "taxes": [] } ], "has_more": false, "total_count": 1, "url": "/v1/invoices/in_1J34pzGPZ1iASj5zB87qdBNZ/lines" }, "livemode": false, "metadata": { }, "next_payment_attempt": null, "number": "C008FC2-0354", "on_behalf_of": null, "parent": { "quote_details": null, "subscription_details": { "metadata": {}, "pause_collection": null, "subscription": "sub_JgRjFjhKbtD2qz" } }, "payment_intent": { "id": "pi_1J34pzGPZ1iASj5zI2nOAaE6", "object": "payment_intent", "allowed_source_types": [ "card" ], "amount": 2000, "amount_capturable": 0, "amount_received": 0, "application": null, "application_fee_amount": null, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic", "charges": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/charges?payment_intent=pi_1J34pzGPZ1iASj5zI2nOAaE6" }, "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu", "confirmation_method": "automatic", "created": 1623873347, "currency": "usd", "customer": "cus_CMqDWO2xODTZqt", "description": "Subscription creation", "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "last_payment_error": null, "livemode": false, "metadata": { }, "next_action": null, "next_source_action": null, "on_behalf_of": null, "payment_method": null, "payment_method_options": { "card": { "installments": null, "network": null, "request_three_d_secure": "automatic" } }, "payment_method_types": [ "card" ], "receipt_email": null, "review": null, "setup_future_usage": "off_session", "shipping": null, "source": "card_1By6iQGPZ1iASj5z7ijKBnXJ", "statement_descriptor": null, "statement_descriptor_suffix": null, "status": "requires_confirmation", "transfer_data": null, "transfer_group": null }, "payment_settings": { "payment_method_options": null, "payment_method_types": null, "save_default_payment_method": "on_subscription" }, "period_end": 1623873347, "period_start": 1623873347, "post_payment_credit_notes_amount": 0, "pre_payment_credit_notes_amount": 0, "receipt_number": null, "starting_balance": 0, "statement_descriptor": null, "status": "open", "status_transitions": { "finalized_at": 1623873347, "marked_uncollectible_at": null, "paid_at": null, "voided_at": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subtotal": 2000, "tax": null, "tax_percent": null, "total": 2000, "total_discount_amounts": [], "total_tax_amounts": [], "transfer_data": null, "webhooks_delivered_at": 1623873347 }, "livemode": false, "metadata": { }, "next_pending_invoice_item_invoice": null, "pause_collection": null, "pending_invoice_item_interval": null, "pending_setup_intent": null, "pending_update": null, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "quantity": 1, "schedule": null, "start": 1623873347, "start_date": 1623873347, "status": "incomplete", "tax_percent": null, "transfer_data": null, "trial_end": null, "trial_start": null } ``` #### Customers v1 ```json {"id": "sub_JgRjFjhKbtD2qz", "object": "subscription", "application_fee_percent": null, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": "null" }, "billing_cycle_anchor": 1623873347, "billing_cycle_anchor_config": null, "cancel_at": null, "cancel_at_period_end": false, "canceled_at": null, "cancellation_details": { "comment": null, "feedback": null, "reason": null }, "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd","customer": identifier("customer"), "days_until_due": null, "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "discounts": [], "ended_at": null, "invoice_customer_balance_settings": { "account_tax_ids": null, "issuer": { "type": "self" } }, "items": { "object": "list", "data": [ { "id": "si_JgRjmS4Ur1khEx", "object": "subscription_item", "created": 1623873347,"current_period_end": 1626465347, "current_period_start": 1623873347, "discounts": [], "metadata": { }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "subscription": "sub_JgRjFjhKbtD2qz", "tax_rates": [ ] } ], "has_more": false, "total_count": 1, "url": "/v1/subscription_items?subscription=sub_JgRjFjhKbtD2qz" }, "latest_invoice": { "id": "in_1J34pzGPZ1iASj5zB87qdBNZ", "object": "invoice", "account_country": "US", "account_name": "Angelina's Store", "account_tax_ids": null, "amount_due": 2000, "amount_overpaid": 0, "amount_paid": 0, "amount_remaining": 2000, "amount_shipping": 0, "attempt_count": 0, "attempted": false, "auto_advance": false, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": null, "status": null }, "automatically_finalizes_at": null, "billing_reason": "subscription_update", "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd", "custom_fields": null, "customer": identifier("customer"), "customer_address": null, "customer_email": "angelina@stripe.com", "customer_name": null, "customer_phone": null, "customer_shipping": { "address": { "city": "", "country": "US", "line1": "Berry", "line2": "", "postal_code": "", "state": "" }, "name": "", "phone": null }, "customer_tax_exempt": "none", "customer_tax_ids": [ ], "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "description": null, "discounts": [], "due_date": null, "effective_at": "1623873347", "ending_balance": 0, "footer": null, "from_invoice": null, "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp", "invoice_pdf": "https://pay.stripe.com/invoice/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp/pdf", "last_finalization_error": null, "latest_revision": null, "lines": { "object": "list", "data": [ { "id": "il_1N2CjMBwKQ696a5NeOawRQP2", "object": "line_item", "amount": 2000, "currency": "usd", "description": "1 × Gold Special (at $20.00 / month)", "discount_amounts": [ ], "discountable": true, "discounts": [ ], "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "livemode": false, "metadata": { }, "parent": { "invoice_item_details": null, "subscription_item_details": { "invoice_item": null, "proration": false, "proration_details": { "credited_items": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subscription_item": "si_JgRjmS4Ur1khEx" }, "type": "subscription_item_details" }, "period": { "end": 1626465347, "start": 1623873347 }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "taxes": [] } ], "has_more": false, "total_count": 1, "url": "/v1/invoices/in_1J34pzGPZ1iASj5zB87qdBNZ/lines" }, "livemode": false, "metadata": { }, "next_payment_attempt": null, "number": "C008FC2-0354", "on_behalf_of": null, "parent": { "quote_details": null, "subscription_details": { "metadata": {}, "pause_collection": null, "subscription": "sub_JgRjFjhKbtD2qz" } }, "payment_intent": { "id": "pi_1J34pzGPZ1iASj5zI2nOAaE6", "object": "payment_intent", "allowed_source_types": [ "card" ], "amount": 2000, "amount_capturable": 0, "amount_received": 0, "application": null, "application_fee_amount": null, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic", "charges": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/charges?payment_intent=pi_1J34pzGPZ1iASj5zI2nOAaE6" }, "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu", "confirmation_method": "automatic", "created": 1623873347, "currency": "usd", "customer": "cus_CMqDWO2xODTZqt", "description": "Subscription creation", "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "last_payment_error": null, "livemode": false, "metadata": { }, "next_action": null, "next_source_action": null, "on_behalf_of": null, "payment_method": null, "payment_method_options": { "card": { "installments": null, "network": null, "request_three_d_secure": "automatic" } }, "payment_method_types": [ "card" ], "receipt_email": null, "review": null, "setup_future_usage": "off_session", "shipping": null, "source": "card_1By6iQGPZ1iASj5z7ijKBnXJ", "statement_descriptor": null, "statement_descriptor_suffix": null, "status": "requires_confirmation", "transfer_data": null, "transfer_group": null }, "payment_settings": { "payment_method_options": null, "payment_method_types": null, "save_default_payment_method": "on_subscription" }, "period_end": 1623873347, "period_start": 1623873347, "post_payment_credit_notes_amount": 0, "pre_payment_credit_notes_amount": 0, "receipt_number": null, "starting_balance": 0, "statement_descriptor": null, "status": "open", "status_transitions": { "finalized_at": 1623873347, "marked_uncollectible_at": null, "paid_at": null, "voided_at": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subtotal": 2000, "tax": null, "tax_percent": null, "total": 2000, "total_discount_amounts": [], "total_tax_amounts": [], "transfer_data": null, "webhooks_delivered_at": 1623873347 }, "livemode": false, "metadata": { }, "next_pending_invoice_item_invoice": null, "pause_collection": null, "pending_invoice_item_interval": null, "pending_setup_intent": null, "pending_update": null, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "quantity": 1, "schedule": null, "start": 1623873347, "start_date": 1623873347, "status": "incomplete", "tax_percent": null, "transfer_data": null, "trial_end": null, "trial_start": null } ``` ### Actualiza el punto de conexión del servidor Agrega la creación de claves efímeras al punto de conexión de la suscripción y devuélvela en la respuesta: #### Ruby ```ruby ephemeral_key = Stripe::EphemeralKey.create( {customer: customer_id}, {stripe_version: '2025-06-30.basil'} ) { subscriptionId: subscription.id, clientSecret: subscription.latest_invoice.confirmation_secret.client_secret, ephemeralKey: ephemeral_key.secret, customerId: customer_id, }.to_json ``` ### Actualiza tu modelo de respuesta ```swift struct SubscriptionsResponse: Decodable { let subscriptionId: String let clientSecret: String let ephemeralKey: String let customerId: String } ``` ### Pasar la configuración del cliente a PaymentSheet Agrega lo siguiente al configurar PaymentSheet: ```swift config.customer = .init(id: customerId, ephemeralKeySecret: ephemeralKey) ``` ## Recopilar datos de pago [Cliente] Utiliza [Payment Sheet](https://docs.stripe.com/payments/mobile/payment-sheet.md) para recolectar detalles del pago y activar la suscripción. Puedes personalizar Elements para que coincida con la apariencia de tu solicitud. Payment Sheet recopila de forma segura todos los detalles de pago necesarios para una amplia variedad de métodos de pago. Más información sobre los [métodos de pago admitidos](https://docs.stripe.com/payments/payment-methods/payment-method-support.md#product-support) para Payment Sheet y Subscriptions. ### Agregar el Payment Element a tu aplicación > Este paso muestra una forma de empezar, pero puedes usar cualquier [integración de pagos dentro de la aplicación](https://docs.stripe.com/payments/mobile.md). Inicializa y presenta el Payment Element móvil usando la clase PaymentSheet. ```swift struct SubscribeView: View { let paymentSheet: PaymentSheet @State var isPaymentSheetPresented = false init(clientSecret: String) { var config = PaymentSheet.Configuration() // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. config.allowsDelayedPaymentMethods = true config.primaryButtonLabel = "Subscribe for $15/month" self.paymentSheet = PaymentSheet(paymentIntentClientSecret: clientSecret, configuration: config) } var body: some View { Button { isPaymentSheetPresented = true } label: { Text("Subscribe") }.paymentSheet(isPresented: $isPaymentSheetPresented, paymentSheet: paymentSheet) { result in switch result { case .completed: // Handle completion case .canceled: break case .failed(let error): // Handle error } } } } ``` El Payment Element móvil renderiza una hoja que le permite a tu cliente seleccionar un método de pago. El formulario recopila automáticamente todos los datos de pago necesarios para el método de pago que elijan. Establecer `allowsDelayedPaymentMethods` en true permite aceptar métodos de pago de [notificación diferida](https://docs.stripe.com/payments/payment-methods.md#payment-notification) como cuentas bancarias en EE. UU. Para estos métodos de pago, el estado final del pago no se conoce cuando se completa el `PaymentSheet`, sino que se efectúa con éxito o falla más tarde. Si aceptas este tipo de métodos de pago, infórmale al cliente que su pedido está confirmado y solo finalízalo (por ejemplo, envía el producto) cuando el pago se realice correctamente. Puedes personalizar el Payment Element para que coincida con el diseño de tu aplicación usando la [propiedad `appearance`](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=ios) de tu objeto `PaymentSheet.Configuration`. ### Confirmar pago El Payment Element móvil crea un PaymentMethod y confirma que el primer PaymentIntent de la suscripción está incompleto, lo que genera un cargo. Si se requiere *autenticación reforzada de clientes* (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) (SCA) para el pago, el Payment Element se encarga del proceso de autenticación antes de confirmar el PaymentIntent. ## Configurar una URL de retorno [Lado del cliente] El cliente puede salir de tu aplicación para autenticarse (por ejemplo, en Safari o en su aplicación bancaria). Para permitirles que regresen automáticamente a tu aplicación después de autenticarse, [configura un esquema de URL personalizado](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) y define el delegado de la aplicación para que envíe la URL al SDK. Stripe no admite [enlaces universales](https://developer.apple.com/documentation/xcode/allowing-apps-and-websites-to-link-to-your-content). #### SceneDelegate #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { guard let url = URLContexts.first?.url else { return } let stripeHandled = StripeAPI.handleURLCallback(with: url) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } } ``` #### AppDelegate #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { let stripeHandled = StripeAPI.handleURLCallback(with: url) if (stripeHandled) { return true } else { // This was not a Stripe url – handle the URL normally as you would } return false } ``` #### SwiftUI #### Swift ```swift @main struct MyApp: App { var body: some Scene { WindowGroup { Text("Hello, world!").onOpenURL { incomingURL in let stripeHandled = StripeAPI.handleURLCallback(with: incomingURL) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } } } } } ``` Además, debes definir la [returnURL](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:6Stripe12PaymentSheetC13ConfigurationV9returnURLSSSgvp) del objeto [PaymentSheet.Configuration](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html) en la URL de tu aplicación. ```swift var configuration = PaymentSheet.Configuration() configuration.returnURL = "your-app://stripe-redirect" ``` ## Optional: Habilitar Apple Pay ### Inscribirse para obtener un ID de comerciante Apple Obtén un ID de comerciante Apple [solicitando un nuevo identificador](https://developer.apple.com/account/resources/identifiers/add/merchant) en el sitio web de desarrolladores de Apple. Completa el formulario con una descripción y el identificador. La descripción es para tus registros y se puede modificar en el futuro. Stripe recomienda usar el nombre de tu aplicación como identificador (por ejemplo, `merchant.com.{{YOUR_APP_NAME}}`). ### Crear un nuevo certificado de Apple Pay Crea un certificado para que tu aplicación cifre los datos de pago. Ve a [Configuración de certificados de iOS](https://dashboard.stripe.com/settings/ios_certificates) en el Dashboard, haz clic en **Agregar nueva aplicación** y sigue la guía. Descarga un archivo de solicitud de firma de certificado (CSR) para obtener un certificado seguro de Apple que te permita utilizar Apple Pay. Se debe usar un archivo CSR para emitir exactamente un certificado. Si cambias tu ID de comerciante de Apple, debes ir a la [Configuración de certificados de iOS](https://dashboard.stripe.com/settings/ios_certificates) en el Dashboard para obtener una nueva CSR y un nuevo certificado. ### Integrarse con Xcode Agrega la funcionalidad Apple Pay a tu aplicación. En Xcode, abre la configuración del proyecto, selecciona la pestaña **Firma y funcionalidades** y agrega la funcionalidad **Apple Pay**. En este paso, quizá se te solicite iniciar sesión en tu cuenta de desarrollador. Selecciona el ID de comerciante que creaste antes, y tu aplicación estará lista para aceptar Apple Pay. ![](https://b.stripecdn.com/docs-statics-srv/assets/xcode.a701d4c1922d19985e9c614a6f105bf1.png) Habilitar la funcionalidad Apple Pay en Xcode ### Agregar Apple Pay #### Pagos recurrentes Para agregar Apple Pay a PaymentSheet, establece [applePay](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:6Stripe12PaymentSheetC13ConfigurationV8applePayAC05ApplefD0VSgvp) después de inicializar `PaymentSheet.Configuration` con tu ID de comerciante Apple y el [código de país de tu empresa](https://dashboard.stripe.com/settings/account). Conforme a las [directrices de Apple](https://developer.apple.com/design/human-interface-guidelines/apple-pay#Supporting-subscriptions) para pagos recurrentes, también debes establecer otros atributos en `PKPaymentRequest`. Agrega un controlador en [ApplePayConfiguration.paymentRequestHandlers](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/applepayconfiguration/handlers/paymentrequesthandler) para configurar [PKPaymentRequest.paymentSummaryItems](https://developer.apple.com/documentation/passkit/pkpaymentrequest/1619231-paymentsummaryitems) con la cantidad que pretendes cobrar (por ejemplo, USD 9.95 al mes). También puedes adoptar [tokens de comerciante](https://developer.apple.com/apple-pay/merchant-tokens/) estableciendo las propiedades `recurringPaymentRequest` o `automaticReloadPaymentRequest` en la `PKPaymentRequest`. Para obtener más información sobre cómo usar los pagos recurrentes con Apple Pay, consulta la [Documentación de Apple sobre PassKit](https://developer.apple.com/documentation/passkit/pkpaymentrequest). #### iOS (Swift) ```swift let customHandlers = PaymentSheet.ApplePayConfiguration.Handlers( paymentRequestHandler: { request in // PKRecurringPaymentSummaryItem is available on iOS 15 or later if #available(iOS 15.0, *) { let billing = PKRecurringPaymentSummaryItem(label: "My Subscription", amount: NSDecimalNumber(string: "59.99")) // Payment starts today billing.startDate = Date() // Payment ends in one year billing.endDate = Date().addingTimeInterval(60 * 60 * 24 * 365) // Pay once a month. billing.intervalUnit = .month billing.intervalCount = 1 // recurringPaymentRequest is only available on iOS 16 or later if #available(iOS 16.0, *) { request.recurringPaymentRequest = PKRecurringPaymentRequest(paymentDescription: "Recurring", regularBilling: billing, managementURL: URL(string: "https://my-backend.example.com/customer-portal")!) request.recurringPaymentRequest?.billingAgreement = "You'll be billed $59.99 every month for the next 12 months. To cancel at any time, go to Account and click 'Cancel Membership.'" } request.paymentSummaryItems = [billing] request.currencyCode = "USD" } else { // On older iOS versions, set alternative summary items. request.paymentSummaryItems = [PKPaymentSummaryItem(label: "Monthly plan starting July 1, 2022", amount: NSDecimalNumber(string: "59.99"), type: .final)] } return request } ) var configuration = PaymentSheet.Configuration() configuration.applePay = .init(merchantId: "merchant.com.your_app_name", merchantCountryCode: "US", customHandlers: customHandlers) ``` ### Seguimiento de pedidos Para agregar información de [seguimiento de pedidos](https://developer.apple.com/design/human-interface-guidelines/technologies/wallet/designing-order-tracking) en iOS 16 o posterior, configura un [authorizationResultHandler](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/applepayconfiguration/handlers/authorizationresulthandler) en tu `PaymentSheet.ApplePayConfiguration.Handlers`. Stripe llamará a tu implementación después de que se efectivice el pago, pero antes de que iOS descarte la hoja de Apple Pay. En tu implementación de `authorizationResultHandler`, obtén los datos del pedido de tu servidor para el pedido completado. Agrega los datos al [PKPaymentAuthorizationResult](https://developer.apple.com/documentation/passkit/pkpaymentauthorizationresult) proporcionado y devuelve el resultado modificado. Para obtener más información sobre el seguimiento de pedidos, consulta la [Documentación sobre los pedidos por billetera de Apple](https://developer.apple.com/documentation/walletorders). #### iOS (Swift) ```swift let customHandlers = PaymentSheet.ApplePayConfiguration.Handlers( authorizationResultHandler: { result in do { // Fetch the order details from your service let myOrderDetails = try await MyAPIClient.shared.fetchOrderDetails(orderID: orderID) result.orderDetails = PKPaymentOrderDetails( orderTypeIdentifier: myOrderDetails.orderTypeIdentifier, // "com.myapp.order" orderIdentifier: myOrderDetails.orderIdentifier, // "ABC123-AAAA-1111" webServiceURL: myOrderDetails.webServiceURL, // "https://my-backend.example.com/apple-order-tracking-backend" authenticationToken: myOrderDetails.authenticationToken) // "abc123" // Return your modified PKPaymentAuthorizationResult return result } catch { return PKPaymentAuthorizationResult(status: .failure, errors: [error]) } } ) var configuration = PaymentSheet.Configuration() configuration.applePay = .init(merchantId: "merchant.com.your_app_name", merchantCountryCode: "US", customHandlers: customHandlers) ``` ## Escuchar webhooks [Servidor] Para completar la integración, tienes que procesar los *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) que envió Stripe. Estos son eventos que se originan cada vez que un estado dentro de Stripe cambia, por ejemplo, cuando las suscripciones crean facturas nuevas. En tu aplicación, configura un controlador de HTTP para aceptar una solicitud POST que contenga el evento de webhook y verifica la firma del evento: #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/webhook' do # You can use webhooks to receive information about asynchronous payment events. # For more about our webhook events check out https://stripe.com/docs/webhooks. webhook_secret = ENV['STRIPE_WEBHOOK_SECRET'] payload = request.body.read if !webhook_secret.empty? # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured. sig_header = request.env['HTTP_STRIPE_SIGNATURE'] event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, webhook_secret ) rescue JSON::ParserError => e # Invalid payload status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature puts '⚠️ Webhook signature verification failed.' status 400 return end else data = JSON.parse(payload, symbolize_names: true) event = Stripe::Event.construct_from(data) end # Get the type of webhook event sent - used to check the status of PaymentIntents. event_type = event['type'] data = event['data'] data_object = data['object'] if event_type == 'invoice.paid' # Used to provision services after the trial has ended. # The status of the invoice will show up as paid. Store the status in your # database to reference when a user accesses your service to avoid hitting rate # limits. # puts data_object end if event_type == 'invoice.payment_failed' # If the payment fails or the customer does not have a valid payment method, # an invoice.payment_failed event is sent, the subscription becomes past_due. # Use this webhook to notify your user that their payment has # failed and to retrieve new card details. # puts data_object end if event_type == 'customer.subscription.deleted' # handle subscription canceled automatically based # upon your subscription settings. Or if the user cancels it. # puts data_object end content_type 'application/json' { status: 'success' }.to_json end ``` Durante el desarrollo, usa la CLI de Stripe para [observar los webhooks y reenviarlos a tu aplicación](https://docs.stripe.com/webhooks.md#test-webhook). Ejecuta lo siguiente en una nueva terminal mientras tu aplicación de desarrollo está funcionando: #### curl ```bash stripe listen --forward-to localhost:4242/webhook ``` Para la producción, configura una URL de punto de conexión de webhook en el Dashboard o utiliza la [API Webhook Endpoints](https://docs.stripe.com/api/webhook_endpoints.md). Necesita escuchar algunos eventos para completar los pasos restantes de esta guía. Consulte [Eventos de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md#events) para más detalles sobre los webhooks específicos de suscripción. ## Brindar acceso a tu servicio [Cliente y servidor] Ahora que la suscripción está activa, dale a tu usuario acceso a tu servicio. Para ello, escucha los eventos `customer.subscription.created`, `customer.subscription.updated`, y `customer.subscription.deleted`. Estos eventos pasan un objeto Subscription que contiene un campo `status` que indica si la suscripción está activa, vencida o cancelada. Consulta [el ciclo de vida de la suscripción](https://docs.stripe.com/billing/subscriptions/overview.md#subscription-lifecycle) para obtener una lista completa de estados. En tu controlador de webhook: 1. Verifica el estado de la suscripción. Si es `activo`, entonces tu usuario ha pagado por su producto. 1. Revisa el producto al que se suscribió el cliente y bríndale acceso al servicio. Es mejor revisar el producto que el precio porque te da más flexibilidad en caso de que necesites cambiar la tarifa o el intervalo de facturación. 1. Almacena el `product.id`, `subscription.id` y el `subscription.status` en tu base de datos junto con `customer.id` que ya guardaste. Consulta este registro cuando tengas que determinar qué funcionalidades habilitar para el usuario en tu aplicación. El estado de la suscripción puede cambiar en cualquier momento de su ciclo de vida, incluso si tu solicitud no hace ninguna llamada directa a Stripe. Por ejemplo, se puede producir un error de renovación debido a una tarjeta de crédito vencida, lo que genera que el estado de la suscripción pase a vencido. O, si usas el [portal de clientes](https://docs.stripe.com/customer-management.md), un usuario puede optar por cancelar la suscripción sin ingresar a tu aplicación directamente. El uso correcto del controlador mantiene el estado de tu solicitud sincronizado con Stripe. ## Cancelar la suscripción [Cliente y servidor] Con frecuencia, se les permite a los clientes cancelar su suscripción. En este ejemplo, se agrega la opción de cancelación en la página de configuración de la cuenta. En este ejemplo, el ID de la suscripción se recopila en el front-end, pero tu aplicación puede obtener esta información de tu base de datos para el usuario que ha iniciado sesión. ![Modelo de interfaz de cancelación de suscripciones.](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-subscriptions-guide-account-settings.6559626ba4b434826a67abfea165e097.png) Configuración de la cuenta con la posibilidad de cancelar la suscripción ```swift func cancelSubscription() async { var request = URLRequest(url: URL(string: "http://localhost:4242/cancel-subscription")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try! JSONEncoder().encode(["subscriptionId": subscription.id]) let (subscriptionResponse, _) = try! await URLSession.shared.data(for: request) // Update the state to show the subscription has been cancelled } ``` En el back-end, define el punto de conexión para que la aplicación haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/cancel-subscription' do content_type 'application/json' data = JSON.parse request.body.read deleted_subscription = Stripe::Subscription.cancel(data['subscriptionId']) deleted_subscription.to_json end ``` Tu back-end recibe un evento `customer.subscription.deleted`. Una vez que se cancela la suscripción, actualiza tu base de datos para eliminar el ID de suscripción de Stripe que estaba almacenado y limitar el acceso al servicio. Cuando una suscripción se cancela, no se puede reactivar. En su lugar, recopila información de facturación actualizada de tu cliente, actualiza su método de pago predeterminado y crea una nueva suscripción con su registro de cliente existente. ## Prueba tu integración ### Prueba métodos de pago Usa la siguiente tabla para probar diferentes métodos y escenarios de pago. | Método de pago | Escenario | Cómo hacer la prueba | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Débito directo BECS | Tu cliente paga correctamente con débito directo BECS. | Completa el formulario con el número de cuenta `900123456` y BSB `000000`. El PaymentIntent confirmado pasa en un principio al estado `processing` y, tres minutos más tarde, a `succeeded`. | | Débito directo BECS | El pago de tu cliente falla con un código de error `account_closed`. | Completa el formulario con el número de cuenta `111111113` y BSB `000000`. | | Tarjeta de crédito | El pago con tarjeta se efectúa correctamente y no requiere autenticación. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4242 4242 4242 4242` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | El pago con tarjeta requiere *autenticación* (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). | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0025 0000 3155` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | La tarjeta es rechazada con el código `insufficient_funds`. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0000 0000 9995` y cualquier fecha de vencimiento, CVC y código postal. | | Débito directo SEPA | Tu cliente paga correctamente con débito directo SEPA. | Completa el formulario con el número de cuenta `AT321904300235473204`. El PaymentIntent confirmado pasa inicialmente al estado “en proceso” y, tres minutos más tarde, a “completado”. | | Débito directo SEPA | El estado de PaymentIntent de tu cliente pasa de `processing` a `requires_payment_method`. | Completa el formulario con el número de cuenta `AT861904300235473202`. | ### Supervisa eventos Configura webhooks para recibir notificaciones de los eventos de cambios en las suscripciones, como actualizaciones y cancelaciones. Obtén más información sobre los [webhooks de suscripciones](https://docs.stripe.com/billing/subscriptions/webhooks.md). Puedes ver los eventos en el [Dashboard](https://dashboard.stripe.com/test/events) o con la [CLI de Stripe](https://docs.stripe.com/webhooks.md#test-webhook). Para obtener más detalles, consulta [cómo probar tu integración con Billing](https://docs.stripe.com/billing/testing.md). ## Optional: Permitir que los clientes cambien de plan [Cliente y servidor] Para permitirles a los clientes cambiar de suscripción, recopila el ID de precio de la opción a la que quieren pasar. A continuación, envía el nuevo ID de precio desde la aplicación a un punto de conexión del back-end. En este ejemplo, también se especifica el ID de suscripción, pero puedes recuperarlo de tu base de datos para el usuario que ha iniciado sesión. ```swift func updateSubscription(priceId: String, subscriptionId: String) async -> SubscriptionsResponse { var request = URLRequest(url: URL(string: "http://localhost:4242/update-subscription")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try! JSONEncoder().encode(["subscriptionId": subscriptionId, "priceId": priceId]) let (responseData, _) = try! await URLSession.shared.data(for: request) // SubscriptionsResponse is a Decodable struct conforming to the expected response from your backend let subscriptionsResponse = try! JSONDecoder().decode(SubscriptionsResponse.self, from: responseData) return subscriptionsResponse } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada especificando el ID de suscripción y el nuevo ID de precio. La suscripción ahora es Premium, a USD 15 por mes, en lugar de Básica a USD 5 por mes. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/update-subscription' do content_type 'application/json' data = JSON.parse request.body.read subscription = Stripe::Subscription.retrieve(data['subscriptionId']) updated_subscription = Stripe::Subscription.update( data['subscriptionId'], cancel_at_period_end: false, items: [ { id: subscription.items.data[0].id, price: data['newPriceId'] } ] ) updated_subscription.to_json end ``` En tu aplicación, se recibe un evento `customer.subscription.updated`. ## Optional: Previsualizar un cambio de precio [Cliente y servidor] Cuando tu cliente cambia de suscripción, a menudo es necesario hacer un ajuste en el importe adeudado que se conoce como [prorrateo](https://docs.stripe.com/billing/subscriptions/prorations.md). Puedes usar el [punto de conexión de creación de la vista previa de facturas](https://docs.stripe.com/api/invoices/create_preview.md) para mostrarles a tus clientes el importe ajustado. Desde la aplicación, pasa los datos de la vista previa de la factura a un punto de conexión del back-end. ```swift func createPreviewInvoice(customerId: String, subscriptionId: String, newPriceId: String) async -> InvoiceResponse { var request = URLRequest(url: URL(string: "http://localhost:4242/create-preview-invoice")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try! JSONEncoder().encode(["subscriptionId": subscriptionId, "customerId": customerId, "newPriceId": newPriceId]) let (responseData, _) = try! await URLSession.shared.data(for: request) // Invoice is a Decodable struct conforming to the expected response from your backend let invoiceResponse = try! JSONDecoder().decode(InvoiceResponse.self, from: responseData) return invoiceResponse } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/create-preview-invoice' do content_type 'application/json' data = JSON.parse request.body.read subscription = Stripe::Subscription.retrieve(data['subscriptionId']) invoice = Stripe::Invoice.create_preview( customer: data['customerId'], subscription: data['subscriptionId'], subscription_details: { items: [ { id: subscription.items.data[0].id, deleted: true }, { price: data['newPriceId'], deleted: false } ] } ) invoice.to_json end ``` ## Optional: Mostrar el método de pago del cliente [Cliente y servidor] Mostrar la marca y los últimos 4 dígitos de la tarjeta le permite al cliente saber qué tarjeta se está utilizando o si es necesario actualizar el método de pago. Desde el front-end, pasa el ID del método de pago a un punto de conexión del back-end que recupere los datos del método de pago. ```swift func retrieveCustomerPaymentMethod(paymentMethodId: String) async -> PaymentMethodResponse { var request = URLRequest(url: URL(string: "http://localhost:4242/retrieve-customer-payment-method")!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try! JSONEncoder().encode(["paymentMethodId": paymentMethodId]) let (responseData, _) = try! await URLSession.shared.data(for: request) // PaymentMethodResponse is a Decodable struct conforming to the expected response from your backend let paymentMethodResponse = try! JSONDecoder().decode(PaymentMethodResponse.self, from: responseData) return paymentMethodResponse } ``` En el back-end, define el punto de conexión para que la aplicación haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/retrieve-customer-payment-method' do content_type 'application/json' data = JSON.parse request.body.read payment_method = Stripe::PaymentMethod.retrieve(data['paymentMethodId']) payment_method.to_json end ``` Ejemplo de respuesta: ```json { "id": "pm_1GcbHY2eZvKYlo2CoqlVxo42", "object": "payment_method", "billing_details": { "address": { "city": null, "country": null, "line1": null, "line2": null, "postal_code": null, "state": null }, "email": null, "name": null, "phone": null }, "card": { "brand": "visa", "checks": { "address_line1_check": null, "address_postal_code_check": null, "cvc_check": "pass" }, "country": "US", "exp_month": 8, "exp_year": 2021, "fingerprint": "Xt5EWLLDS7FJjR1c", "funding": "credit", "generated_from": null, "last4": "4242", "three_d_secure_usage": { "supported": true }, "wallet": null }, "created": 1588010536, "customer": "cus_HAxB7dVQxhoKLh", "livemode": false, "metadata": {}, "type": "card" } ``` > Te recomendamos guardar `paymentMethod.id` y `last4` en tu base de datos, por ejemplo, `paymentMethod.id` como `stripeCustomerPaymentMethodId` en tu colección o tabla de `users`. Si lo necesitas, también tienes la opción de guardar `exp_month`, `exp_year`, `fingerprint` y `billing_details`. Esto sirve para limitar el número de llamadas a Stripe, tanto para mejorar el rendimiento como para evitar una posible limitación de la frecuencia. ## Cuéntales a tus clientes qué es Stripe Stripe recopila información sobre las interacciones de los clientes con Elements para proporcionarte servicios, mejorarlos y prevenir el fraude. Esto incluye el uso de cookies y direcciones IP para identificar qué Elements vio un cliente durante una sola sesión de finalización de compra. Tienes la responsabilidad de divulgar y obtener todos los derechos y consentimientos necesarios para que Stripe use los datos para dichos fines. Si deseas obtener más información, visita nuestro [centro de privacidad](https://stripe.com/legal/privacy-center#as-a-business-user-what-notice-do-i-provide-to-my-end-customers-about-stripe). #### Android Aprende a vender *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) de precio fijo. Usarás [Payment Element para dispositivos móviles](https://docs.stripe.com/payments/accept-a-payment.md) para crear un formulario de pago personalizado que puedes integrar en tu aplicación. ![Página de suscripción de precio fijo con Payment Element móvil](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-collect-payment-details-mobile.b11cdc8fa8952d753238df4df3375fa6.png) > Si vendes productos o servicios digitales que se consumen dentro de tu aplicación (por ejemplo, suscripciones, monedas de juegos, niveles de juegos, acceso a contenido prémium o desbloqueo de una versión completa), debes usar las API de compra desde la aplicación de Apple. Esta regla tiene algunas excepciones, como los servicios personales uno a uno y las [aplicaciones basadas en regiones específicas](https://support.stripe.com/questions/changes-to-mobile-app-store-rules). Consulta las [pautas de revisión de la App Store](https://developer.apple.com/app-store/review/guidelines/#payments) para obtener más información. ## Crear tu suscripción Esta guía te explica cómo: - Modelar tu empresa creando un catálogo de productos. - Crear un proceso de registro para agregar clientes. - Crear suscripciones y recopilar información de pago. - Comprueba y supervisa el estado de los pagos y las suscripciones. - Permitir que los clientes cambien de plan o cancelen la suscripción. - Aprenda a usar el [modo facturación flexible](https://docs.stripe.com/billing/subscriptions/billing-mode.md) para acceder a un comportamiento de facturación mejorado y funcionalidades adicionales. ## Cómo modelar la suscripción en Stripe [Subscriptions](https://docs.stripe.com/api/subscriptions.md) simplifica tu facturación y crea automáticamente *Facturas* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) y [PaymentIntents](https://docs.stripe.com/api/payment_intents.md) por ti. Para crear y activar una suscripción, necesitas crear primero un *Producto para modelar lo que se vende, y un *Precio, que determina el intervalo y el importe por cobrar. También necesitas un [Cliente](https://docs.stripe.com/api/customers.md) para almacenar los *PaymentMethods* utilizados para realizar cada pago recurrente.** #### Accounts v2 Diagrama que muestra objetos de facturación comunes y sus relaciones (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions) #### Customer v1 Diagrama que muestra objetos de facturación comunes y sus relaciones (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions) ### Definiciones de los objetos de la API | Recurso | Definición | | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Cuenta configurada como un cliente](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) | Representa a un cliente en la API Accounts v2 que compra una suscripción. Configura un objeto `Cuenta` como cliente y asócialo a una suscripción para realizar cargos recurrentes y hacerles un seguimiento, y para gestionar los productos a los que se suscribe. Consulta nuestra [guía Usar cuentas como clientes](https://docs.stripe.com/connect/use-accounts-as-customers.md) para obtener más información. | | [Customer](https://docs.stripe.com/api/customers.md) | Representa a un cliente en la API Clientes que compra una suscripción. Usa el objeto `Cliente` asociado a una suscripción para realizar y hacer seguimiento de los cargos recurrentes y administrar los productos a los que se suscriben. | | [Derecho](https://docs.stripe.com/api/entitlements/active-entitlement.md) | Representa el acceso de un cliente a una funcionalidad incluida en un producto de servicio al que está suscrito. Cuando creas una suscripción para la compra recurrente de un producto por parte de un cliente, se crea automáticamente un derecho activo para cada funcionalidad asociada a ese producto. Cuando un cliente accede a tus servicios, utiliza sus derechos activos para habilitar las funcionalidades incluidas en su suscripción. | | [Funcionalidad](https://docs.stripe.com/api/entitlements/feature.md) | Representa una funcionalidad o capacidad a la que tus clientes pueden acceder cuando se suscriben a un producto de servicio. Puedes incluir funciones en un producto creando ProductFeatures. | | [Factura](https://docs.stripe.com/api/invoices.md) | Una declaración de importes que un cliente adeuda y que rastrea los estados de pago desde el borrador hasta su pago o su finalización. Las suscripciones generan facturas automáticamente. | | [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) | Una forma de crear flujos de pago dinámicos. Un PaymentIntent hace un seguimiento del ciclo de vida del flujo del proceso compra del cliente y activa pasos adicionales de autenticación, si así lo exigen las disposiciones normativas, las reglas antifraude personalizadas de Radar o los métodos de pago con redireccionamiento. Las facturas crean PaymentIntents de forma automática. | | [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) | Los métodos de pago que usa un cliente para pagar tus productos. Por ejemplo, puedes guardar una tarjeta de crédito en un objeto `Cuenta` o `Cliente` configurado por el cliente y usarla para hacer pagos recurrentes para ese cliente. Por lo general, se usa con las API Payment Intents o Setup Intents. | | [Precio](https://docs.stripe.com/api/prices.md) | Define el precio por unidad, la moneda y el ciclo de facturación para un producto. | | [Producto](https://docs.stripe.com/api/products.md) | Un bien o servicio que vende tu empresa. Un producto de servicio puede incluir una o más funciones. | | [ProductFeature](https://docs.stripe.com/api/product-feature.md) | Representa la inclusión de una sola funcionalidades en un solo producto. Cada producto está asociado a una ProductFeature para cada funcionalidad que incluye, y cada funcionalidad está asociada a una ProductFeature para cada producto que la incluye. | | [Suscripción](https://docs.stripe.com/api/subscriptions.md) | Representa la compra recurrente programada de un producto por parte de un cliente. Usa una suscripción para cobrar pagos y proporcionar entrega repetida o acceso continuo a un producto. | Veamos un ejemplo de cómo funcionan juntos los productos, las funcionalidades y los derechos. Imagina que quieres configurar un servicio recurrente que ofrezca dos niveles: un producto estándar con funcionalidad básica y un producto avanzado que agregue funcionalidad extendida. 1. Creas dos funcionalidades: `basic_features` y `extended_features`. 1. Creas dos productos: `standard_product` y `advanced_product`. 1. Para el producto estándar, creas una ProductFeature que asocia `basic_features` con `standard_product`. 1. Para el producto avanzado, creas dos ProductFeatures: una que asocia `basic_features` con `advanced_product` y otra que asocia `extended_features` con `advanced_product`. Un cliente, `first_customer`, se suscribe al producto estándar. Cuando creas la suscripción, Stripe crea automáticamente un derecho que asocia `first_customer` con `basic_features`. Otro cliente, `second_customer`, se suscribe al producto avanzado. Al crear la suscripción, Stripe crea automáticamente dos derechos: uno que asocia `second_customer` con `basic_features` y otro que asocia `second_customer` con `extended_features`. Puedes determinar qué funcionalidades aprovisionar para un cliente [recuperando sus derechos activos o recibiendo notificaciones del evento Resumen de derechos activos](https://docs.stripe.com/billing/entitlements.md#entitlements). No tienes que recuperar sus suscripciones, productos y funcionalidades. ## Configura Stripe 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. A continuación, instala la CLI de Stripe. La CLI proporciona pruebas de webhook y puedes ejecutarla para realizar llamadas API a Stripe. Esta guía muestra cómo utilizar la CLI para configurar un modelo de precios en una sección posterior. Para obtener más opciones de instalación, consulta [Empezar a usar la CLI de Stripe](https://docs.stripe.com/stripe-cli.md). ## Crear el modelo de tarifas [CLI o Dashboard de Stripe] Los [modelos de precios recurrentes](https://docs.stripe.com/products-prices/pricing-models.md) representan los productos o servicios que vendes, cuánto cuestan, qué monedas aceptas para los pagos y el período de servicio para las suscripciones. Para crear el modelo de precios, crea [productos](https://docs.stripe.com/api/products.md) (lo que vendes) y [precios](https://docs.stripe.com/api/prices.md) (cuánto cuestan y con qué frecuencia cobrar por los productos). En este ejemplo, se utiliza una tarifa con tasa fija con dos opciones de niveles de servicio diferentes: básico y premium. Para cada opción de nivel de servicio, debes crear un producto y un precio recurrente. Si quieres agregar un cargo por única vez, como el costo de instalación, crea un tercer producto con un precio por única vez. Cada producto se factura de forma mensual. El precio del producto básico es de 5 USD. El precio del producto premium es de 15 USD. Consulta la guía de [tarifas con tasa fija](https://docs.stripe.com/subscriptions/pricing-models/flat-rate-pricing.md) para ver un ejemplo con tres niveles. #### Dashboard Ve a la página [Agregar un producto](https://dashboard.stripe.com/test/products/create) y crea dos productos. Agrega un precio a cada producto, cada uno con un período de facturación mensual recurrente: - Producto prémium: servicio prémium con más funcionalidades - Precio: Tarifa plana | 15 USD - Producto básico: servicio básico con las funcionalidades mínimas - Precio: Tarifa plana | 5 USD Después de crear los precios, registra los ID de precio para usarlos en otros pasos. Los ID de precio se ven así: `price_G0FvDp6vZvdwRZ`. Cuando esté todo listo, usa el botón **Copiar en modo activo**, en la parte superior derecha de la página, para clonar el producto y pasarlo de [entorno de prueba a modo activo](https://docs.stripe.com/keys.md#test-live-modes). #### API Puedes usar la API para crear los [productos](https://docs.stripe.com/api/products.md) y los [precios](https://docs.stripe.com/api/prices.md). Crear el producto premium: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Premium Service" \ -d "description=Premium service with extra features" ``` Crear el producto básico: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Basic Service" \ -d "description=Basic service with minimum features" ``` Registra el ID de cada producto. Se ve así: ```json { "id": "prod_H94k5odtwJXMtQ", "object": "product", "active": true, "attributes": [ ], "created": 1587577341, "description": "Premium service with extra features", "images": [ ], "livemode": false, "metadata": { }, "name": "Billing Guide: Premium Service", "statement_descriptor": null, "type": "service", "unit_label": null, "updated": 1587577341 } ``` Usa los ID de producto para crear el precio de cada producto. El número [unit_amount](https://docs.stripe.com/api/prices/object.md#price_object-unit_amount) está en centavos. Por ejemplo, `1500` = 15 USD. Crear el precio superior: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{PREMIUM_PRODUCT_ID}} \ -d unit_amount=1500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Crear el precio básico: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{BASIC_PRODUCT_ID}} \ -d unit_amount=500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Registra el ID de cada precio para poder utilizarlo en los pasos siguientes. Se ve así: ```json { "id": "price_HGd7M3DV3IMXkC", "object": "price", "product": "prod_HGd6W1VUqqXGvr", "type": "recurring", "currency": "usd", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "active": true, "billing_scheme": "per_unit", "created": 1589319695, "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "unit_amount": 1500, "unit_amount_decimal": "1500", "tiers": null, "tiers_mode": null, "transform_quantity": null } ``` ## Crear el cliente [Cliente y servidor] Stripe requiere un *cliente* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) para cada suscripción. En el front-end de tu aplicación, recopila toda la información necesaria de tus usuarios y envíala al back-end. > #### Use the Accounts v2 API to represent customers > > If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Es posible que desees usar una biblioteca de la red para enviar solicitudes de red a tu back-end. Este documento utiliza [okhttp](https://square.github.io/okhttp/), pero puedes utilizar cualquier biblioteca que funcione mejor en tu proyecto. ```groovy dependencies { ... implementation "com.squareup.okhttp3:okhttp:4.12.0" } ``` Si necesitas recopilar datos de la dirección, el Address Element te permite recopilar una dirección de envío o facturación para tus clientes. Para obtener más información sobre el Address Element, visita la página de [Address Element](https://docs.stripe.com/elements/address-element.md). ```kotlin import androidx.compose.foundation.layout.Column import androidx.compose.material3.Button import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import org.json.JSONObject @Composable fun RegisterView() { var email by remember { mutableStateOf("") } Column { OutlinedTextField(value = email, label = { Text(text = "Email") }, onValueChange = { email = it }) Button(onClick = { val body = JSONObject().put("email", email).toString() .toRequestBody("application/json".toMediaType()) val request = Request.Builder().url("http://10.0.2.2:4567/create-customer").post(body).build() CoroutineScope(Dispatchers.IO).launch { OkHttpClient().newCall(request).execute().use { response -> if (response.isSuccessful) { println(JSONObject(response.body!!.string()).get("customer")) } } } }) { Text(text = "Submit") } } } ``` Crea el “Customer Object” de Stripe en el servidor. ```curl curl https://api.stripe.com/v1/customers \ -u "<>:" \ -d email={{CUSTOMER_EMAIL}} \ -d name={{CUSTOMER_NAME}} \ -d "shipping[address][city]=Brothers" \ -d "shipping[address][country]=US" \ -d "shipping[address][line1]=27 Fredrick Ave" \ -d "shipping[address][postal_code]=97712" \ -d "shipping[address][state]=CA" \ -d "shipping[name]={{CUSTOMER_NAME}}" \ -d "address[city]=Brothers" \ -d "address[country]=US" \ -d "address[line1]=27 Fredrick Ave" \ -d "address[postal_code]=97712" \ -d "address[state]=CA" ``` ## Crear la suscripción [Cliente y servidor] > Si quieres procesar el Payment Element antes de crear una suscripción, consulta [Recopilar los datos de pago antes de crear un Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=subscription). Permite que tu nuevo cliente elija un plan y luego cree la suscripción. En esta guía, elegirá entre un plan Básico y un plan Prémium. En tu aplicación, envía el ID de precio seleccionado y el ID del registro del cliente al back-end. ```kotlin import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import org.json.JSONObject fun createSubscription(priceId: String, customerId: String): SubscriptionResponse? { val body = JSONObject() .put("priceId", priceId) .put("customerId", customerId).toString() .toRequestBody("application/json".toMediaType()) val request = Request.Builder().url("http://10.0.2.2:4567/create-subscription").post(body).build() OkHttpClient().newCall(request).execute().use { response -> if (response.isSuccessful) { // SubscriptionsResponse is data class conforming to the expected response from your backend. // It should include the client_secret, as discussed below. return Gson().fromJson(response.body!!.string(), SubscriptionResponse::class.java) } } return null } ``` En el back-end, crea una suscripción con estado `incomplete` usando `payment_behavior=default_incomplete`. Luego, devuelve el `client_secret` desde el primer [payment intent](https://docs.stripe.com/payments/payment-intents.md) de la suscripción al front-end para completar el pago expandiendo el [`confirmation_secret`](https://docs.stripe.com/api/invoices/object.md#invoice_object-confirmation_secret) en la factura más reciente de la suscripción. Para habilitar el [comportamiento de suscripción mejorado](https://docs.stripe.com/billing/subscriptions/billing-mode.md), establece `billing_mode[type]` en `flexible`. Debes utilizar la versión de la API de Stripe [2025-06-30.basil](https://docs.stripe.com/changelog/basil.md#2025-06-30.basil) o posterior. Establece [save_default_payment_method](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-payment_settings-save_default_payment_method) en `on_subscription` para guardar el método de pago como predeterminado para una suscripción cuando un pago se realiza correctamente. Guardar un método de pago predeterminado aumenta la tasa de éxito de futuros pagos de suscripción. En el siguiente ejemplo, se crea una `Subscription` y se expande el `confirmation_secret` de su última factura en la respuesta. Esto te permite pasar el secreto al front-end para confirmar el pago. #### Accounts v2 ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "items[0][price]={{PRICE_ID}}" \ -d payment_behavior=default_incomplete \ -d "payment_settings[save_default_payment_method]=on_subscription" \ -d "billing_mode[type]=flexible" \ -d "expand[0]=latest_invoice.confirmation_secret" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/subscriptions \ -u "<>:" \ -d "customer={{CUSTOMER_ID}}" \ -d "items[0][price]={{PRICE_ID}}" \ -d payment_behavior=default_incomplete \ -d "payment_settings[save_default_payment_method]=on_subscription" \ -d "billing_mode[type]=flexible" \ -d "expand[0]=latest_invoice.confirmation_secret" ``` > Si usas un *precio en múltiples monedas* (A single Price object can support multiple currencies. Each purchase uses one of the supported currencies for the Price, depending on how you use the Price in your integration), usa el parámetro [currency](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-currency) para indicarle a la suscripción cuál de las monedas del precio debe usar. (Si omites el parámetro `currency`, la suscripción utilizará la moneda predeterminada del precio). La suscripción ahora está `inactiva` y a la espera de pago. El ejemplo de respuesta que figura a continuación destaca los campos mínimos que deben almacenarse, pero puedes almacenar los campos a los que tu solicitud accede con frecuencia. #### Accounts v2 ```json {"id": "sub_JgRjFjhKbtD2qz", "object": "subscription", "application_fee_percent": null, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": "null" }, "billing_cycle_anchor": 1623873347, "billing_cycle_anchor_config": null, "cancel_at": null, "cancel_at_period_end": false, "canceled_at": null, "cancellation_details": { "comment": null, "feedback": null, "reason": null }, "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd","customer_account": identifier("customerAccount"), "days_until_due": null, "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "discounts": [], "ended_at": null, "invoice_customer_balance_settings": { "account_tax_ids": null, "issuer": { "type": "self" } }, "items": { "object": "list", "data": [ { "id": "si_JgRjmS4Ur1khEx", "object": "subscription_item", "created": 1623873347,"current_period_end": 1626465347, "current_period_start": 1623873347, "discounts": [], "metadata": { }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "subscription": "sub_JgRjFjhKbtD2qz", "tax_rates": [ ] } ], "has_more": false, "total_count": 1, "url": "/v1/subscription_items?subscription=sub_JgRjFjhKbtD2qz" }, "latest_invoice": { "id": "in_1J34pzGPZ1iASj5zB87qdBNZ", "object": "invoice", "account_country": "US", "account_name": "Angelina's Store", "account_tax_ids": null, "amount_due": 2000, "amount_overpaid": 0, "amount_paid": 0, "amount_remaining": 2000, "amount_shipping": 0, "attempt_count": 0, "attempted": false, "auto_advance": false, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": null, "status": null }, "automatically_finalizes_at": null, "billing_reason": "subscription_update", "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd", "custom_fields": null, "customer_account": identifier("customerAccount"), "customer_address": null, "customer_email": "angelina@stripe.com", "customer_name": null, "customer_phone": null, "customer_shipping": { "address": { "city": "", "country": "US", "line1": "Berry", "line2": "", "postal_code": "", "state": "" }, "name": "", "phone": null }, "customer_tax_exempt": "none", "customer_tax_ids": [ ], "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "description": null, "discounts": [], "due_date": null, "effective_at": "1623873347", "ending_balance": 0, "footer": null, "from_invoice": null, "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp", "invoice_pdf": "https://pay.stripe.com/invoice/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp/pdf", "last_finalization_error": null, "latest_revision": null, "lines": { "object": "list", "data": [ { "id": "il_1N2CjMBwKQ696a5NeOawRQP2", "object": "line_item", "amount": 2000, "currency": "usd", "description": "1 × Gold Special (at $20.00 / month)", "discount_amounts": [ ], "discountable": true, "discounts": [ ], "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "livemode": false, "metadata": { }, "parent": { "invoice_item_details": null, "subscription_item_details": { "invoice_item": null, "proration": false, "proration_details": { "credited_items": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subscription_item": "si_JgRjmS4Ur1khEx" }, "type": "subscription_item_details" }, "period": { "end": 1626465347, "start": 1623873347 }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "taxes": [] } ], "has_more": false, "total_count": 1, "url": "/v1/invoices/in_1J34pzGPZ1iASj5zB87qdBNZ/lines" }, "livemode": false, "metadata": { }, "next_payment_attempt": null, "number": "C008FC2-0354", "on_behalf_of": null, "parent": { "quote_details": null, "subscription_details": { "metadata": {}, "pause_collection": null, "subscription": "sub_JgRjFjhKbtD2qz" } }, "payment_intent": { "id": "pi_1J34pzGPZ1iASj5zI2nOAaE6", "object": "payment_intent", "allowed_source_types": [ "card" ], "amount": 2000, "amount_capturable": 0, "amount_received": 0, "application": null, "application_fee_amount": null, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic", "charges": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/charges?payment_intent=pi_1J34pzGPZ1iASj5zI2nOAaE6" }, "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu", "confirmation_method": "automatic", "created": 1623873347, "currency": "usd", "customer": "cus_CMqDWO2xODTZqt", "description": "Subscription creation", "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "last_payment_error": null, "livemode": false, "metadata": { }, "next_action": null, "next_source_action": null, "on_behalf_of": null, "payment_method": null, "payment_method_options": { "card": { "installments": null, "network": null, "request_three_d_secure": "automatic" } }, "payment_method_types": [ "card" ], "receipt_email": null, "review": null, "setup_future_usage": "off_session", "shipping": null, "source": "card_1By6iQGPZ1iASj5z7ijKBnXJ", "statement_descriptor": null, "statement_descriptor_suffix": null, "status": "requires_confirmation", "transfer_data": null, "transfer_group": null }, "payment_settings": { "payment_method_options": null, "payment_method_types": null, "save_default_payment_method": "on_subscription" }, "period_end": 1623873347, "period_start": 1623873347, "post_payment_credit_notes_amount": 0, "pre_payment_credit_notes_amount": 0, "receipt_number": null, "starting_balance": 0, "statement_descriptor": null, "status": "open", "status_transitions": { "finalized_at": 1623873347, "marked_uncollectible_at": null, "paid_at": null, "voided_at": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subtotal": 2000, "tax": null, "tax_percent": null, "total": 2000, "total_discount_amounts": [], "total_tax_amounts": [], "transfer_data": null, "webhooks_delivered_at": 1623873347 }, "livemode": false, "metadata": { }, "next_pending_invoice_item_invoice": null, "pause_collection": null, "pending_invoice_item_interval": null, "pending_setup_intent": null, "pending_update": null, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "quantity": 1, "schedule": null, "start": 1623873347, "start_date": 1623873347, "status": "incomplete", "tax_percent": null, "transfer_data": null, "trial_end": null, "trial_start": null } ``` #### Customers v1 ```json {"id": "sub_JgRjFjhKbtD2qz", "object": "subscription", "application_fee_percent": null, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": "null" }, "billing_cycle_anchor": 1623873347, "billing_cycle_anchor_config": null, "cancel_at": null, "cancel_at_period_end": false, "canceled_at": null, "cancellation_details": { "comment": null, "feedback": null, "reason": null }, "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd","customer": identifier("customer"), "days_until_due": null, "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "discounts": [], "ended_at": null, "invoice_customer_balance_settings": { "account_tax_ids": null, "issuer": { "type": "self" } }, "items": { "object": "list", "data": [ { "id": "si_JgRjmS4Ur1khEx", "object": "subscription_item", "created": 1623873347,"current_period_end": 1626465347, "current_period_start": 1623873347, "discounts": [], "metadata": { }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "subscription": "sub_JgRjFjhKbtD2qz", "tax_rates": [ ] } ], "has_more": false, "total_count": 1, "url": "/v1/subscription_items?subscription=sub_JgRjFjhKbtD2qz" }, "latest_invoice": { "id": "in_1J34pzGPZ1iASj5zB87qdBNZ", "object": "invoice", "account_country": "US", "account_name": "Angelina's Store", "account_tax_ids": null, "amount_due": 2000, "amount_overpaid": 0, "amount_paid": 0, "amount_remaining": 2000, "amount_shipping": 0, "attempt_count": 0, "attempted": false, "auto_advance": false, "automatic_tax": { "disabled_reason": null, "enabled": false, "liability": null, "status": null }, "automatically_finalizes_at": null, "billing_reason": "subscription_update", "collection_method": "charge_automatically", "created": 1623873347, "currency": "usd", "custom_fields": null, "customer": identifier("customer"), "customer_address": null, "customer_email": "angelina@stripe.com", "customer_name": null, "customer_phone": null, "customer_shipping": { "address": { "city": "", "country": "US", "line1": "Berry", "line2": "", "postal_code": "", "state": "" }, "name": "", "phone": null }, "customer_tax_exempt": "none", "customer_tax_ids": [ ], "default_payment_method": null, "default_source": null, "default_tax_rates": [ ], "description": null, "discounts": [], "due_date": null, "effective_at": "1623873347", "ending_balance": 0, "footer": null, "from_invoice": null, "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp", "invoice_pdf": "https://pay.stripe.com/invoice/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp/pdf", "last_finalization_error": null, "latest_revision": null, "lines": { "object": "list", "data": [ { "id": "il_1N2CjMBwKQ696a5NeOawRQP2", "object": "line_item", "amount": 2000, "currency": "usd", "description": "1 × Gold Special (at $20.00 / month)", "discount_amounts": [ ], "discountable": true, "discounts": [ ], "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "livemode": false, "metadata": { }, "parent": { "invoice_item_details": null, "subscription_item_details": { "invoice_item": null, "proration": false, "proration_details": { "credited_items": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subscription_item": "si_JgRjmS4Ur1khEx" }, "type": "subscription_item_details" }, "period": { "end": 1626465347, "start": 1623873347 }, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "price": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "price", "active": true, "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "tiers_mode": null, "transform_quantity": null, "type": "recurring", "unit_amount": 2000, "unit_amount_decimal": "2000" }, "quantity": 1, "taxes": [] } ], "has_more": false, "total_count": 1, "url": "/v1/invoices/in_1J34pzGPZ1iASj5zB87qdBNZ/lines" }, "livemode": false, "metadata": { }, "next_payment_attempt": null, "number": "C008FC2-0354", "on_behalf_of": null, "parent": { "quote_details": null, "subscription_details": { "metadata": {}, "pause_collection": null, "subscription": "sub_JgRjFjhKbtD2qz" } }, "payment_intent": { "id": "pi_1J34pzGPZ1iASj5zI2nOAaE6", "object": "payment_intent", "allowed_source_types": [ "card" ], "amount": 2000, "amount_capturable": 0, "amount_received": 0, "application": null, "application_fee_amount": null, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic", "charges": { "object": "list", "data": [ ], "has_more": false, "total_count": 0, "url": "/v1/charges?payment_intent=pi_1J34pzGPZ1iASj5zI2nOAaE6" }, "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu", "confirmation_method": "automatic", "created": 1623873347, "currency": "usd", "customer": "cus_CMqDWO2xODTZqt", "description": "Subscription creation", "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ", "last_payment_error": null, "livemode": false, "metadata": { }, "next_action": null, "next_source_action": null, "on_behalf_of": null, "payment_method": null, "payment_method_options": { "card": { "installments": null, "network": null, "request_three_d_secure": "automatic" } }, "payment_method_types": [ "card" ], "receipt_email": null, "review": null, "setup_future_usage": "off_session", "shipping": null, "source": "card_1By6iQGPZ1iASj5z7ijKBnXJ", "statement_descriptor": null, "statement_descriptor_suffix": null, "status": "requires_confirmation", "transfer_data": null, "transfer_group": null }, "payment_settings": { "payment_method_options": null, "payment_method_types": null, "save_default_payment_method": "on_subscription" }, "period_end": 1623873347, "period_start": 1623873347, "post_payment_credit_notes_amount": 0, "pre_payment_credit_notes_amount": 0, "receipt_number": null, "starting_balance": 0, "statement_descriptor": null, "status": "open", "status_transitions": { "finalized_at": 1623873347, "marked_uncollectible_at": null, "paid_at": null, "voided_at": null }, "subscription": "sub_JgRjFjhKbtD2qz", "subtotal": 2000, "tax": null, "tax_percent": null, "total": 2000, "total_discount_amounts": [], "total_tax_amounts": [], "transfer_data": null, "webhooks_delivered_at": 1623873347 }, "livemode": false, "metadata": { }, "next_pending_invoice_item_invoice": null, "pause_collection": null, "pending_invoice_item_interval": null, "pending_setup_intent": null, "pending_update": null, "plan": { "id": "price_1J32RfGPZ1iASj5zHHp57z7C", "object": "plan", "active": true, "amount": 2000, "amount_decimal": "2000", "billing_scheme": "per_unit", "created": 1623864151, "currency": "usd", "interval": "month", "interval_count": 1, "livemode": false, "metadata": { }, "nickname": null, "product": "prod_JgPF5xnq7qBun3", "tiers": null, "tiers_mode": null, "transform_usage": null, "trial_period_days": null, "usage_type": "licensed" }, "quantity": 1, "schedule": null, "start": 1623873347, "start_date": 1623873347, "status": "incomplete", "tax_percent": null, "transfer_data": null, "trial_end": null, "trial_start": null } ``` ### Actualiza el punto de conexión del servidor Agrega la creación de claves efímeras al punto de conexión de la suscripción y devuélvela en la respuesta: #### Ruby ```ruby ephemeral_key = Stripe::EphemeralKey.create( {customer: customer_id}, {stripe_version: '2025-06-30.basil'} ) { subscriptionId: subscription.id, clientSecret: subscription.latest_invoice.confirmation_secret.client_secret, ephemeralKey: ephemeral_key.secret, customerId: customer_id, }.to_json ``` ### Actualiza tu modelo de respuesta ```kotlin data class SubscriptionsResponse( val subscriptionId: String, val clientSecret: String, val ephemeralKey: String, val customerId: String ) ``` ### Pasar la configuración del cliente a PaymentSheet Agrega lo siguiente al configurar PaymentSheet: ```kotlin PaymentSheet.Configuration( primaryButtonLabel = "Subscribe for $15/month", merchantDisplayName = "My merchant name", customer = PaymentSheet.CustomerConfiguration( id = customerId, ephemeralKeySecret = ephemeralKey ) ) ``` ## Recopilar datos de pago [Cliente] Utiliza [Payment Sheet](https://docs.stripe.com/payments/mobile/payment-sheet.md) para recolectar detalles del pago y activar la suscripción. Puedes personalizar Elements para que coincida con la apariencia de tu solicitud. Payment Sheet recopila de forma segura todos los detalles de pago necesarios para una amplia variedad de métodos de pago. Más información sobre los [métodos de pago admitidos](https://docs.stripe.com/payments/payment-methods/payment-method-support.md#product-support) para Payment Sheet y Subscriptions. ### Agregar el Payment Element a tu aplicación > Este paso muestra una forma de empezar, pero puedes usar cualquier [integración de pagos dentro de la aplicación](https://docs.stripe.com/payments/mobile.md). Inicializa y presenta el Payment Element móvil usando la clase PaymentSheet. ```kotlin import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.PaymentSheetResult import com.stripe.android.paymentsheet.rememberPaymentSheet @Composable fun SubscribeView(clientSecret: String) { val paymentSheet = rememberPaymentSheet(::onPaymentSheetResult) Button(onClick = { paymentSheet.presentWithPaymentIntent( clientSecret, PaymentSheet.Configuration( primaryButtonLabel = "Subscribe for $15/month", merchantDisplayName = "My merchant name", // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. allowsDelayedPaymentMethods = true ) ) }) { Text(text = "Subscribe") } } fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { when (paymentSheetResult) { is PaymentSheetResult.Canceled -> { print("Canceled") } is PaymentSheetResult.Failed -> { print("Error: ${paymentSheetResult.error}") } is PaymentSheetResult.Completed -> { // Display for example, an order confirmation screen print("Completed") } } } ``` El Payment Element móvil renderiza una hoja que le permite a tu cliente seleccionar un método de pago. El formulario recopila automáticamente todos los datos de pago necesarios para el método de pago que elijan. Establecer `allowsDelayedPaymentMethods` en true permite aceptar métodos de pago de [notificación diferida](https://docs.stripe.com/payments/payment-methods.md#payment-notification) como cuentas bancarias en EE. UU. Para estos métodos de pago, el estado final del pago no se conoce cuando se completa el `PaymentSheet`, sino que se efectúa con éxito o falla más tarde. Si aceptas este tipo de métodos de pago, infórmale al cliente que su pedido está confirmado y solo finalízalo (por ejemplo, envía el producto) cuando el pago se realice correctamente. Puedes personalizar el Payment Element para que coincida con el diseño de tu aplicación usando la [propiedad `appearance`](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=ios) de tu objeto `PaymentSheet.Configuration`. ### Confirmar pago El Payment Element móvil crea un PaymentMethod y confirma que el primer PaymentIntent de la suscripción está incompleto, lo que genera un cargo. Si se requiere *autenticación reforzada de clientes* (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) (SCA) para el pago, el Payment Element se encarga del proceso de autenticación antes de confirmar el PaymentIntent. ## Escuchar webhooks [Servidor] Para completar la integración, tienes que procesar los *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) que envió Stripe. Estos son eventos que se originan cada vez que un estado dentro de Stripe cambia, por ejemplo, cuando las suscripciones crean facturas nuevas. En tu aplicación, configura un controlador de HTTP para aceptar una solicitud POST que contenga el evento de webhook y verifica la firma del evento: #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/webhook' do # You can use webhooks to receive information about asynchronous payment events. # For more about our webhook events check out https://stripe.com/docs/webhooks. webhook_secret = ENV['STRIPE_WEBHOOK_SECRET'] payload = request.body.read if !webhook_secret.empty? # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured. sig_header = request.env['HTTP_STRIPE_SIGNATURE'] event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, webhook_secret ) rescue JSON::ParserError => e # Invalid payload status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature puts '⚠️ Webhook signature verification failed.' status 400 return end else data = JSON.parse(payload, symbolize_names: true) event = Stripe::Event.construct_from(data) end # Get the type of webhook event sent - used to check the status of PaymentIntents. event_type = event['type'] data = event['data'] data_object = data['object'] if event_type == 'invoice.paid' # Used to provision services after the trial has ended. # The status of the invoice will show up as paid. Store the status in your # database to reference when a user accesses your service to avoid hitting rate # limits. # puts data_object end if event_type == 'invoice.payment_failed' # If the payment fails or the customer does not have a valid payment method, # an invoice.payment_failed event is sent, the subscription becomes past_due. # Use this webhook to notify your user that their payment has # failed and to retrieve new card details. # puts data_object end if event_type == 'customer.subscription.deleted' # handle subscription canceled automatically based # upon your subscription settings. Or if the user cancels it. # puts data_object end content_type 'application/json' { status: 'success' }.to_json end ``` Durante el desarrollo, usa la CLI de Stripe para [observar los webhooks y reenviarlos a tu aplicación](https://docs.stripe.com/webhooks.md#test-webhook). Ejecuta lo siguiente en una nueva terminal mientras tu aplicación de desarrollo está funcionando: #### curl ```bash stripe listen --forward-to localhost:4242/webhook ``` Para la producción, configura una URL de punto de conexión de webhook en el Dashboard o utiliza la [API Webhook Endpoints](https://docs.stripe.com/api/webhook_endpoints.md). Necesita escuchar algunos eventos para completar los pasos restantes de esta guía. Consulte [Eventos de suscripción](https://docs.stripe.com/billing/subscriptions/webhooks.md#events) para más detalles sobre los webhooks específicos de suscripción. ## Brindar acceso a tu servicio [Cliente y servidor] Ahora que la suscripción está activa, dale a tu usuario acceso a tu servicio. Para ello, escucha los eventos `customer.subscription.created`, `customer.subscription.updated`, y `customer.subscription.deleted`. Estos eventos pasan un objeto Subscription que contiene un campo `status` que indica si la suscripción está activa, vencida o cancelada. Consulta [el ciclo de vida de la suscripción](https://docs.stripe.com/billing/subscriptions/overview.md#subscription-lifecycle) para obtener una lista completa de estados. En tu controlador de webhook: 1. Verifica el estado de la suscripción. Si es `activo`, entonces tu usuario ha pagado por su producto. 1. Revisa el producto al que se suscribió el cliente y bríndale acceso al servicio. Es mejor revisar el producto que el precio porque te da más flexibilidad en caso de que necesites cambiar la tarifa o el intervalo de facturación. 1. Almacena el `product.id`, `subscription.id` y el `subscription.status` en tu base de datos junto con `customer.id` que ya guardaste. Consulta este registro cuando tengas que determinar qué funcionalidades habilitar para el usuario en tu aplicación. El estado de la suscripción puede cambiar en cualquier momento de su ciclo de vida, incluso si tu solicitud no hace ninguna llamada directa a Stripe. Por ejemplo, se puede producir un error de renovación debido a una tarjeta de crédito vencida, lo que genera que el estado de la suscripción pase a vencido. O, si usas el [portal de clientes](https://docs.stripe.com/customer-management.md), un usuario puede optar por cancelar la suscripción sin ingresar a tu aplicación directamente. El uso correcto del controlador mantiene el estado de tu solicitud sincronizado con Stripe. ## Cancelar la suscripción [Cliente y servidor] Con frecuencia, se les permite a los clientes cancelar su suscripción. En este ejemplo, se agrega la opción de cancelación en la página de configuración de la cuenta. En este ejemplo, el ID de la suscripción se recopila en el front-end, pero tu aplicación puede obtener esta información de tu base de datos para el usuario que ha iniciado sesión. ![Modelo de interfaz de cancelación de suscripciones.](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-subscriptions-guide-account-settings.6559626ba4b434826a67abfea165e097.png) Configuración de la cuenta con la posibilidad de cancelar la suscripción ```kotlin fun cancelSubscription(subscriptionId: String): SubscriptionResponse? { val body = JSONObject().put("subscriptionId", subscriptionId).toString() .toRequestBody("application/json".toMediaType()) val request = Request.Builder().url("http://10.0.2.2:4567/cancel-subscription").post(body).build() OkHttpClient().newCall(request).execute().use { response -> if (response.isSuccessful) { return Gson().fromJson(response.body!!.string(), SubscriptionResponse::class.java) } } return null } ``` En el back-end, define el punto de conexión para que la aplicación haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/cancel-subscription' do content_type 'application/json' data = JSON.parse request.body.read deleted_subscription = Stripe::Subscription.cancel(data['subscriptionId']) deleted_subscription.to_json end ``` Tu back-end recibe un evento `customer.subscription.deleted`. Una vez que se cancela la suscripción, actualiza tu base de datos para eliminar el ID de suscripción de Stripe que estaba almacenado y limitar el acceso al servicio. Cuando una suscripción se cancela, no se puede reactivar. En su lugar, recopila información de facturación actualizada de tu cliente, actualiza su método de pago predeterminado y crea una nueva suscripción con su registro de cliente existente. ## Prueba tu integración ### Prueba métodos de pago Usa la siguiente tabla para probar diferentes métodos y escenarios de pago. | Método de pago | Escenario | Cómo hacer la prueba | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Débito directo BECS | Tu cliente paga correctamente con débito directo BECS. | Completa el formulario con el número de cuenta `900123456` y BSB `000000`. El PaymentIntent confirmado pasa en un principio al estado `processing` y, tres minutos más tarde, a `succeeded`. | | Débito directo BECS | El pago de tu cliente falla con un código de error `account_closed`. | Completa el formulario con el número de cuenta `111111113` y BSB `000000`. | | Tarjeta de crédito | El pago con tarjeta se efectúa correctamente y no requiere autenticación. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4242 4242 4242 4242` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | El pago con tarjeta requiere *autenticación* (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). | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0025 0000 3155` y cualquier fecha de vencimiento, CVC y código postal. | | Tarjeta de crédito | La tarjeta es rechazada con el código `insufficient_funds`. | Completa el formulario de tarjeta de crédito con el número de tarjeta `4000 0000 0000 9995` y cualquier fecha de vencimiento, CVC y código postal. | | Débito directo SEPA | Tu cliente paga correctamente con débito directo SEPA. | Completa el formulario con el número de cuenta `AT321904300235473204`. El PaymentIntent confirmado pasa inicialmente al estado “en proceso” y, tres minutos más tarde, a “completado”. | | Débito directo SEPA | El estado de PaymentIntent de tu cliente pasa de `processing` a `requires_payment_method`. | Completa el formulario con el número de cuenta `AT861904300235473202`. | ### Supervisa eventos Configura webhooks para recibir notificaciones de los eventos de cambios en las suscripciones, como actualizaciones y cancelaciones. Obtén más información sobre los [webhooks de suscripciones](https://docs.stripe.com/billing/subscriptions/webhooks.md). Puedes ver los eventos en el [Dashboard](https://dashboard.stripe.com/test/events) o con la [CLI de Stripe](https://docs.stripe.com/webhooks.md#test-webhook). Para obtener más detalles, consulta [cómo probar tu integración con Billing](https://docs.stripe.com/billing/testing.md). ## Optional: Permitir que los clientes cambien de plan [Cliente y servidor] Para permitirles a los clientes cambiar de suscripción, recopila el ID de precio de la opción a la que quieren pasar. A continuación, envía el nuevo ID de precio desde la aplicación a un punto de conexión del back-end. En este ejemplo, también se especifica el ID de suscripción, pero puedes recuperarlo de tu base de datos para el usuario que ha iniciado sesión. ```kotlin fun updateSubscription(subscriptionId: String, priceId: String): SubscriptionResponse? { val body = JSONObject() .put("priceId", priceId) .put("subscriptionId", subscriptionId).toString() .toRequestBody("application/json".toMediaType()) val request = Request.Builder().url("http://10.0.2.2:4567/update-subscription").post(body).build() OkHttpClient().newCall(request).execute().use { response -> if (response.isSuccessful) { // It should include the client_secret, as discussed below. return Gson().fromJson(response.body!!.string(), SubscriptionResponse::class.java) } } return null } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada especificando el ID de suscripción y el nuevo ID de precio. La suscripción ahora es Premium, a USD 15 por mes, en lugar de Básica a USD 5 por mes. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/update-subscription' do content_type 'application/json' data = JSON.parse request.body.read subscription = Stripe::Subscription.retrieve(data['subscriptionId']) updated_subscription = Stripe::Subscription.update( data['subscriptionId'], cancel_at_period_end: false, items: [ { id: subscription.items.data[0].id, price: data['newPriceId'] } ] ) updated_subscription.to_json end ``` En tu aplicación, se recibe un evento `customer.subscription.updated`. ## Optional: Previsualizar un cambio de precio [Cliente y servidor] Cuando tu cliente cambia de suscripción, a menudo es necesario hacer un ajuste en el importe adeudado que se conoce como [prorrateo](https://docs.stripe.com/billing/subscriptions/prorations.md). Puedes usar el [punto de conexión de creación de la vista previa de facturas](https://docs.stripe.com/api/invoices/create_preview.md) para mostrarles a tus clientes el importe ajustado. Desde la aplicación, pasa los datos de la vista previa de la factura a un punto de conexión del back-end. ```kotlin fun createPreviewInvoice( subscriptionId: String, priceId: String, newPriceId: String ): InvoiceResponse? { val body = JSONObject() .put("priceId", priceId) .put("subscriptionId", subscriptionId) .put("newPriceId", newPriceId).toString() .toRequestBody("application/json".toMediaType()) val request = Request.Builder().url("http://10.0.2.2:4567/create-preview-invoice").post(body).build() OkHttpClient().newCall(request).execute().use { response -> if (response.isSuccessful) { // InvoiceResponse is a data class conforming to the expected response from your backend return Gson().fromJson(response.body!!.string(), InvoiceResponse::class.java) } } return null } ``` En el back-end, define el punto de conexión para que el front-end haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/create-preview-invoice' do content_type 'application/json' data = JSON.parse request.body.read subscription = Stripe::Subscription.retrieve(data['subscriptionId']) invoice = Stripe::Invoice.create_preview( customer: data['customerId'], subscription: data['subscriptionId'], subscription_details: { items: [ { id: subscription.items.data[0].id, deleted: true }, { price: data['newPriceId'], deleted: false } ] } ) invoice.to_json end ``` ## Optional: Mostrar el método de pago del cliente [Cliente y servidor] Mostrar la marca y los últimos 4 dígitos de la tarjeta le permite al cliente saber qué tarjeta se está utilizando o si es necesario actualizar el método de pago. Desde el front-end, pasa el ID del método de pago a un punto de conexión del back-end que recupere los datos del método de pago. ```kotlin fun retrieveCustomerPaymentMethod(paymentMethodId: String): PaymentMethodResponse? { val body = JSONObject() .put("paymentMethodId", paymentMethodId).toString() .toRequestBody("application/json".toMediaType()) val request = Request.Builder().url("http://10.0.2.2:4567/retrieve-customer-payment-method").post(body) .build() OkHttpClient().newCall(request).execute().use { response -> if (response.isSuccessful) { // PaymentMethodResponse is a data class conforming to the expected response from your backend return Gson().fromJson(response.body!!.string(), PaymentMethodResponse::class.java) } } return null } ``` En el back-end, define el punto de conexión para que la aplicación haga la llamada. #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' post '/retrieve-customer-payment-method' do content_type 'application/json' data = JSON.parse request.body.read payment_method = Stripe::PaymentMethod.retrieve(data['paymentMethodId']) payment_method.to_json end ``` Ejemplo de respuesta: ```json { "id": "pm_1GcbHY2eZvKYlo2CoqlVxo42", "object": "payment_method", "billing_details": { "address": { "city": null, "country": null, "line1": null, "line2": null, "postal_code": null, "state": null }, "email": null, "name": null, "phone": null }, "card": { "brand": "visa", "checks": { "address_line1_check": null, "address_postal_code_check": null, "cvc_check": "pass" }, "country": "US", "exp_month": 8, "exp_year": 2021, "fingerprint": "Xt5EWLLDS7FJjR1c", "funding": "credit", "generated_from": null, "last4": "4242", "three_d_secure_usage": { "supported": true }, "wallet": null }, "created": 1588010536, "customer": "cus_HAxB7dVQxhoKLh", "livemode": false, "metadata": {}, "type": "card" } ``` > Te recomendamos guardar `paymentMethod.id` y `last4` en tu base de datos, por ejemplo, `paymentMethod.id` como `stripeCustomerPaymentMethodId` en tu colección o tabla de `users`. Si lo necesitas, también tienes la opción de guardar `exp_month`, `exp_year`, `fingerprint` y `billing_details`. Esto sirve para limitar el número de llamadas a Stripe, tanto para mejorar el rendimiento como para evitar una posible limitación de la frecuencia. ## Cuéntales a tus clientes qué es Stripe Stripe recopila información sobre las interacciones de los clientes con Elements para proporcionarte servicios, mejorarlos y prevenir el fraude. Esto incluye el uso de cookies y direcciones IP para identificar qué Elements vio un cliente durante una sola sesión de finalización de compra. Tienes la responsabilidad de divulgar y obtener todos los derechos y consentimientos necesarios para que Stripe use los datos para dichos fines. Si deseas obtener más información, visita nuestro [centro de privacidad](https://stripe.com/legal/privacy-center#as-a-business-user-what-notice-do-i-provide-to-my-end-customers-about-stripe). #### React Native Aprende a vender *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis) de precio fijo. Usarás [Payment Element para dispositivos móviles](https://docs.stripe.com/payments/accept-a-payment.md) para crear un formulario de pago personalizado que puedes integrar en tu aplicación. ![Página de suscripción de precio fijo con Payment Element móvil](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-collect-payment-details-mobile.b11cdc8fa8952d753238df4df3375fa6.png) > Si vendes productos o servicios digitales que se consumen dentro de tu aplicación (por ejemplo, suscripciones, monedas de juegos, niveles de juegos, acceso a contenido prémium o desbloqueo de una versión completa), debes usar las API de compra desde la aplicación de Apple. Esta regla tiene algunas excepciones, como los servicios personales uno a uno y las [aplicaciones basadas en regiones específicas](https://support.stripe.com/questions/changes-to-mobile-app-store-rules). Consulta las [pautas de revisión de la App Store](https://developer.apple.com/app-store/review/guidelines/#payments) para obtener más información. ## Crear tu suscripción Esta guía te explica cómo: - Modelar tu empresa creando un catálogo de productos. - Crear un proceso de registro para agregar clientes. - Crear suscripciones y recopilar información de pago. - Comprueba y supervisa el estado de los pagos y las suscripciones. - Permitir que los clientes cambien de plan o cancelen la suscripción. - Aprenda a usar el [modo facturación flexible](https://docs.stripe.com/billing/subscriptions/billing-mode.md) para acceder a un comportamiento de facturación mejorado y funcionalidades adicionales. ## Cómo modelar la suscripción en Stripe [Subscriptions](https://docs.stripe.com/api/subscriptions.md) simplifica tu facturación y crea automáticamente *Facturas* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) y [PaymentIntents](https://docs.stripe.com/api/payment_intents.md) por ti. Para crear y activar una suscripción, necesitas crear primero un *Producto para modelar lo que se vende, y un *Precio, que determina el intervalo y el importe por cobrar. También necesitas un [Cliente](https://docs.stripe.com/api/customers.md) para almacenar los *PaymentMethods* utilizados para realizar cada pago recurrente.** #### Accounts v2 Diagrama que muestra objetos de facturación comunes y sus relaciones (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions) #### Customer v1 Diagrama que muestra objetos de facturación comunes y sus relaciones (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions) ### Definiciones de los objetos de la API | Recurso | Definición | | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Cuenta configurada como un cliente](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) | Representa a un cliente en la API Accounts v2 que compra una suscripción. Configura un objeto `Cuenta` como cliente y asócialo a una suscripción para realizar cargos recurrentes y hacerles un seguimiento, y para gestionar los productos a los que se suscribe. Consulta nuestra [guía Usar cuentas como clientes](https://docs.stripe.com/connect/use-accounts-as-customers.md) para obtener más información. | | [Customer](https://docs.stripe.com/api/customers.md) | Representa a un cliente en la API Clientes que compra una suscripción. Usa el objeto `Cliente` asociado a una suscripción para realizar y hacer seguimiento de los cargos recurrentes y administrar los productos a los que se suscriben. | | [Derecho](https://docs.stripe.com/api/entitlements/active-entitlement.md) | Representa el acceso de un cliente a una funcionalidad incluida en un producto de servicio al que está suscrito. Cuando creas una suscripción para la compra recurrente de un producto por parte de un cliente, se crea automáticamente un derecho activo para cada funcionalidad asociada a ese producto. Cuando un cliente accede a tus servicios, utiliza sus derechos activos para habilitar las funcionalidades incluidas en su suscripción. | | [Funcionalidad](https://docs.stripe.com/api/entitlements/feature.md) | Representa una funcionalidad o capacidad a la que tus clientes pueden acceder cuando se suscriben a un producto de servicio. Puedes incluir funciones en un producto creando ProductFeatures. | | [Factura](https://docs.stripe.com/api/invoices.md) | Una declaración de importes que un cliente adeuda y que rastrea los estados de pago desde el borrador hasta su pago o su finalización. Las suscripciones generan facturas automáticamente. | | [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) | Una forma de crear flujos de pago dinámicos. Un PaymentIntent hace un seguimiento del ciclo de vida del flujo del proceso compra del cliente y activa pasos adicionales de autenticación, si así lo exigen las disposiciones normativas, las reglas antifraude personalizadas de Radar o los métodos de pago con redireccionamiento. Las facturas crean PaymentIntents de forma automática. | | [PaymentMethod](https://docs.stripe.com/api/payment_methods.md) | Los métodos de pago que usa un cliente para pagar tus productos. Por ejemplo, puedes guardar una tarjeta de crédito en un objeto `Cuenta` o `Cliente` configurado por el cliente y usarla para hacer pagos recurrentes para ese cliente. Por lo general, se usa con las API Payment Intents o Setup Intents. | | [Precio](https://docs.stripe.com/api/prices.md) | Define el precio por unidad, la moneda y el ciclo de facturación para un producto. | | [Producto](https://docs.stripe.com/api/products.md) | Un bien o servicio que vende tu empresa. Un producto de servicio puede incluir una o más funciones. | | [ProductFeature](https://docs.stripe.com/api/product-feature.md) | Representa la inclusión de una sola funcionalidades en un solo producto. Cada producto está asociado a una ProductFeature para cada funcionalidad que incluye, y cada funcionalidad está asociada a una ProductFeature para cada producto que la incluye. | | [Suscripción](https://docs.stripe.com/api/subscriptions.md) | Representa la compra recurrente programada de un producto por parte de un cliente. Usa una suscripción para cobrar pagos y proporcionar entrega repetida o acceso continuo a un producto. | Veamos un ejemplo de cómo funcionan juntos los productos, las funcionalidades y los derechos. Imagina que quieres configurar un servicio recurrente que ofrezca dos niveles: un producto estándar con funcionalidad básica y un producto avanzado que agregue funcionalidad extendida. 1. Creas dos funcionalidades: `basic_features` y `extended_features`. 1. Creas dos productos: `standard_product` y `advanced_product`. 1. Para el producto estándar, creas una ProductFeature que asocia `basic_features` con `standard_product`. 1. Para el producto avanzado, creas dos ProductFeatures: una que asocia `basic_features` con `advanced_product` y otra que asocia `extended_features` con `advanced_product`. Un cliente, `first_customer`, se suscribe al producto estándar. Cuando creas la suscripción, Stripe crea automáticamente un derecho que asocia `first_customer` con `basic_features`. Otro cliente, `second_customer`, se suscribe al producto avanzado. Al crear la suscripción, Stripe crea automáticamente dos derechos: uno que asocia `second_customer` con `basic_features` y otro que asocia `second_customer` con `extended_features`. Puedes determinar qué funcionalidades aprovisionar para un cliente [recuperando sus derechos activos o recibiendo notificaciones del evento Resumen de derechos activos](https://docs.stripe.com/billing/entitlements.md#entitlements). No tienes que recuperar sus suscripciones, productos y funcionalidades. ## Configura Stripe 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. A continuación, instala la CLI de Stripe. La CLI proporciona pruebas de webhook y puedes ejecutarla para realizar llamadas API a Stripe. Esta guía muestra cómo utilizar la CLI para configurar un modelo de precios en una sección posterior. Para obtener más opciones de instalación, consulta [Empezar a usar la CLI de Stripe](https://docs.stripe.com/stripe-cli.md). ## Crear el modelo de tarifas [CLI o Dashboard de Stripe] Los [modelos de precios recurrentes](https://docs.stripe.com/products-prices/pricing-models.md) representan los productos o servicios que vendes, cuánto cuestan, qué monedas aceptas para los pagos y el período de servicio para las suscripciones. Para crear el modelo de precios, crea [productos](https://docs.stripe.com/api/products.md) (lo que vendes) y [precios](https://docs.stripe.com/api/prices.md) (cuánto cuestan y con qué frecuencia cobrar por los productos). En este ejemplo, se utiliza una tarifa con tasa fija con dos opciones de niveles de servicio diferentes: básico y premium. Para cada opción de nivel de servicio, debes crear un producto y un precio recurrente. Si quieres agregar un cargo por única vez, como el costo de instalación, crea un tercer producto con un precio por única vez. Cada producto se factura de forma mensual. El precio del producto básico es de 5 USD. El precio del producto premium es de 15 USD. Consulta la guía de [tarifas con tasa fija](https://docs.stripe.com/subscriptions/pricing-models/flat-rate-pricing.md) para ver un ejemplo con tres niveles. #### Dashboard Ve a la página [Agregar un producto](https://dashboard.stripe.com/test/products/create) y crea dos productos. Agrega un precio a cada producto, cada uno con un período de facturación mensual recurrente: - Producto prémium: servicio prémium con más funcionalidades - Precio: Tarifa plana | 15 USD - Producto básico: servicio básico con las funcionalidades mínimas - Precio: Tarifa plana | 5 USD Después de crear los precios, registra los ID de precio para usarlos en otros pasos. Los ID de precio se ven así: `price_G0FvDp6vZvdwRZ`. Cuando esté todo listo, usa el botón **Copiar en modo activo**, en la parte superior derecha de la página, para clonar el producto y pasarlo de [entorno de prueba a modo activo](https://docs.stripe.com/keys.md#test-live-modes). #### API Puedes usar la API para crear los [productos](https://docs.stripe.com/api/products.md) y los [precios](https://docs.stripe.com/api/prices.md). Crear el producto premium: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Premium Service" \ -d "description=Premium service with extra features" ``` Crear el producto básico: ```curl curl https://api.stripe.com/v1/products \ -u "<>:" \ --data-urlencode "name=Billing Guide: Basic Service" \ -d "description=Basic service with minimum features" ``` Registra el ID de cada producto. Se ve así: ```json { "id": "prod_H94k5odtwJXMtQ", "object": "product", "active": true, "attributes": [ ], "created": 1587577341, "description": "Premium service with extra features", "images": [ ], "livemode": false, "metadata": { }, "name": "Billing Guide: Premium Service", "statement_descriptor": null, "type": "service", "unit_label": null, "updated": 1587577341 } ``` Usa los ID de producto para crear el precio de cada producto. El número [unit_amount](https://docs.stripe.com/api/prices/object.md#price_object-unit_amount) está en centavos. Por ejemplo, `1500` = 15 USD. Crear el precio superior: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{PREMIUM_PRODUCT_ID}} \ -d unit_amount=1500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Crear el precio básico: ```curl curl https://api.stripe.com/v1/prices \ -u "<>:" \ -d product={{BASIC_PRODUCT_ID}} \ -d unit_amount=500 \ -d currency=usd \ -d "recurring[interval]=month" ``` Registra el ID de cada precio para poder utilizarlo en los pasos siguientes. Se ve así: ```json { "id": "price_HGd7M3DV3IMXkC", "object": "price", "product": "prod_HGd6W1VUqqXGvr", "type": "recurring", "currency": "usd", "recurring": { "interval": "month", "interval_count": 1, "trial_period_days": null, "usage_type": "licensed" }, "active": true, "billing_scheme": "per_unit", "created": 1589319695, "livemode": false, "lookup_key": null, "metadata": {}, "nickname": null, "unit_amount": 1500, "unit_amount_decimal": "1500", "tiers": null, "tiers_mode": null, "transform_quantity": null } ``` ## Crear el cliente [Cliente y servidor] Stripe requiere un *cliente* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments) para cada suscripción. En el front-end de tu aplicación, recopila toda la información necesaria de tus usuarios y envíala al back-end. > #### Use the Accounts v2 API to represent customers > > If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Si necesitas recopilar datos de la dirección, el Address Element te permite recopilar una dirección de envío o facturación para tus clientes. Para obtener más información sobre el Address Element, visita la página de [Address Element](https://docs.stripe.com/elements/address-element.md). ```javascript import React from 'react'; import {View, TextInput, StyleSheet, Button, Platform} from 'react-native'; function RegisterView() { const [email, setEmail] = React.useState(''); const createCustomer = async () => { const apiEndpoint = Platform.OS === 'ios' ? 'http://localhost:4242' : 'http://10.0.2.2:4567'; const response = await fetch(`${apiEndpoint}/create-customer`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email: email, }), }); if (response.status === 200) { const customer = await response.json(); console.log(customer); } }; return (