Planes y Suscripciones con PayPal 馃殌 Pagos recurrentes

La mayor铆a de personas en la actualidad nos encontramos suscritos a alg煤n servicio.

El ejemplo m谩s pr谩ctico es Netflix.

Suscribirte a Netflix significa que te inscribes a uno de sus planes, y mes tras mes se realiza un cobro sobre tu tarjeta.

A esto se le conoce tambi茅n como Software as a Service, o de manera abreviada, SaaS.

Significa que tienes acceso a un servicio, a una aplicaci贸n, a un software, a cambio de un pago recurrente.

驴Te gustar铆a tener tu propio sistema de suscripciones?

Hoy aprender谩s a implementar uno, usando la API de PayPal.

Conceptos fundamentales

Ya hemos visto anteriormente c贸mo implementar pagos con PayPal.

Sin embargo, en ese caso se trata de pagos 煤nicos.

Un usuario realiza un pago, se confirma la validez de la transacci贸n, y el usuario recibe aquello por lo que pag贸.

Ahora en cambio, no se trata de una operaci贸n 煤nica, sino m谩s bien de pagos recurrentes.

Para ello, lo primero es entender la diferencia entre:

  • Producto
  • Plan
  • Suscripci贸n

Para la API de PayPal, un Producto es lo que ofreces, un Plan es c贸mo lo ofreces, y una Suscripci贸n es un contrato entre t煤 y cada uno de tus clientes.

Define tus Planes

Antes de empezar a ver c贸digo, es importante que tengas una cuenta de PayPal configurada.

Debes registrar con la API de PayPal al menos un Producto y al menos un Plan.

Recuerda que los usuarios se suscriben a Planes. Ellos deciden qu茅 Plan les interesa m谩s.

Comunicaci贸n con la API de PayPal

Para comunicarnos con la API de PayPal, b谩sicamente necesitamos hacer peticiones HTTP.

脡stas peticiones se pueden hacer de muchas formas:

  • Desde nuestro backend
  • Usando una aplicaci贸n como Postman
  • Desde la terminal usando cURL
  • Etc茅tera

Tus Productos y Planes los puedes definir con cualquier de estas alternativas.

Sin embargo, la comunicaci贸n con la API desde nuestro backend, de igual forma debe llevarse a cabo, ya que ser谩 necesaria para los pasos siguientes.

Entonces, a continuaci贸n te comparto una clase PayPalClient que he definido.

Se trata de una clase PHP que podr谩s usar en tu proyecto para realizar peticiones a la API de PayPal.

use GuzzleHttp\Client as GuzzleClient;

class PayPalClient
{
    private $client;
    private $accessToken;
    
    public function __construct()
    {
        if (config('paypal.settings.mode') === 'live') {
            $clientId = config('paypal.live_client_id');
            $secret = config('paypal.live_secret');
            $baseUri = 'https://api-m.paypal.com';
        } else {
            $clientId = config('paypal.sandbox_client_id');
            $secret = config('paypal.sandbox_secret');
            $baseUri = 'https://api-m.sandbox.paypal.com';
        }
        
        $this->client = new GuzzleClient(['base_uri' => $baseUri]);
        $this->accessToken = $this->getAccessToken($clientId, $secret);      
        // dd($this->accessToken);
    }
    
    private function getAccessToken($clientId, $secret) 
    {
        $response = $this->client->request('POST', '/v1/oauth2/token', [
                'headers' => [
                    'Accept' => 'application/json',
                    'Content-Type' => 'application/x-www-form-urlencoded',
                ],
                'body' => 'grant_type=client_credentials',
                'auth' => [
                    $clientId, $secret, 'basic'
                ]
            ]
        );

        $data = json_decode($response->getBody(), true);
        return $data['access_token'];
    }
    
    private function getHeaders()
    {
        return [
            'Accept' => 'application/json',
            'Authorization' => 'Bearer ' . $this->accessToken,
            'Content-Type' => 'application/json'
        ];
    }
    
    public function getPlans()
    {        
        $response = $this->client->request('GET', '/v1/billing/plans', [
                'headers' => $this->getHeaders()
            ]
        );

        return json_decode($response->getBody(), true);
    }

