Todos los artículos
Análisis a fondo8 min de lectura

Verifica las notificaciones del servidor de App Store antes de actuar sobre un reembolso, porque cualquiera puede enviar datos a tu URL de webhook

Una notificación de reembolso no es más que una petición HTTPS hasta que compruebas su firma. Así se verifican las notificaciones del servidor de App Store y los mensajes RTDN de Google Play, qué firma cada tienda y cuánto te cuesta un reembolso falsificado o rechazado por error.

Un sello de lacre de latón y un sobre sellado junto a un portátil sobre un escritorio bajo la luz cálida de una lámpara, una imagen de por qué conviene verificar las notificaciones del servidor de App Store antes de confiar en ellas

Puntos clave

  • Apple envía cada notificación del servidor de App Store de la versión 2 como un signedPayload, una JSON Web Signature con tres partes en Base64URL: un encabezado, una carga útil y una firma.
  • El encabezado JWS de una notificación del servidor de App Store incluye una cadena de certificados x5c con tres certificados: un certificado hoja de firma, un intermedio de Apple con la extensión Apple Worldwide Developer Relations 1.2.840.113635.100.6.2.1 y una raíz de Apple.
  • La App Store Server Library de Apple verifica las notificaciones con un SignedDataVerifier que comprueba la cadena de certificados, el bundle ID, el entorno y, en producción, el appAppleId, y puede consultar en línea la revocación de certificados.
  • Las notificaciones para desarrolladores en tiempo real de Google Play no están firmadas por Google Play. En una suscripción push, Pub/Sub puede adjuntar un token OpenID Connect firmado en el encabezado Authorization, y tu servidor comprueba su firma, su audiencia y sus claims de email.
  • Google indica que una RTDN solo te informa de que cambió el estado de una compra, así que la respuesta segura ante cualquier notificación de reembolso es confirmarla con la Google Play Developer API antes de revocar el acceso.
  • Apple envía las notificaciones del servidor de App Store desde la subred 17.0.0.0/8, pero una lista de IP permitidas solo limita quién puede llegar a tu endpoint. La firma es lo que demuestra que el mensaje procede de Apple.
  • Un verificador que rechaza por error mensajes auténticos es tan costoso como uno que acepta falsificaciones, porque un CONSUMPTION_REQUEST que descartas tiene un plazo de respuesta de 12 horas y una revisión de contracargo de Google Play tiene 24 horas.

Cualquiera que conozca tu URL de webhook puede enviarle un reembolso. Esa es la incómoda realidad detrás de cada notificación del servidor de App Store y de cada notificación para desarrolladores en tiempo real de Google Play: hasta que la verificas, el mensaje no es más que un POST HTTPS con algo de JSON dentro. Si tu servidor revoca una suscripción, retira créditos o bloquea una cuenta porque una petición decía REFUND, has entregado ese poder a cualquiera capaz de escribir un comando curl.

Ambas tiendas te ofrecen una forma de comprobarlo. Apple firma la propia notificación, de modo que puedes verificar las notificaciones del servidor de App Store sin nada más que el certificado raíz de Apple. Google Play sigue otro camino. El mensaje no está firmado, pero la entrega de Pub/Sub sí puede estarlo, y Google te pide de todos modos que confirmes cada cambio con su API. Veamos qué demuestra cada una y qué cuesta equivocarse en cualquiera de las dos direcciones.

Qué firma realmente cada tienda

PreguntaApp Store Server Notifications V2Google Play RTDN
¿Está firmado el propio mensaje?Sí, signedPayload es un JWSNo, el campo data es JSON codificado en base64
Qué demuestra el remitenteCadena de certificados x5c hasta una raíz de AppleToken OIDC de Pub/Sub en push, o tu propio pull autenticado
Objetos firmados anidadossignedTransactionInfo y signedRenewalInfo, cada uno con su propio JWSNinguno
Campos que deben coincidir con tu appbundleId, appAppleId, environmentpackageName
Red de origen17.0.0.0/8, sandbox y producciónGoogle Cloud Pub/Sub
Confirmar antes de actuarOpcional, los datos firmados son el registroObligatorio, Google indica llamar a la Developer API
TransporteHTTPS, TLS 1.2 o posteriorPush HTTPS, o pull con biblioteca cliente

Cómo verificar las notificaciones del servidor de App Store

