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 ?.

Cursos recomendados

Curso intensivo de 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.

Ingresar al curso
Curso práctico de Javascript

Aprende Javascript

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

Ingresar al curso
Curso de Laravel, Vue.js y Pusher

Aprende Vue.js

Desarrollemos un Messenger! Aprende sobre Channels, Queues, Vuex, JWT, Sesiones, BootstrapVue y mucho más.

Ingresar al curso
Logo de Programación y más

¿Tienes alguna duda?

Si algo no te quedó claro o tienes alguna sugerencia, escribe un comentario aquí debajo.

Además recuerda compartir el post si te resultó de ayuda! 🙂

Cargando comentarios ...

Antes que te vayas

Inscríbete en nuestro curso gratuito de Laravel