This post is a tutorial on how to create a slack bot for PayPal.

Requirements


Whenever a transaction is received by a PayPal account, a slack message should be sent to a specific channel. The message should contain all the details of the transaction.

Design and Implementation


Lets get started by breaking the requirements into smaller tasks that we can handle independently.

NODEJS SERVER

We need to receive PayPal notifications - so we will need a server. We will implement this in NodeJS.

REACTJS CLIENT

We need to allow the user to Login and configure/retreive the URL where PayPal should send notifications. We will implement this frontend in React.

SLACK BOT

The PayPal notifications should be sent to Slack. We will create a slack bot using the app/bot creation facilities provided by Slack.


Implementation


Slack Bot


Lets get started with the process of creating a slack bot.

Create a slack bot


First navigate to https://ledbulb.slack.com/apps and make sure that the name you want for your bot/app is available. Next, click on Build and then choose Start Building. Replace ledbulb with your slack workspace.

This should show you a popup asking for the app name and the development workspace. Here, I have entered the name as Money-Dev because I have already created an app called Money which I will use for Production purposes.

Create a Slack App
Create a Slack App

Next, you should see the Add features and functionality section.

Features and Functionality of a slack app
Features and Functionality of a slack app

Incoming Webhooks


Click on Incoming Webhooks and activate it. Incoming webhooks are required to send messages to Slack from our NodeJS server. We need the webhooks because the messages are sent without direct user interaction.

Incoming Webhooks
Incoming Webhooks


Later on we will enable Event subscriptions as well. We cannot do it right now because it requires our nodejs server to be up and running. As soon as we enable Event Subscriptions, slack will send a challenge to our server to verify that we have entered the right URL.

Now, if you scroll down to the section on App Credentials, you should see various fields such as Client ID, Client Secret, etc. We need these values later.

Display Information


Feel free to scroll down and configure Display Information. This can be done now or later when you want to push your app to the app store.

Features


In the left sidebar, you should see various links. Click on each of them and learn what they do. We will look at the most important one here - OAuth and Permissions.

OAuth and Permissions.


Whenever the App is installed, Slack will ask permission from the user to share their credentials(a token) with you - the app.

OAuth is the authorization protocol using which Slack shares the token with you.

When it comes to Permissions, Slack will tell the user the permissions your app is requesting - such as webhooks, identity, etc. This is  to inform the user about the data that your app is requesting. Only if the user grants permission, you will receive the token from slack.

Here are the steps involved in exchanging the token.

  • Whenever the App is installed from the Slack App Store or by using a Add To Slack button, Slack will pass a variable called code (This is not the token). The code will be passed in the URL to your app. So that means that we should tell Slack to which URL the code should be passed.
    We will ask Slack to pass it to this path /api/oauth/redirect-add-to-slack. So that means our endpoints during development and production will be different.

My development endpoint is http://localhost:3000/api/oauth/redirect-add-to-slack

My production endpoint is https://www.pagemonk.com/api/oauth/redirect-add-to-slack

Enter both these URLs in Redirect URLs section under `OAuth and Permissions`.

OAuth and Permissions for the Slack App
OAuth and Permissions for the Slack App

My Scopes section currently has only one scope. We can add more later on if required. But remember, adding a scope after app is installed will require user to reinstall the app.

Scopes for the Slack App
Scopes for the Slack App

Nodejs - Express server


Now in your express server, add a route for processing OAuth redirects from Slack.

app.post('/api/oauth/redirect-add-to-slack', 	          slackController.oauthRedirectAddToSlack);


And in your slackController's oauthRedirectAddToSlack method, we will exchange the code parameter for a token.

First, create the slack URL with the required parameters. Slack client_id, client_secret are available in your app dashboard. SLACK_REDIRECT_URI_SIGNIN_WITH_SLACK is the redirect URL in your OAuth settings. Based on your environment, you should use your localhost URL or the production URL.

var requestOptions = {
    uri: 'https://slack.com/api/oauth.access'+
      '?code='+req.query.code+
      '&client_id='+process.env.SLACK_CLIENT_ID+
      '&client_secret='+process.env.SLACK_CLIENT_SECRET+
      '&redirect_uri='+process.env.SLACK_REDIRECT_URI_SIGNIN_WITH_SLACK,
    method: 'GET'
}


Next, make the request to slack

const response = await request(requestOptions);


If this request is successful, slack will exchange the code param for  a json response.  The response looks like this:

{
    "ok" : true,
    "access_token" : "xoxp-2323343-23412312-123123123-02b9a9079",
    "scope" : "identify,incoming-webhook",
    "user_id" : "U344IOOI4",
    "team_id" : "T34UI4KOI",
    "enterprise_id" : null,
    "team_name" : "SlackWorkspace",
    "incoming_webhook" : {
        "channel" : "#slair-channel",
        "channel_id" : "CBDEE32ZF",
        "configuration_url" : "https://slackworkspace.slack.com/services/FG45WE876",
        "url" : "https://hooks.slack.com/services/T34UI4KOI/U344IOOI4/eheyre3783jsdusihww22"
     },
}

This payload contains the access_token, scope, information about the channel and team and details about incoming_webhook. In this project, we will be using only(I think) the incoming_webhook details to send IPN to slack.

Ok, until now that we have figured out how to create the slack bot and do the OAuth protocol for exchanging tokens.

Next, we will see how to receive IPN and save it to the database.

IPN


To receive IPN from PayPal, we need to know the URL where the notification should be sent to.

The URL should be specific to every user who installs the slack app. So, soon after doing the OAuth token exchange, we will create an IPN Url and save it to our database.

It is easy to create a URL. We will use shortid to generate unique IDs.

const shortid = require('shortid');ipnUrl: shortid.generate()


Next, in express we will add a route for the IPNs.

app.post('/api/ipn-listener/:ipnUrl', ipnController.syncIpnListener)


In syncIpnListener, we will verify that the IPN is coming from PayPal and then find the user to whom this IPN belongs to. To test IPN, we can use PayPal's excellent support for sandbox. There they have a IPN testing tool and you can send IPN any number of times until you are sure you have fixed all the bugs.

A sample IPN looks like this

{
    "payment_type" : "instant",
    "payment_date" : "15:59:42 Nov 08, 2019 PST",
    "payment_status" : "Pending",
    "address_status" : "confirmed",
    "payer_status" : "verified",
    "first_name" : "John",
    "last_name" : "Smith",
    "payer_email" : "buyer@paypalsandbox.com",
    "payer_id" : "TESTBUYERID01",
    "address_name" : "John Smith",
    "address_country" : "United States",
    "address_country_code" : "US",
    "address_zip" : "95131"
    ,"address_state" : "CA",
    "address_city" : "San Jose",
    "address_street" : "123 any street",
    "business" : "seller@paypalsandbox.com",
    "receiver_email" : "seller@paypalsandbox.com",
    "receiver_id" : "seller@paypalsandbox.com",
    "residence_country" : "US",
    "item_name" : "something",
    "item_number" : "AK-1234",
    "quantity" : "1",
    "shipping" : "3.04",
    "tax" : "2.02","mc_currency" : "USD","mc_fee" : "0.44",
    "mc_gross" : "12.34",
    "mc_gross_1" : "9.34",
    "txn_type" : "web_accept",
    "txn_id" : "849785180",
    "notify_version" : "2.1",
    "custom" : "xyz123",
    "invoice" : "abc1234",
    "test_ipn" : "1",
    "verify_sign" : "PCWWMGR9KncUDME5psh8RAh7Uq"
}


Next we need to get the url to send the message to slack. This url is oauth_payload.incoming_webhook.url. If we POST a message to this endpoint, it will go to the slack channel that the user configured while installing the app.

Send slack message
The PayPal IPN has many fields. For now, we will send all of them to slack. To send this message, we need to format it in a specific way. You can use slack's Block Kit builder available at https://api.slack.com/tools/block-kit-builder for building and testing sample messages.

Basically, the message will look like this. The first section is the title and the second section has the keys and values. There are limitations on the length of the fields array. So, we had to split the section into multiple smaller ones.

{
  blocks: [
      {
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: 'You have a new IPN'
        }
      },
    {
      type: "section",
      fields: [{// All the keys and values go here
          type: 'mrkdwn',
	      text: *${key}*\n${ipn[key]}
        },
        {
          type: 'mrkdwn',
          text: *${key}*\n${ipn[key]
        }
      },
      {
        type: 'mrkdwn',
        text: *${key}*\n${ipn[key]
      }
    },
  ..... .. ..

Hope you got some understanding of how the slack bot ecosystem works. If you would like to see and install the Money bot, search for Money in the slack app store (https://slack.com/apps) or go to https://www.pagemonk.com and select Add to Slack from there.

If you have any questions, or if you would like to talk to me about building slack apps, feel free to contact me at my email thepagemonk [at] gmail [dot] com.