Cómo añadir un programa de referidos a tu app de suscripción

También en: Alemán · Inglés

Un programa de referidos parece cosa de un fin de semana: cada usuario recibe un código y, cuando un amigo se registra, hay recompensa. Luego llegan las preguntas. ¿Cómo sobrevive el código a una instalación desde la App Store? ¿A quién se le paga si el amigo solo empieza una prueba gratuita? ¿Qué pasa si tres semanas después le devuelven el dinero? ¿Y quién hace la transferencia?

Esta guía las responde por orden. La primera parte es neutral respecto al proveedor: los siete bloques que necesita un programa de referidos para un producto de suscripción en iOS, Android y web, con sus compromisos en cada paso. La segunda parte es un recorrido con AppThunder Referrals como implementación de ejemplo, con sus endpoints y su código reales.

Nota: los datos de terceros son de octubre de 2026 y enlazan a su fuente. Es una guía técnica, no asesoramiento legal ni fiscal. Si tu programa funciona dentro de una app de iOS, lee también nuestra guía sobre las reglas de la App Store para programas de referidos: nadie puede garantizar un resultado en App Review.

Los siete bloques

Bloque Qué pregunta responde Error típico
1. Códigos ¿Quién recomienda? Generar códigos en la app
2. Captura ¿Cómo llega el código al nuevo usuario? Contar con que un enlace sobreviva a la instalación
3. Atribución ¿Qué pago corresponde a qué código? Contar instalaciones o registros en vez de pagos
4. Reglas de comisión ¿Cuánto y durante cuánto tiempo? No decidir bruto o neto, ni la moneda
5. Retención y reembolsos ¿Cuándo es definitiva una comisión? Pagar antes de que lleguen los reembolsos
6. Pagos ¿Quién envía el dinero? No registrar qué cubrió cada pago
7. Control del fraude ¿Qué no debe contar? No comprobar autorreferidos

1. Códigos: uno por usuario, creado en el servidor

Cada persona que recomienda tiene un código, guardado junto a su usuario. Tu servidor lo crea la primera vez que hace falta y después devuelve el código guardado. Nunca generes códigos en el cliente.

  • Alfabeto sin ambigüedades. La gente copia códigos de una captura. Quita 0/O y 1/I.
  • Vincula el código al ID de usuario que conoce tu sistema de cobro. Si tu sistema de suscripciones identifica a los usuarios por un app user ID, usa ese mismo ID para quien recomienda; si no, no podrás detectar autorreferidos.
  • Códigos desactivables. Un partner se va o un código acaba en una web de cupones: lo desactivas sin borrar el historial.

2. Captura: cómo llega el código al nuevo usuario

Canal Cómo puede llegar el código ¿Determinista?
Web ?ref=CODE en el enlace, guardado en el navegador hasta el registro Sí, mismo dispositivo y navegador
iOS, app instalada Universal link o esquema de URL con el código Sí
iOS, instalación nueva El nuevo usuario escribe el código Sí
Android, instalación nueva Código escrito o Play Install Referrer Sí
Cualquiera Cruzar IP, modelo de dispositivo y hora («fingerprinting») No: es una suposición

En iOS, un enlace no puede llevar un código a través de una instalación desde la App Store. Los universal links solo abren una app ya instalada. Los enlaces de campaña de App Store Connect (token ct=) alimentan App Analytics de forma agregada y con umbrales mínimos; no le dicen a tu app quién invitó a este usuario. En Android, la Play Install Referrer API devuelve la URL de referencia de la instalación, así que un código en el enlace de Play Store puede llegar al primer arranque.

El patrón que funciona en todas partes: el mensaje para compartir incluye el propio código, no solo un enlace, y el onboarding tiene un campo «¿Tienes un código de referido?». Valida el código contra tu servidor antes de mostrar «aplicado».

El fingerprinting cubre el hueco solo sobre el papel. Es probabilístico (las comisiones pagadas sobre él son dinero real pagado sobre suposiciones) y trae obligaciones de privacidad que un campo de código no tiene.

Decide también qué pasa si alguien llega con dos códigos distintos. First touch (gana el primer código) es fácil de explicar y difícil de secuestrar en el último momento por una web de cupones. Aplica la misma regla en el navegador y en el servidor.

3. Atribución: vincular el código al pago

En un negocio de suscripción, la conversión no es la instalación ni el registro: es el pago, el primero y, según tus reglas, las renovaciones. El código tiene que estar donde tu sistema de cobro lo devuelva cuando entra el dinero:

  • Suscripciones in-app: SDK de suscripciones como RevenueCat permiten añadir atributos propios al suscriptor; según la documentación de RevenueCat, están disponibles, entre otros, en los webhooks.
  • Stripe: mete el código en los metadatos de la suscripción al crear la Checkout Session (subscription_data), y cada factura de esa suscripción lo llevará.
  • Todo lo demás: tu backend guarda en el registro «el usuario X llegó con el código Y» y comunica cada pago.

