Add person-to-bot payments

To enable a payer to make a direct payment to your bot:

1. To receive pay messages, listen for pay messages.
2. To start payment processing, create an interactive callback.
3. To enable the payer to approve or cancel the payment, create an approval endpoint and a cancellation endpoint.

Listen for pay messages

Set up a controller to listen for pay messages to your bot:

/****************************************************************
* If a payer makes a direct payment, provide confirmation 
* before pushing to callback for processing
****************************************************************/
controller.hears('pay', 'direct_message', function(bot, message) {
  bot.reply(message, {
    attachments:[{
      title: 'Would you like to pay for this service?',
      callback_id: '111',
      attachment_type: 'default',
      actions: [{
        name: 'yes',
        text: 'Yes',
        value: 'yes',
        type: 'button',
      },{
        name: 'no',
        text: 'No',
        value: 'no',
        type: 'button',
      }]
    }]
  });
});

The controller hears method prompts the payer with an interactive button so that they can confirm the payment.

The bot replies with yes and no buttons.

Create an interactive callback

After the payer clicks yes or no, handle that activity through the interactive message callback. For no, simply cancel the payment. For yes, create a link to redirect the payer to PayPal to begin payment.

/****************************************************************
* After the payer agrees to the payment or agreement, handle 
* all payment requests in the callback
****************************************************************/
controller.on('interactive_message_callback', function(bot, message) {
  // For no, cancel. Otherwise, process payment.
  if (message.actions[0].value === 'no') {
    bot.replyInteractive(message, 'Payment process cancelled');
  } else {
    bot.replyInteractive(message, 'Generating your payment link. Hold on a moment...');
    
    // Prepare base payment message for bot to respond with
    var reply = {
      attachments: [{
        fallback: 'Payment initiation information failed to load',
        color: '#36a64f',
        pretext: 'Click the link below to initiate payment',
        title: 'Make payment to COMPANY',
        footer: 'PayPal Payment Bot',
        footer_icon: 'https://s3-us-west-2.amazonaws.com/slack-files2/avatars/2016-08-17/70252203425_a7e48673014756aad9a5_96.jpg',
        ts: message.ts
      }]
    };
  
    // Build PayPal payment request
    var payReq = JSON.stringify({
      intent:'sale',
      redirect_urls: {
        return_url: redirect + '/process',
        cancel_url: redirect + '/cancel'
      },
      payer: {
        payment_method: 'paypal'
      },
      transactions: [{
        description: 'This is the payment transaction description.',
        amount: {
          total: '10',
          currency: 'USD'
        }
      }]
    });
         
    // Create payment request before PayPal redirect to approve
    paypal.payment.create(payReq, function(error, payment) {
      if (error) {
        console.error(error);
      } else {
        // Capture HATEOAS links
        var links = {};
        payment.links.forEach(function(linkObj) {
          links[linkObj.rel] = {
            href: linkObj.href,
            method: linkObj.method
          };
        })
    
        // If redirect url present, insert link into bot message and display
        if (links.hasOwnProperty('approval_url')) {
          reply.attachments[0].title_link = links['approval_url'].href;
          bot.replyInteractive(message, reply);
        } else {
          console.error('no redirect URI present');
        }
      }
    });
  }
});

After the payer clicks yes, the app:

  • Creates an immediate, interactive reply to notify the payer that processing has begun.

  • Creates the interactive reply that houses the link to PayPal because you cannot automatically redirect the payer to a web address.

  • Creates the payment request object, which includes all required payment information.

  • Calls payment.create(...) with the payment request object.

  • If the payment starts successfully, extracts the approval URL. Redirects the payer to the approval URL, adds it to the bot reply, and displays the reply to the payer.

Create an approval endpoint

After the payer confirms payment, redirect him or her to the /process endpoint in the application.

To handle this redirect, add an HTTP GET /process endpoint:

/****************************************************************
* After the payer is redirected to PayPal, process a direct 
* PayPal payment
****************************************************************/
controller.webserver.get('/process', function(req, res) {
  // Extract payment confirmation information needed to process payment
  var paymentId = req.query.paymentId;
  var payerId = { payer_id: req.query.PayerID };

  // Attempt to complete the payment for the person
  paypal.payment.execute(paymentId, payerId, function(error, payment) {
    if (error) {
      console.error(JSON.stringify(error));
    } else {
      if (payment.state == 'approved') { 
        res.send('Payment completed successfully');
      } else {
        res.send('Payment not successful');
      }
    }
  });
});

After that endpoint is triggered, extract the payment ID and payer ID that PayPal sends. Call payment.execute(...) with the variables to complete payment.

Create a cancellation endpoint

If the payer cancels the payment during the PayPal payment confirmation step, redirect the payer to the /cancel endpoint in the app.

To handle this redirect, add an HTTP GET /cancel endpoint:

/****************************************************************
* Payment incomplete: The payer canceled the PayPal payment
****************************************************************/
controller.webserver.get('/cancel', function(req, res) {
  res.send('Payment canceled');
});

This example simply displays a Payment canceled message. Your app should provide a properly handled experience.