Press ESC to close

Suscripciones mensuales con compromiso de 12 meses (StoreKit)

Apple ha incorporado en 2026 (SDK de Xcode 26.5 / iOS, iPadOS, macOS, tvOS y visionOS 26.4) un nuevo modelo de suscripción nativo: la suscripción mensual con un compromiso de 12 meses, conocida como commitment plan. Resuelve por fin, sin trucos, el caso de uso de toda la vida: una suscripción anual que el cliente paga mes a mes.

En esta entrada lo vemos de forma visual y resumida: qué es, dónde está disponible, qué API necesitas y, sobre todo, los dos puntos que más fallos provocan: qué fecha usar para dar acceso y qué pasa cuando el cliente cancela.

1. El concepto de un vistazo

Anual estándar vs. compromiso de 12 meses

Suscripción anual clásica

1 cobro
por adelantado, por todo el año
  • Plan de facturación .upFront
  • Un único pago inicial
  • Renueva una vez al año

Commitment plan (nuevo)

12 cobros
mensuales, con compromiso anual
  • Plan de facturación .monthly
  • El cliente se compromete a los 12 pagos
  • Al terminar, renueva otro compromiso de 12 meses salvo cancelación

Cada periodo mensual se comporta exactamente como una suscripción mensual normal: genera una transacción independiente y concede un mes de acceso. La diferencia es que el cliente se ha comprometido al año completo.

2. Disponibilidad y límites

Requisitos y restricciones

Requisitos técnicos

  • SDK mínimo: Xcode 26.5
  • SO mínimo: iOS, iPadOS, macOS, tvOS y visionOS 26.4

Restricción geográfica

Disponible en todo el mundo EXCEPTO EE. UU. y Singapur.

No es un producto nuevo: es un plan de facturación mensual que activas sobre tu suscripción anual existente desde App Store Connect. Esto significa que el grupo de suscripción y el product ID no cambia.

3. Mapa de la API

Lo que necesitas conocer
ElementoPara qué sirve
Product.SubscriptionInfo.BillingPlanTypeDistingue el plan: .upFront (anual clásico) o .monthly (commitment plan).
Product.SubscriptionInfo.PricingTermsArray con los planes disponibles. Si hay commitment plan, tiene dos entradas (la .upFront y la .monthly).
Transaction.CommitmentInfoDatos para mostrar el progreso del compromiso con tu propia UI personalizada: billingPeriodNumber, totalBillingPeriods, expirationDate y price. Si no quieres complicarte con UI custom, abre la pantalla del sistema llamando a showManageSubscriptions(in:) o showManageSubscriptions(in:subscriptionGroupID:).
billingPlanType (Transaction)Indica si la transacción es de un commitment plan (.monthly). Compruébalo antes de ramificar lógica.
.billingPlanType(.monthly)PurchaseOption que pasas a product.purchase(options:) para comprar el plan mensual.

Comprar el plan

let result = try await product.purchase(options: [.billingPlanType(.monthly)])

Sin esa opción, se compra el plan estándar .upFront. Las renovaciones mensuales posteriores no pasan por purchase(): llegan por Transaction.updates, igual que cualquier suscripción mensual.

Importante

Antes de la compra debes mostrar al cliente los dos importes: el precio mensual y el precio total del compromiso. Es un requisito de Apple, no una recomendación.

4. Las DOS fechas importantes

Es el error número uno. Una transacción de commitment plan lleva dos fechas distintas y usar la equivocada rompe el control de acceso.

Para dar acceso (entitlement)

expirationDate en Transaction

Fin del MES actual

Ej.: 30 de junio de 2026, el final del periodo mensual en curso.

ÚSALA para conceder acceso

Solo para mostrar progreso

expirationDate en Transaction.CommitmentInfo

Fin de los 12 MESES

Ej.: 31 de diciembre de 2026, el final de todo el compromiso.

NUNCA para acceso

Cuidado con la fecha

Si las confundes, o concedes 12 meses de acceso con un solo pago, o revocas el acceso meses antes de tiempo. Lee siempre estas fechas de la transacción más reciente, porque pueden desplazarse tras recuperar un fallo de pago.

Lógica de acceso (igual que una mensual normal)

Recorre currentEntitlements (Transaction.Transactions) y concede acceso cuando, en cada transacción:

  • expirationDate está en el futuro, Y
  • revocationDate es nil, Y
  • isUpgraded es false.

Si tu app ya gestiona bien las suscripciones mensuales, esta misma lógica funciona sin cambios.

5. ¿Qué pasa cuando el cliente cancela?

El segundo concepto contraintuitivo: cancelar significa cancelar la renovación del compromiso, no los pagos que quedan del compromiso actual. El cobro mensual continúa hasta completar los 12 periodos.

Línea temporal de una cancelación
1.
willAutoRenew (Product.SubscriptionInfo.RenewalInfo.CommitmentInfo) cambia a 0.
El compromiso NO se renovará al terminar el año.
2.
El valor de willAutoRenew en la información de renovación de la suscripción (renewalInfo) sigue en 1.
La facturación mensual continúa por los periodos que quedan.
3.
El servidor recibe DID_CHANGE_RENEWAL_STATUS (AUTO_RENEW_DISABLED).
Y siguen llegando DID_RENEW cada mes hasta el final.
4.
Tras el periodo 12: llega EXPIRED.
Aquí, y solo aquí, termina el acceso.

Comportamiento crítico

Sigue dando acceso durante los 12 periodos. Cancelar no revoca el servicio; solo lo hace EXPIRED (o una revocación).

No confundas los dos. El primer willAutoRenew responde a "¿se renovará el compromiso anual?"; mietras que el segundo willAutoRenew responde a "¿se cobrará el mes que viene?".

Fallo de pago: ojo, no hay periodo de gracia

Sin periodo de gracia

La mayor diferencia con una suscripción normal: el Billing Grace Period NO se aplica a los commitment plans. Revoca el acceso en cuanto veas DID_FAIL_TO_RENEW y restáuralo con DID_RENEW (subtipo BILLING_RECOVERY). App Store reintenta el cobro hasta 90 días.

6. Conclusión

Los commitment plans hacen nativo el clásico "anual pagado a plazos". Si tu app ya gestiona suscripciones mensuales, el 90 % del trabajo está hecho: la lógica de acceso es la misma. Solo tienes que recordar tres cosas: usar expirationDate (Transaction) para el acceso, seguir dando servicio tras una cancelación hasta EXPIRED y revocar de inmediato si falla un pago (sin periodo de gracia). Pruébalo de principio a fin en el sandbox con renovación acelerada (puedes configurarlo desde el apartado Developer, dentro del apartado de configuración de tu dispostivo de prueba).

Bibliografía y fuentes consultadas

Reflexiones de alguien que disfruta investigando y conectando temas; no es asesoría legal.