    // ...
}

Aqu铆 tienes una explicaci贸n m谩s detallada de c贸mo conectarte a la API de PayPal para registrar productos y planes:

Mostrar botones de pago

Lo primero es agregar el JS SDK de PayPal.

Este es un script que puedes ubicar justo antes del cierre de tu etiqueta body:

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&vault=true&intent=subscription"></script>

En donde dice YOUR_CLIENT_ID debes agregar tu Client ID, proporcionado por PayPal.

Lo segundo es tener un div donde vamos a renderizar nuestros botones:

<div id="paypal-button-container"></div>

Este elemento lo puedes ubicar en cualquier parte de tu HTML, seg煤n creas conveniente.

Por 煤ltimo, renderizamos los botones ejecutando el siguiente script:

paypal.Buttons({
	createSubscription: function(data, actions) {
		return actions.subscription.create({
			'plan_id': 'YOUR_PLAN_ID'
		});
	},
	onApprove: function(data, actions) {
		console.log('You have successfully created subscription ' + data.subscriptionID);
	}
}).render('#paypal-button-container');

De esta manera los usuarios de nuestro sitio podr谩n suscribirse a nuestros planes.

N贸tese que debemos reemplazar el valor para plan_id en el c贸digo anterior.

A continuaci贸n puedes ver una explicaci贸n m谩s detallada sobre:

  • C贸mo renderizar los botones de pago.
  • Y as铆 mismo, c贸mo realizar una primera suscripci贸n con PayPal, usando el entorno sandbox.

M煤ltiples planes de suscripci贸n

驴Quieres permitir que tus usuarios se suscriban a un plan Mensual, pero tambi茅n a uno Anual?

Luego de definir m煤ltiples planes con PayPal, puedes mostrar los botones de pago para uno u otro.

S贸lo necesitas cambiar el "plan id" al momento de renderizar los botones de pago.

Aqu铆 tienes un ejemplo de c贸mo lograr ello en tu proyecto Laravel:

Verificar suscripci贸n exitosa

La funci贸n onApprove nos da el ID de la suscripci贸n creada v铆a PayPal.

Lo que debemos hacer entonces es pasar este ID a nuestro backend y verificar all铆 que el pago realmente se haya completado.

De ser as铆, procederemos a registrar la suscripci贸n en nuestra base de datos.

En el siguiente video podemos ver qu茅 datos debemos considerar, la ruta a definir, y la forma de validaci贸n:

Actualizar vistas para usuarios suscritos

Una vez que registramos en nuestra base de datos qu茅 usuarios son premium y cu谩les no, lo siguiente es adaptar nuestras vistas, para que los usuarios suscritos a planes vean un contenido distinto a aquellos que no tienen membres铆a.

Para esto podemos modificar nuestro modelo User y definir nuevos accessors, que nos permitan consultar qu茅 usuarios son premium y cu谩les son los datos de la suscripci贸n activa que cada uno tiene.

En el siguiente video vemos c贸mo declarar una relaci贸n entre User y Suscription, y c贸mo adaptar nuestras vistas en funci贸n a los accessors isPremium y lastSubscription.

Cancelar suscripci贸n desde nuestra plataforma

Como parte del flujo b谩sico de suscripciones, debemos permitir a nuestros usuarios cancelar su suscripci贸n.

Esto significa que un usuario contar谩 con los beneficios premium hasta que termine el periodo por el cu谩l ha pagado. Pero ya no se realizar谩n m谩s pagos por la suscripci贸n.

Para esto podemos definir un m茅todo cancel en nuestro controlador.

public function cancel(PayPalClient $payPalClient)
{
    $subscription = auth()->user()->lastSubscription;
    
    if (!$subscription) {
        return back();
    }
    
    $body = [
        'reason' => 'User cancelled from the platform Settings.'
    ];        

    $statusCode = $payPalClient->cancelSubscription($subscription->paypal_subscription_id, $body);        
    
    if ($statusCode >= 200 && $statusCode < 300) {
        $subscription->cancel();
        $notification = 'Tu suscripci贸n se ha cancelado correctamente.';
    } else {
        $notification = 'Ocurri贸 un error inesperado. Por favor escribe un mensaje a [email protected] si necesitas ayuda.';
    }
                    
    return back()->with(compact('notification'));
}

脡ste m茅todo debe ir asociado a una nueva ruta, y ejecutarse cuando un usuario haga clic sobre el bot贸n "Cancelar" en su panel.

Puedes ver el siguiente cap铆tulo, donde implementamos esto paso a paso:

Cancelaciones externas

Si un usuario cancela su suscripci贸n desde nuestro sitio:

  • Nosotros simplemente actualizamos nuestra base de datos.
  • Y notificamos a PayPal de la cancelaci贸n.

Sin embargo, si un usuario cancela su suscripci贸n desde PayPal, o a trav茅s de su banco, 驴c贸mo nos enteramos de ello?

En ese caso, PayPal nos debe notificar de dicho cambio de estado, para que nosotros podamos actualizar nuestra base de datos y dejar de renovar la membres铆a premium para el usuario.

Esto es posible a trav茅s de Webhooks.

El siguiente video explica c贸mo escuchar PayPal Webhook Events y c贸mo hacer uso de PayPal Sandbox para verificar el funcionamiento de nuestra aplicaci贸n:

Subir cambios a nuestro servidor

Cada vez que hacemos cambios a nuestra estructura de base de datos, l贸gica de negocio y dependencias, tenemos que seguir un orden para publicar nuestros cambios.

Es importante:

  1. Hacer un backup de nuestra base de datos y probar que funcione, por si las cosas salen mal.
  2. Obtener cambios en el servidor v铆a Git Pull.
  3. Instalar dependencias de nuestro proyecto v铆a Composer.
  4. Ejecutar nuevas migraciones y verificar cambios.
  5. Actualizar nuestras credenciales seg煤n sea necesario.

En el siguiente video puedes ver c贸mo hacer ello, adem谩s de otras buenas pr谩cticas y recomendaciones:

Renovar suscripci贸n

Hasta el momento, nuestra tabla de suscripciones crea un registro nuevo por cada nuevo usuario que se suscribe a nuestra plataforma.

En el momento en que identificamos el inicio de una suscripci贸n, creamos el nuevo registro en nuestra base de datos.

驴Pero qu茅 ocurre al finalizar el primer mes o el primer a帽o del usuario suscrito?

  • PayPal se encargar谩 de cobrar de manera recurrente a los usuarios suscritos.

  • Sin embargo, nuestra base de datos no se actualizar谩 si nosotros no implementamos ello.

Esto 煤ltimo podemos lograrlo escuchando a eventos PayPal adicionales.

En la 煤ltima lecci贸n vemos c贸mo mejorar nuestro controlador (el que atiende PayPal Webhook Events), y c贸mo probar nuestro flujo completo de suscripci贸n:

驴Quieres aprender m谩s?

Te recomiendo continuar viendo la serie completa en YouTube, sobre c贸mo implementar un Sistema de Suscripciones con PayPal.

Si tienes alguna duda, s贸lo deja un comentario en el video correspondiente, y estar茅 encantando de ayudarte ?.

Logo de Programaci贸n y m谩s

Comparte este post si te fue de ayuda 馃檪.

Reg铆strate

Accede a todos los cursos, y resuelve todas tus dudas.

Cursos Recomendados

Imagen para el curso Laravel y Android

Laravel y Android

Curso intensivo. Incluye el desarrollo de una API, su consumo, y autenticaci贸n v铆a JWT. Tambi茅n vemos Kotlin desde 0.

Iniciar curso
Imagen para el curso Aprende Javascript

Aprende Javascript

Domina JS con este curso pr谩ctico y completo! Fundamentos, ejemplos reales, ES6+, POO, Ajax, Webpack, NPM y m谩s.

Iniciar curso
Imagen para el curso Docker y Microservicios

Docker y Microservicios

Aprende por qu茅 es importante y c贸mo funciona Docker, con este nuevo curso pr谩ctico!

Iniciar curso

Espera un momento ...

驴Te gustar铆a llevar mi curso de Laravel, gratis?

S贸lo debes ingresar tus datos: