SubSovereign
All guides

SubSovereign en Web & React Native — guía de integración

Esta guía cubre el SDK de JavaScript/TypeScript, que funciona en tres entornos desde una misma biblioteca: React Native (iOS + Android), React Native TV y la web (con Stripe). Lleva tu app de "no tengo ni idea de quién me ha pagado" a "mi app desbloquea las funciones correctas para el usuario correcto, verificadas en mi propio servidor".

Qué hace SubSovereign por ti

Tus usuarios se suscriben a través de una tienda de aplicaciones (Apple, Google) o, en la web, mediante Stripe. SubSovereign responde a una única pregunta para tu app, de forma fiable: ¿qué ha pagado realmente este usuario?

  • Tu app pregunta a SubSovereign por el derecho de acceso del usuario — lo que ha desbloqueado.
  • La validación de recibo se realiza en el servidor, directamente con la tienda (o Stripe), por lo que un cliente manipulado no puede falsificar una suscripción.
  • El muro de pago se configura de forma remota, así que puedes cambiar precios, pruebas y redacción sin necesidad de redeploy.
  • Es autoalojado: se ejecuta en tu infraestructura, los datos de tus usuarios se quedan contigo y no hay porcentaje de ingresos — te quedas con el 100 % de lo que pagan tus usuarios.

Nunca confíes en el cliente. El cliente pregunta; el servidor decide.

Antes de empezar

Necesitarás un servidor SubSovereign en ejecución, una app registrada en el panel de control (que te proporcionará un appId y una clave de API), y tus niveles de acceso (rangos, por ejemplo, pro) creados y vinculados a los productos que compran tus usuarios: productos de App Store / Google Play para React Native, o precios de Stripe para web. Gestiona la compra en sí como lo harías normalmente (bibliotecas de compras integradas en React Native, Stripe Checkout/Billing en web); SubSovereign verifica y registra la compra después.

Paso 1 — Instalar el SDK

npm install @subsovereign/js-sdk
import SubSovereign from '@subsovereign/js-sdk';

Paso 2 — Configurar una vez, al iniciar la app

SubSovereign.configure({
  apiKey:  'YOUR_APP_API_KEY',                  // del panel de control
  appId:   'your-app-id',                       // del panel de control
  baseUrl: 'https://subs.yourdomain.com/api/v1', // TU servidor autoalojado
  userId:  currentUser.id,                      // tu propio ID de usuario estable
  locale:  'es',                                // el idioma del usuario
});

Usa un userId estable para el usuario conectado: el mismo valor en todas partes, para que el acceso le siga en todos los dispositivos y plataformas. Vuelve a ejecutar configure si un usuario diferente inicia sesión.

Paso 3 — Comprobar a qué puede acceder el usuario

La imagen completa se obtiene con checkEntitlements():

try {
  const result = await SubSovereign.checkEntitlements();
  if (result.hasAccess) unlockProFeatures();
  else showFreeExperience();
} catch (err) {
  // Mantén al usuario con su último acceso conocido y vuelve a intentarlo más tarde.
  console.warn('Error al comprobar el derecho de acceso:', err);
}

Para una puerta sencilla hay un asistente de conveniencia, hasAccess(), que se cierra por defecto (devuelve false) en caso de error de red para que un fallo puntual nunca desbloquee funciones de pago por error:

if (await SubSovereign.hasAccess('pro')) unlockProFeatures();

Cada derecho de acceso en result.entitlements incluye accessLevelId, isActive, expiresAt, willRenew y su store. result.fromCache es true si la respuesta provino de la última caché conocida durante una breve interrupción.

Paso 4 — Vender una suscripción

Mostrar el muro de pago

const paywall = await SubSovereign.getPaywallConfig('web'); // o 'ios' | 'android' | 'firetv' | 'roku'
if (paywall) renderPaywall(paywall);   // titular, funciones, productos…
else renderFallbackPaywall();

Completar la compra y luego verificarla

Ejecuta la compra de la forma habitual para la plataforma y, a continuación, pasa el resultado a SubSovereign para que el servidor valide la compra y conceda el nivel de acceso. Elige la llamada que coincida con dónde se realizó la compra:

// Web (Stripe)
await SubSovereign.validateStripeSubscription({
  subscriptionId, productId, accessLevelId: 'pro',
});

// React Native — iOS (StoreKit)
await SubSovereign.validateApplePurchase({ transactionId, productId, accessLevelId: 'pro' });

// React Native — Android (Play Billing)
await SubSovereign.validateGooglePurchase({ purchaseToken, productId, accessLevelId: 'pro' });

Cada una devuelve true una vez que el servidor ha confirmado la compra. Vuelve a ejecutar checkEntitlements() después y desbloquea.

Banderas de funciones

Lanza funciones desde el servidor sin necesidad de deploy:

const flags = await SubSovereign.getFeatureFlags(); // { newPlayer: true, ... }
if (flags.newPlayer) showNewPlayer();

Paso 5 — Privacidad: GDPR y CCPA

await SubSovereign.recordConsent({ purpose: 'analytics', granted: true });

await SubSovereign.requestErasure();            // "olvídame"
const myData = await SubSovereign.exportMyData(); // exportación de datos
await SubSovereign.setDoNotSell(true);          // señal "No vender" de CCPA / GPC

Gestión de errores

checkEntitlements y las llamadas validate… lanzan excepciones en caso de fallo — envuélvelas en try/catch y, en caso de error, mantén al usuario con su último acceso conocido y vuelve a intentarlo más tarde; nunca bloquees a un usuario de pago por un fallo puntual. Los asistentes de conveniencia (hasAccess, getPaywallConfig, getFeatureFlags) en cambio se cierran por defecto, devolviendo false/null/{}, por lo que es seguro llamarlos en línea.

Buenas prácticas

  • Comprobar al montar / iniciar para que el bloqueo sea justo antes de que el usuario llegue a una función bloqueada.
  • Volver a comprobar después de comprar para que la interfaz se actualice inmediatamente.
  • Nunca confíes en el cliente — pregunta al servidor; es quien verificó el recibo.
  • Un userId por usuario real, mantenido estable en web y móvil.

Referencia rápida

Quieres… Llama a…
Configurar el SDK SubSovereign.configure(config)
Ver qué ha desbloqueado el usuario await checkEntitlements()EntitlementResult
Puerta sencilla (cerrado por defecto) await hasAccess('pro')boolean
Mostrar el muro de pago remoto await getPaywallConfig(platform)PaywallConfig | null
Verificar una compra de Stripe / Apple / Google await validateStripeSubscription / validateApplePurchase / validateGooglePurchase(…)
Leer banderas de funciones await getFeatureFlags()
GDPR / CCPA recordConsent · requestErasure · exportMyData · setDoNotSell

Pasos siguientes