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.

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

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.

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

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.

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.