Tres reglas lo mantienen limpio:

  1. Gana la primera atribución. Un segundo código no mueve a un usuario ya atribuido.
  2. Sigue los cambios de identidad. Los IDs anónimos se fusionan y las suscripciones se transfieren; RevenueCat envía para ello un evento TRANSFER. El referido tiene que moverse con ellos.
  3. Ignora las compras de prueba. Los eventos de sandbox y modo test nunca generan comisión.

4. Reglas de comisión

Regla Ejemplo Encaja con
Porcentaje, recurrente, sin límite 20 % de cada pago Creadores y partners que promocionan siempre
Porcentaje, recurrente, limitado 20 % durante los primeros 12 meses La mayoría de apps de suscripción: premia la retención sin una deuda de por vida
Importe fijo por conversión 10 $ cuando el amigo paga por primera vez Programas de usuario a usuario

Dos decisiones que se suelen saltar:

  • ¿Bruto o neto? Las tiendas se quedan una comisión y en la web hay IVA. Decide si el porcentaje se aplica a lo que pagó el cliente o a lo que te llega a ti, y ponlo en las condiciones del programa.
  • Una sola moneda de cuentas. Los clientes pagan en muchas monedas y el saldo de quien recomienda necesita una. El webhook de RevenueCat, por ejemplo, envía price como precio en USD de la transacción, según su documentación.

Una prueba gratuita es un referido, pero no un ingreso: márcala como atribuida y no pagues nada hasta el primer pago real.

5. Periodo de retención y reembolsos

Los reembolsos llegan después de la compra. Los clientes de la App Store los solicitan más tarde en reportaproblem.apple.com; en los pagos con tarjeta, Stripe indica que las redes suelen permitir disputas en un plazo de 120 días. Si pagas las comisiones al instante, tarde o temprano pagarás alguna sobre dinero que ya no tienes.

La respuesta es un periodo de retención: cada comisión empieza pendiente, pasa a aprobada tras un número fijo de días y solo se pagan las aprobadas. Un reembolso durante la retención anula la comisión. Una retención corta paga antes, una larga atrapa más reembolsos; para suscripciones mensuales, 30 días (más o menos hasta la primera renovación) es un punto de partida razonable. Dos detalles:

  • Anula por transacción, no por suscripción. Reembolsar marzo no debe anular enero y febrero.
  • Una cancelación no es un reembolso. Quien deja de renovar conserva los meses pagados, así que las comisiones ya ganadas se mantienen.

6. Pagos

Opción Qué significa
Pagar tú mismo Exportar quién cobra cuánto, pagar por PayPal, Wise o transferencia, marcar como pagado
Plataforma que paga a los referidores Menos trabajo manual; dependes de que dé de alta a cada referidor
Recompensas in-app Meses gratis o créditos; en iOS, con los mecanismos de Apple (ver abajo)

Para un programa pequeño basta con una exportación mensual y un pago en lote. Registra qué comisiones cubrió cada pago, para poder rastrear un reembolso tardío, y revisa la parte fiscal de pagar a referidores en tu país antes del primer pago.

7. Control del fraude

  • Autorreferidos bloqueados: mismo ID de usuario, un alias suyo o el mismo email en ambos lados
  • Comisiones solo sobre pagos reales, nunca sobre instalaciones o registros
  • Eventos de sandbox y modo test ignorados
  • Retención antes del pago; los reembolsos anulan comisiones
  • Gana la primera atribución
  • Códigos y claves secretas de API solo en el servidor

¿Qué puede recibir la persona invitada?

Recompensar a quien invita es el núcleo de un programa de referidos. Con la persona invitada, iOS se vuelve delicado: un código propio que desbloquea el plan premium choca con la directriz 3.1.1 de las App Review Guidelines: «Apps may not use their own mechanisms to unlock content or functionality». Los detalles están en nuestra guía sobre las reglas de la App Store. Para un descuento, usa las herramientas de las tiendas:

Ambos son descuentos, no atribución: no te dicen quién invitó a quién. Para la comisión sigues necesitando tu propio código de referido.

Recorrido: montarlo con AppThunder Referrals

AppThunder Referrals cuesta una tarifa plana de 19 € al mes (neto, más IVA), sin porcentaje sobre ingresos. Crear un programa es gratis; hace falta una tarjeta antes de crear el primer código de referido. Cada programa tiene una clave pública (pk_aff_…, segura en apps y webs: solo puede validar un código) y una clave secreta (sk_aff_…, solo para el backend). Los ejemplos usan pk_aff_xxx y sk_aff_xxx; la URL base está en tu panel.

Paso 1: fija las reglas

Crea un programa en el panel y elige la regla de comisión (un porcentaje de cada pago, durante todos los meses o un número fijo, o un importe fijo por conversión) y la retención (30 días por defecto). Las comisiones se calculan sobre el precio sin impuestos, antes de las comisiones de las tiendas, en un libro en USD; las demás monedas se convierten al tipo de referencia del BCE del día del pago.

Paso 2: crea el código de cada usuario en tu backend

POST https://<project>.functions.supabase.co/aff-ref-api/codes
Authorization: Bearer sk_aff_xxx
Content-Type: application/json

{ "external_user_id": "<your user id>" }
→ { "code": "K7QM4XP" }

Las llamadas repetidas para el mismo usuario devuelven el mismo código; sin tarjeta registrada, la respuesta es 402 payment_required. En suscripciones in-app, usa el ID de usuario que conoce tu SDK de suscripciones: es el que compara la comprobación de autorreferidos.

Paso 3 (iOS): captura el código y vincúlalo al suscriptor

La plantilla de Swift es un archivo para copiar, no un paquete. Purchases es el SDK de RevenueCat; la plantilla usa las funciones estándar de atributos propios y webhooks de RevenueCat, que cualquier desarrollador puede configurar: no hay alianza ni integración oficial. Lo esencial:

import UIKit
// + your subscription SDK's import (provides Purchases)

enum AppThunderRef {
    static let apiBase = URL(string: "API_BASE")!  // dashboard

    /// Checks a typed code before "applied" UI. Public key only.
    static func validateCode(_ code: String, done: @escaping (Bool) -> Void) {
        var url = URLComponents(url: apiBase.appendingPathComponent("codes/\(code)"), resolvingAgainstBaseURL: false)!
        url.queryItems = [URLQueryItem(name: "public_key", value: "pk_aff_xxx")]
        URLSession.shared.dataTask(with: url.url!) { data, _, _ in
            let json = data.flatMap { try? JSONSerialization.jsonObject(with: $0) as? [String: Any] }
            done(json?["valid"] as? Bool ?? false)
        }.resume()
    }

    /// Attaches the code to the subscriber as the attribute `at_ref`.
    static func applyCode(_ code: String) {
        Purchases.shared.attribution.setAttributes(["at_ref": code])
    }
}

Llama a validateCode desde el campo del onboarding (done se ejecuta en una cola en segundo plano: pasa a la cola principal para tocar la interfaz), muestra «aplicado» y después llama a applyCode. La plantilla completa añade share, que abre la hoja de compartir con Use my code K7QM4XP: https://yourapp.com/?ref=K7QM4XP, para que el código sobreviva a la instalación. Las plantillas de Kotlin, React Native y Flutter hacen lo mismo. En el código de la app no hay ninguna clave secreta: todo lo que se distribuye en una app se puede extraer.

Paso 4: conecta los eventos de compra

  • Webhook de suscripciones (in-app). Pega la URL del webhook de tu panel en los ajustes de webhooks de tu plataforma de suscripciones, junto con el valor de la cabecera Authorization que el panel muestra una sola vez. Las compras iniciales, las renovaciones y las compras sin renovación automática generan comisiones; un reembolso (motivo de cancelación CUSTOMER_SUPPORT) anula la comisión de esa transacción y un reembolso parcial la reduce; una cancelación normal no; los eventos de sandbox se ignoran; un TRANSFER mueve el referido.
  • Stripe (web). Añade en tu panel de Stripe un endpoint de webhook para invoice.paid, invoice_payment.paid, charge.refunded, charge.dispute.created y charge.dispute.closed, pega su signing secret en los ajustes del programa y mete el código en los metadatos de la suscripción como at_ref (paso 5). Una disputa suspende la comisión hasta que se resuelve; los reembolsos parciales la reducen.
  • API REST (cualquier otro cobro). Registra el referido en el alta con POST /referrals (code, referee_external_id) (el ID o email de quien recomienda devuelve 422 self_referral_blocked) y después comunica cada pago:
POST https://<project>.functions.supabase.co/aff-ref-api/events
Authorization: Bearer sk_aff_xxx
Content-Type: application/json

{ "external_user_id": "<your user id>", "amount": 29.00, "currency": "usd",
  "provider_event_id": "inv_1042", "group_ref": "inv_1042" }

provider_event_id hace la llamada idempotente; si envías otra currency, amount se convierte a USD al tipo de referencia del BCE. Un reembolso es la misma llamada con amount negativo, un provider_event_id nuevo y el group_ref de la venta (por defecto, el group_ref de una venta es su propio provider_event_id). Reembolsar una parte reduce la comisión en esa proporción.

Paso 5 (web): snippet y checkout

El panel genera un snippet <script> para cada página a la que pueda llegar un enlace de referido. Lee ?ref=, guarda el primer código durante 90 días en el localStorage de ese dispositivo y expone window.AppThunderRef. Solo contiene la clave pública y no puede crear una comisión por sí solo:

// browser
const code = window.AppThunderRef.getCode();   // null if none
// send `code` to your server with the signup form, as referredBy

// your server (Node, Stripe Billing)
const session = await stripe.checkout.sessions.create({
  mode: 'subscription', /* line_items, success_url … */
  subscription_data: { metadata: { at_ref: req.body.referredBy } },
});

Con la primera factura pagada con un código válido, el webhook de Stripe crea el referido y la comisión; las renovaciones llegan por el mismo webhook. Si tu web funciona dentro de una app creada con AppThunder, el snippet funciona sin cambios en la web view de la app.

Paso 6: muestra las cifras y paga

GET /members/{external_user_id}/stats devuelve { "referrals": n, "earned_usd": x }. Necesita la clave secreta, así que llámalo desde tu servidor para el usuario con sesión iniciada. Tras la retención, exporta las comisiones aprobadas (PayPal Mass Pay, lote de Wise o CSV), paga a tus referidores y marca el lote como pagado.

Checklist antes del lanzamiento

  • Un código por usuario, creado en el servidor
  • Campo de código en el onboarding; el mensaje para compartir incluye el código
  • Código vinculado al suscriptor o a la suscripción de Stripe, no solo a tu registro de alta
  • Regla de comisión, moneda y bruto/neto en las condiciones del programa
  • Retención configurada; los reembolsos anulan por transacción
  • Clave secreta solo en el backend
  • Descuentos para invitados con códigos de oferta de Apple o códigos promocionales de Google Play
  • Programa descrito en las Notes for Review de App Store Connect

Dónde encaja AppThunder Referrals

AppThunder Referrals cubre los bloques 1 a 5 y la contabilidad del 6: códigos generados en el servidor, plantillas para copiar en Swift, Kotlin, React Native, Flutter y web, atribución por webhook de suscripciones, webhook de Stripe o API REST, reglas de comisión, retención configurable, reembolsos que anulan comisiones, bloqueo de autorreferidos y exportaciones para pagos. La atribución es solo determinista: un referido cuenta cuando de verdad llega un código, sin fingerprinting del dispositivo ni emparejamiento probabilístico. 19 € al mes en tarifa plana, sin porcentaje, cancelable mensualmente.

Lo que no hace:

  • Mover dinero. AppThunder nunca retiene ni envía fondos; tú pagas a tus referidores a partir de la exportación y la parte fiscal sigue siendo tuya.
  • Deferred deep links. En una instalación nueva de iOS, el nuevo usuario escribe el código: es la consecuencia de no hacer fingerprinting.
  • Un SDK. Copias una plantilla y ese código es tuyo.
  • Recuperar comisiones ya pagadas. Los reembolsos y las disputas perdidas anulan o reducen comisiones hasta que las marcas como pagadas; después, lo arreglas tú con quien recomendó.
  • Recompensar a los invitados. Los descuentos para el amigo van por códigos de oferta de Apple o códigos promocionales de Google Play, que configuras en las consolas de las tiendas.

Preguntas frecuentes

¿Puede un enlace de referido sobrevivir a una instalación desde la App Store? No de forma determinista. Los universal links solo abren una app instalada y los enlaces de campaña solo alimentan analíticas agregadas. Pon el código en el mensaje para compartir y deja que el nuevo usuario lo escriba.

¿Debo pagar comisión por una prueba gratuita? Cuenta la prueba como referido atribuido, pero paga solo cuando llegue el primer pago real.

¿Cuánto debe durar el periodo de retención? Lo suficiente para cubrir el plazo en el que llegan la mayoría de tus reembolsos. Para suscripciones mensuales, 30 días es un buen punto de partida.

¿Puedo meter la clave secreta en la app si la ofusco? No. Todo lo que se distribuye en una app se puede extraer. La app recibe la clave pública, que valida códigos y nada más.

¿Necesito RevenueCat para usar AppThunder Referrals? No. Las plantillas móviles usan el SDK de RevenueCat para el atributo del suscriptor, pero cualquier backend puede usar la API REST y los productos web pueden usar el webhook de Stripe.