La documentación de Apple describe el signedPayload como una cadena de tres componentes codificados en Base64URL separados por puntos: un encabezado, una carga útil y una firma, firmada conforme a la especificación JSON Web Signature. Decodificar la carga útil es fácil. Confiar en ella requiere cuatro comprobaciones.

  • Lee el array x5c del encabezado decodificado. Apple documenta el orden: primero el certificado con la clave de firma, después un certificado intermedio de Apple y por último un certificado raíz de Apple.
  • Valida esa cadena contra una raíz de Apple que hayas descargado tú mismo del sitio PKI de Apple, en la práctica Apple Root CA - G3. Nunca confíes en la raíz que llegó dentro del mensaje, porque un falsificador puede poner ahí cualquier certificado.
  • Confirma que el intermedio lleva la extensión Apple Worldwide Developer Relations, 1.2.840.113635.100.6.2.1, y después verifica la firma JWS con la clave pública del certificado hoja.
  • Compara los datos decodificados con tu app: bundleId, appAppleId en producción y environment. Una firma válida de Apple sobre la app de otro desarrollador, o sobre una compra de sandbox que llega a tu endpoint de producción, sigue sin ser tu reembolso.

Después, repite el proceso con lo que hay dentro. El objeto data contiene signedTransactionInfo y signedRenewalInfo, y cada uno es un JWS independiente con su propia cadena x5c. Un manejador de REFUND que verifica el sobre pero lee la transacción sin verificarla ha dejado un hueco en medio.

Usa la biblioteca de Apple en lugar de escribirla tú

Apple publica la App Store Server Library para Swift, Java, Python y Node. Su SignedDataVerifier recibe tus certificados raíz, un indicador de comprobaciones en línea, el entorno, tu bundle ID y, para producción, tu appAppleId. El código fuente de Node muestra lo que exige: exactamente tres certificados en la cadena, la extensión de hoja de Apple 1.2.840.113635.100.6.11.1 y la extensión del intermedio, las fechas de validez de los certificados, y que coincidan el bundle ID, el ID de la app y el entorno. Con las comprobaciones en línea activadas, también pregunta al servidor OCSP si los certificados hoja e intermedio fueron revocados.

Una lupa de joyero sostenida sobre un certificado de papel con un sello en relieve sobre un escritorio de madera, el tipo de inspección minuciosa que merece un mensaje de reembolso antes de confiar en él

¿Basta con una lista de IP permitidas?

No. Apple indica que, si tu servidor necesita una lista de permitidos, debes añadir la subred 17.0.0.0/8, y que esto se aplica tanto a sandbox como a producción. Eso reduce el ruido. No demuestra que un mensaje sea auténtico, y deja de funcionar en cuanto la red de Apple cambia de una forma de la que no te enteraste. Mantén la comprobación de firma como el verdadero control.

Cómo verificar las notificaciones de reembolso de Google Play

Google Play publica los mensajes RTDN en un tema de Pub/Sub que te pertenece, y solo la cuenta de servicio google-play-developer-notifications@system.gserviceaccount.com debe tener el rol de publicador de Pub/Sub sobre él. Tu suscripción entrega después los mensajes de una de dos formas, y cada una tiene su propia prueba.

  • Suscripción pull: tu servidor abre una conexión autenticada con Pub/Sub y recoge los mensajes. No hay endpoint público, así que no hay nada a lo que un extraño pueda enviar datos.
  • Suscripción push con autenticación activada: Pub/Sub firma un JSON Web Token y lo envía en el encabezado Authorization como token Bearer. La guía de Google indica que valides la firma del token y compruebes que sus claims de email y audiencia coinciden con los valores que configuraste, y su código de ejemplo exige además que email_verified sea true. El token puede tener hasta una hora de antigüedad.
  • Suscripción push sin autenticación: cualquier cosa que pueda alcanzar la URL puede enviar un mensaje con forma de RTDN.

Por qué Google quiere que confirmes con la API

Incluso una RTDN perfectamente autenticada no cuenta toda la historia. La guía de configuración de Google dice con claridad que estas notificaciones solo te informan de que cambió el estado de una compra y que debes llamar a la Google Play Developer API para obtener el estado completo. Para una voidedPurchaseNotification, eso significa localizar la compra en la Voided Purchases API, o consultar su estado actual, antes de revocar nada. La llamada a la API se autentica con tu propia cuenta de servicio, así que su respuesta es algo que un falsificador no puede imitar.

Cuánto cuesta en dinero un reembolso falsificado o rechazado

Una notificación de reembolso falsificada en la que confías te cuesta un cliente que paga. Bloqueas a alguien cuyo dinero todavía tienes, abre una incidencia de soporte, y algunos acudirán a la tienda a pedir el reembolso que tu sistema ya fingió conceder. Una compra o renovación falsificada cuesta en sentido contrario: entregas cómputo de GPU, llamadas de pago a APIs de terceros, almacenamiento y pagos a creadores a cambio de ingresos que nunca existieron.

El fallo opuesto es más silencioso y a menudo mayor. Un verificador que rechaza mensajes auténticos, por un appAppleId incorrecto, una configuración de sandbox en producción o un certificado raíz desactualizado, descarta los dos flujos de reembolso en los que tus pruebas cuentan. Apple pide datos de consumo en un plazo de 12 horas tras un CONSUMPTION_REQUEST. Google te da 24 horas para responder a una revisión de contracargo mediante orders.reviewrefund, y en los pedidos realizados después del 3 de agosto de 2026, un contracargo perdido en Google Play te cuesta el precio de compra menos la comisión de servicio de Play, más la comisión que cobra el banco del comprador.

FalloQué ocurreCuánto cuesta
REFUND falsificado aceptadoUn cliente que paga pierde el accesoTiempo de soporte y una solicitud de reembolso real que tú provocaste
Compra falsificada aceptadaAcceso gratuito a funciones de pagoCómputo, llamadas a APIs, almacenamiento y pagos sin ingresos
CONSUMPTION_REQUEST auténtico rechazadoApple decide sin tus datosLa venta, más todo lo ya gastado en entregarla
Revisión de contracargo auténtica rechazadaGoogle decide sin tus pruebasPrecio de compra y comisiones bancarias en pedidos posteriores al 3 de agosto de 2026

Que un error de verificación no te haga perder un plazo

  • Guarda la petición original antes de verificarla, para que un mensaje rechazado nunca se pierda del todo.
  • Genera una alerta ante cada fallo de verificación. Un mensaje falsificado es ruido. Que todos los mensajes fallen a la vez es un error tuyo.
  • En Apple, puedes reprocesar lo que rechazaste. Get Notification History devuelve el signedPayload original de los últimos 180 días, así que corrige el verificador y vuelve a pasarle las cargas guardadas o recuperadas.
  • En Google, una revisión de contracargo pendiente solo existe en su notificación, así que una audiencia push mal configurada es una revisión perdida. Pruébala con Send Test Message en Play Console después de cada cambio.

RefundHalt verifica las notificaciones de ambas tiendas, confirma los reembolsos con las APIs de las tiendas antes de que nada cambie y responde a los CONSUMPTION_REQUEST y a las revisiones de contracargo dentro de sus plazos, para que un mensaje falso no pueda costarte un cliente y uno real no se te escape.

Preguntas frecuentes

¿Cómo verifico una notificación del servidor de App Store?
Verifica el signedPayload como una JSON Web Signature. Lee la cadena de certificados x5c de su encabezado, valídala contra un certificado raíz de Apple que hayas descargado del sitio PKI de Apple, verifica la firma con la clave del certificado hoja y después comprueba que bundleId, appAppleId y environment coinciden con tu app. La App Store Server Library de Apple hace todo esto en su SignedDataVerifier.
¿Qué clave uso para validar las notificaciones del servidor de App Store?
No necesitas ninguna clave de App Store Connect. La clave pública está en el primer certificado de la cadena x5c dentro del encabezado JWS, y solo confías en ella después de validar la cadena hasta un certificado raíz de Apple que hayas obtenido tú mismo. Tu clave de compras dentro de la app sirve para llamar a las APIs de Apple, no para comprobar notificaciones.
¿Están firmadas las notificaciones para desarrolladores en tiempo real de Google Play?
No, Google Play no firma el propio mensaje RTDN. En una suscripción push autenticada, Pub/Sub envía en el encabezado Authorization un token OpenID Connect firmado que tú validas, y Google indica que llames a la Google Play Developer API después de cada notificación para obtener el estado completo de la compra.
¿Debe mi servidor devolver un error cuando una notificación no supera la verificación?
Guarda primero la petición original y después decide. Apple reintenta una notificación de la versión 2 tras una respuesta 40x o 50x, a las 1, 12, 24, 48 y 72 horas del intento anterior. Si el fallo se debe a tu propia configuración, Get Notification History te permite recuperar el signedPayload original durante 180 días y volver a verificarlo una vez corregido.
¿Sigo necesitando verificar las notificaciones si solo permito el rango de IP de Apple?
Sí. Apple pide a los servidores con lista de permitidos que acepten la subred 17.0.0.0/8, lo que limita quién puede conectarse pero no demuestra que un mensaje sea auténtico. La firma JWS es la comprobación que vincula una notificación con Apple y con tu app.

Fuentes y lecturas adicionales

RefundHalt

El piloto automático de reembolsos para App Store y Google Play

Seguir leyendo

La próxima solicitud de reembolso ya está en camino.

Configura RefundHalt en el tiempo que tardas en leer otro correo de soporte sobre un reembolso que no llegaste a impugnar.