Accede a todos los cursos ¬°a un precio especial! ūüéÖ‚ĚĄūüéĄ

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: