El manejo de reembolsos falla de formas silenciosas, así que prueba los reembolsos de compras dentro de la app en el sandbox antes de que lo haga un cliente real
Tu manejo de reembolsos solo se ejecuta cuando el cliente ya se ha ido, así que un error en él permanece invisible hasta que cuesta dinero real. Ambas tiendas te permiten disparar un reembolso primero en un entorno de prueba. Aquí te explicamos cómo probar los reembolsos de compras dentro de la app en la App Store y Google Play antes de que uno sea real.

Puntos clave
- Las pruebas de StoreKit en Xcode te permiten reembolsar una compra localmente haciendo clic en la flecha de reembolso del Transaction Manager, lo que dispara el listener Transaction.updates de tu app, pero nunca contacta con Apple, así que no se envía ninguna App Store Server Notification.
- Para probar el lado del servidor en Apple, apunta una URL de App Store Server Notifications V2 de sandbox a tu backend: un reembolso en el sandbox entrega entonces un REFUND real, y una solicitud de reembolso entrega un CONSUMPTION_REQUEST, a tu servidor.
- El endpoint Request a Test Notification de Apple envía una notificación de tipo TEST a la URL que configuraste y devuelve un testNotificationToken, así que puedes confirmar que tu webhook es accesible antes de que se dispare cualquier evento real.
- El sandbox de Apple nunca reintenta una notificación fallida, así que un webhook que esté caído cuando el sandbox dispara pierde el evento sin un segundo intento, el mismo tipo de fallo que más tarde te cuesta una ventana de reembolso real.
- Google Play ofrece a los license testers un método de pago llamado Test card, approves then charges back, que dispara una PendingRefundReviewNotification momentos después de la compra para que puedas ensayar tu respuesta orders.reviewrefund de 24 horas.
- Para un license tester en Google Play, una compra sin confirmar se reembolsa automáticamente después de 3 minutos en lugar de los 3 días que espera producción, así que una ruta de confirmación rota falla rápido y a la vista en las pruebas.
- Un manejador de reembolsos que nunca probaste es el que mantiene activo el acceso de pago de un cliente reembolsado, y a partir del 3 de agosto de 2026 una respuesta a un chargeback de Google Play sin probar puede costarte el precio de la compra menos la tarifa de servicio de Play más la tarifa del banco.
Tu manejo de reembolsos es la única ruta de código que solo se ejecuta cuando el cliente ya se ha ido. Nada en tu QA normal la toca, porque para llegar a ella tienes que ser reembolsado de verdad. Así que se lanza sin probar, permanece en silencio durante meses y luego falla en un reembolso real, donde el fallo cuesta dinero en lugar de una prueba en rojo. La solución es dejar de tratar un reembolso como algo que te ocurre y empezar a disparar uno a propósito. Tanto Apple como Google te permiten disparar un reembolso en un entorno de prueba y observar cómo reacciona tu servidor. Aquí te explicamos cómo probar los reembolsos de compras dentro de la app en la App Store y Google Play antes de que un cliente que paga demuestre que tu manejador estaba roto.
Los tres entornos en los que puede dispararse un reembolso, y solo uno es producción
Hay tres lugares separados donde puede dispararse un reembolso de Apple o Google mientras desarrollas, y no son intercambiables. Dos de ellos son tuyos para disparar cuando quieras. El tercero es producción, donde nunca quieres encontrarte por primera vez con un error de reembolso. La trampa es suponer que el fácil, las pruebas locales en Xcode, demuestra toda tu tubería. Demuestra tu app. No dice nada sobre tu servidor.
Las pruebas de StoreKit en Xcode son locales, así que ejercitan tu app y nada más
Las pruebas de StoreKit integradas en Xcode se ejecutan contra un archivo de configuración en tu Mac, sin ida y vuelta a Apple. Abre el StoreKit Transaction Manager desde la barra de depuración, selecciona una transacción comprada y haz clic en la flecha curva de reembolso. La transacción cambia a reembolsada y el listener Transaction.updates de tu app se dispara, exactamente como lo haría en el mundo real. También puedes llamar a beginRefundRequest para presentar la hoja de reembolso real, y en el entorno de Xcode el problema que elijas se corresponde uno a uno con un RevocationReason, con el reembolso aplicado de inmediato. Esta es la forma más rápida de demostrar que tu cliente corta el acceso en el momento en que revocationDate deja de ser nulo. Es también todo lo que las pruebas locales pueden decirte, porque nada aquí llega nunca a los servidores de Apple, así que no se envía ninguna App Store Server Notification. Tu backend no se entera de nada.
El sandbox es donde tu servidor por fin se entera de un reembolso
Para probar la mitad de tu integración que decide el dinero, tu servidor, necesitas el sandbox de Apple. Configura una URL de App Store Server Notifications V2 de sandbox en App Store Connect, inicia sesión con un tester de sandbox en un dispositivo y compra. Ahora un reembolso en el sandbox entrega una notificación REFUND real a tu backend, y una solicitud de reembolso sobre un consumible o un renovable automáticamente entrega un CONSUMPTION_REQUEST, el mismo payload firmado que recibirá tu servidor de producción. Antes de disparar nada, llama al endpoint Request a Test Notification. Le indica al servidor de la App Store que envíe una notificación de tipo TEST a la URL que configuraste y te entrega un testNotificationToken, que pasas a Get Test Notification Status para confirmar la entrega. Si esa ida y vuelta no funciona, tampoco funcionará ninguna notificación real.
| Entorno | Qué puede disparar | Qué demuestra | Qué no puede hacer |
|---|---|---|---|
| Pruebas de StoreKit en Xcode | Un reembolso mediante el Transaction Manager o la hoja de beginRefundRequest | Tu app reacciona a un reembolso localmente, en segundos | Nunca contacta con Apple, así que no se envía ninguna notificación al servidor |
| Sandbox | REFUND y CONSUMPTION_REQUEST reales a tu servidor, más una notificación TEST bajo demanda | Tu backend recibe, verifica y actúa sobre el payload firmado | No reintenta una notificación que tu endpoint no logra recibir |
| Producción | Cada reembolso, con dinero real | Nada que quieras aprender aquí primero | No puedes deshacer el coste de un error |
Cómo probar los reembolsos de compras dentro de la app en la App Store
Ejecútalo en este orden, desde la comprobación barata del cliente hasta la ida y vuelta completa del servidor. Cada paso ejercita una pieza diferente, y los posteriores son los que producción de verdad te factura.
- Crea una clave de In-App Purchase en Users and Access, Integrations, In-App Purchase en App Store Connect, y úsala para firmar tus llamadas a la App Store Server API.
- Apunta tu URL de App Store Server Notifications V2 de sandbox a tu backend, luego llama a Request a Test Notification y confirma que el payload
TESTllega y se verifica contra la cadena de certificados de Apple. - En el Transaction Manager de Xcode, reembolsa una compra y confirma que tu app retira el derecho en el instante en que se establece
revocationDate. - Inicia sesión con un tester de sandbox, compra un consumible, solicita un reembolso y confirma que tu servidor recibe el
CONSUMPTION_REQUESTy puede ensamblar y enviar una respuesta Send Consumption Information bien dentro de la ventana de 12 horas. - Reembolsa una compra de sandbox y confirma que la notificación
REFUNDllega a tu servidor, que revocas el acceso o descuentas el saldo del consumible, y que una entrega repetida de la misma notificación no se aplica dos veces.

Cómo ensayar un reembolso y un chargeback en Google Play
Google Play no tiene un modo local como el de Xcode. Todo se ejecuta contra los servidores de Google, pero los license testers lo mantienen gratis y seguro. Añade tus cuentas de Google de prueba como license testers en Play Console y obtienen un conjunto de métodos de pago de prueba que nunca cobran dinero real. Google marca cada compra de prueba con un aviso en el centro del diálogo de compra, y no se calculan impuestos. Lo que importa para probar reembolsos es qué instrumento de prueba eliges, porque cada uno produce un resultado diferente.
| Método de pago de prueba | Qué simula | Por qué lo usarías |
|---|---|---|
| Test instrument, always approves | Una compra exitosa y limpia | Preparar un pedido que luego puedes reembolsar o revocar |
| Test instrument, always declines | Un pago fallido | Confirmar que no concedes nada ante un rechazo |
| Slow test card, approves after a few minutes | Una compra pendiente que luego tiene éxito | Ejercitar tu manejo de PENDING antes de conceder acceso |
| Slow test card, declines after a few minutes | Una compra pendiente que luego falla | Confirmar que un rechazo pendiente nunca filtra el derecho |
| Test card, approves then charges back | Un chargeback iniciado por el usuario | Disparar una PendingRefundReviewNotification y ensayar tu respuesta de 24 horas |
Dispara un reembolso, un chargeback y el reembolso automático por falta de confirmación
- Compra con la tarjeta de prueba approve-then-charge-back, y una
PendingRefundReviewNotificationllega a tu topic de Real-time Developer Notifications momentos después. Respóndela con una única llamadaorders.reviewrefund, porque Google solo conserva tu primera respuesta. - Reembolsa y revoca un pedido de prueba desde la pestaña Orders en Play Console para disparar una
VoidedPurchaseNotification, y confirma que tu servidor retira el derecho. - Deja a propósito sin confirmar la compra de un license tester. Google la reembolsa automáticamente después de 3 minutos en lugar de los 3 días que permite producción, y te envía por correo la cancelación, así que una ruta de confirmación rota aparece en minutos, no en el cuarto día en producción.
Lo que realmente cuesta una ruta de reembolso sin probar
Un manejador de reembolsos no es decoración. Es el código que evita que pagues por servir a alguien que ya no te paga. Cuando falla en silencio, el reembolso igual se procesa, pero el acceso, el saldo y el gasto detrás de ellos no se detienen.
Sigue el dinero. Cuando Apple o Google reembolsa una compra, tú devuelves el precio de venta y la tienda devuelve su comisión, hasta aquí el balance queda parejo. Lo que no vuelve es todo lo que ya gastaste entregando el producto: el cómputo detrás de un resultado generado, las llamadas a la API del modelo, el almacenamiento de lo que el usuario guardó, el pago que ya enviaste a un creador. Un manejador de reembolsos que nunca revoca el acceso deja que un usuario reembolsado siga gastando eso con cargo a tu presupuesto, sin nada en el sistema que lo detenga.
Las dos ventanas de evidencia lo agudizan. Un CONSUMPTION_REQUEST que nunca ejercitaste en el sandbox es una respuesta que envías mal formada o tarde, y Apple a menudo concede el reembolso por defecto cuando tu respuesta no llega dentro de las 12 horas. Una respuesta a un chargeback de Google Play que nunca disparaste con la tarjeta de prueba es una ventana de 24 horas que fallas en vivo, y a partir del 3 de agosto de 2026 un chargeback perdido en Play te cuesta el precio de la compra menos la tarifa de servicio de Play más la tarifa de chargeback del banco. Cada uno de esos fallos es reproducible gratis en un entorno de prueba primero. Ninguno es barato en producción.
| Ruta sin probar | Cómo falla en producción | Qué te cuesta |
|---|---|---|
| Manejador de REFUND | Un usuario reembolsado conserva el acceso | El cómputo, las llamadas a la API, el almacenamiento y los pagos que sigues gastando en él |
| Respuesta a CONSUMPTION_REQUEST | Mal formada, o enviada después de 12 horas | Apple concede el reembolso por defecto, así que pierdes la venta y el gasto |
| Respuesta orders.reviewrefund | Omitida o incorrecta dentro de 24 horas | A partir del 3 de agosto de 2026, el precio de la compra menos la tarifa de servicio de Play, más la tarifa de chargeback del banco |
Una lista breve antes de lanzar el manejo de reembolsos
No necesitas un laboratorio. Necesitas haber visto cada evento llegar a tu código una vez.
- Tu app retira el acceso en el momento en que una transacción de StoreKit muestra un
revocationDate, confirmado en el Transaction Manager de Xcode. - La URL de tu servidor de sandbox recibe una notificación
TESTy la verifica contra los certificados de Apple. - Un
REFUNDde sandbox revoca el acceso o descuenta el saldo, y una entrega repetida no cuenta dos veces. - Un
CONSUMPTION_REQUESTde sandbox produce una respuesta Send Consumption Information válida bien dentro de las 12 horas. - Una
PendingRefundReviewNotificationde Google desde la tarjeta de prueba de chargeback produce exactamente una llamadaorders.reviewrefund. - Una compra de prueba de Google Play sin confirmar se reembolsa automáticamente en 3 minutos y tu conciliación lo detecta.
Ejecuta esa lista una vez y el manejo de reembolsos deja de ser el código que esperas que funcione. Se convierte en el código que has visto funcionar.
Preguntas frecuentes
- ¿Puedo probar un reembolso de la App Store sin una compra real?
- Sí. Las pruebas de StoreKit en Xcode te permiten reembolsar una compra localmente a través del Transaction Manager, sin dinero real y sin una cuenta de App Store, lo que dispara el listener Transaction.updates de tu app. No envía una notificación al servidor, así que prueba solo tu app, no tu backend.
- ¿Las pruebas locales de StoreKit envían App Store Server Notifications?
- No. Las pruebas de StoreKit en Xcode se ejecutan por completo en tu Mac contra una configuración local y nunca contactan con los servidores de Apple, así que no se envía nunca ninguna App Store Server Notification, incluida REFUND o CONSUMPTION_REQUEST. Usa el sandbox para probar tu servidor.
- ¿Cómo pruebo una respuesta a un chargeback de Google Play?
- Usa el método de pago de license tester llamado Test card, approves then charges back. Dispara una PendingRefundReviewNotification momentos después de la compra, la misma notificación que envía un chargeback bancario real, así que puedes ensayar tu respuesta orders.reviewrefund de 24 horas.
- ¿Por qué mi compra de prueba de Google Play se reembolsa después de unos minutos?
- Para los license testers, Google reembolsa automáticamente una compra después de 3 minutos si tu app no la ha confirmado, y te envía por correo la cancelación. Producción espera 3 días, pero los testers obtienen la versión acelerada para que una ruta de confirmación rota salga a la luz rápido.
- ¿El sandbox de Apple reintenta una notificación de reembolso fallida?
- No. El sandbox no reintenta las App Store Server Notifications, así que si tu endpoint está caído cuando se dispara un reembolso de sandbox, la notificación se descarta sin un segundo intento. Confirma que tu URL es accesible con Request a Test Notification primero.
Fuentes y lecturas adicionales
- Apple Developer: Testing refund requests
- Apple Developer: Testing App Store server notifications
- Apple Developer: Request a Test Notification (App Store Server API)
- Apple Developer: Testing In-App Purchases with the sandbox
- Android Developers: Test your Google Play Billing Library integration
- Android Developers: Help Google dispute chargebacks (orders.reviewrefund)
- Play Console Help: Updates to refund protection and chargeback cost responsibility
RefundHalt
El piloto automático de reembolsos para App Store y Google Play
Seguir leyendo
Lo que un reembolso le cuesta a tu app es más que el precio que devuelves
El precio reembolsado es la línea más pequeña de la factura. Un reembolso también revierte la comisión de la tienda, así que pierdes tu parte, y el cómputo, las llamadas a la API, el almacenamiento y los pagos que ya gastaste se pierden. Un contracargo en Google Play después del 3 de agosto de 2026 añade encima la comisión del banco. Aquí está la factura completa.
Los reembolsos de suscripciones no funcionan como los reembolsos de un solo pago, y la tienda en la que estás decide cuánta voz tienes
Un reembolso de suscripción revierte todo un periodo de facturación, no una única venta. En la App Store, Apple decide y tu servidor solo se entera del resultado. En Google Play eliges tú mismo un reembolso completo o prorrateado. Aquí tienes cómo gestiona cada tienda los reembolsos de suscripciones, y lo que uno te cuesta.