Error with messenger webhook setup - node.js

I am using the same verify token but it's giving me error https://infinite-dusk-17985.herokuapp.com/webhook/ and neither it's responding when I m using it on messenger.
'use strict';
const express = require('express')
const bodyParser = require('body-parser')
const request = require('request')
const app = express()
app.set('port', (process.env.PORT || 5000))
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}))
// parse application/json
app.use(bodyParser.json())
// index
app.get('/', function (req, res) {
res.send('hello world i am a secret bot')
})
// for facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
res.send(req.query['hub.challenge'])
res.send('Sucess, Challenge loop crossed')
}
res.send('Error, wrong token')
})
// to post data
app.post('/webhook/', function (req, res) {
let messaging_events = req.body.entry[0].messaging
for (let i = 0; i < messaging_events.length; i++) {
let event = req.body.entry[0].messaging[i]
let sender = event.sender.id
if (event.message && event.message.text) {
let text = event.message.text
if (text === 'Generic') {
sendGenericMessage(sender)
continue
}
sendTextMessage(sender, "Text received, echo: " + text.substring(0, 200))
}
if (event.postback) {
let text = JSON.stringify(event.postback)
sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token)
continue
}
}
res.sendStatus(200)
})
const token = "EAACKS5K1KvkBAASh07gKvgk9LvjCweLqKxKti1ZBzdzArNFPYNX9ZCx9tu35NNWquJZBuZCdZBLdsZBJAPFhvKgMZBDlazgofkbZAAeE6Hgv3gOh8jRd1W42AAZBIBd7EYNJsADepcpIgSlJEH9kHrup49oT5wZBHZBItnQwwDqr96z4wZDZD"
function sendTextMessage(sender, text) {
let messageData = { text:text }
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
function sendGenericMessage(sender) {
let messageData = {
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [{
"title": "First card",
"subtitle": "Element #1 of an hscroll",
"image_url": "http://messengerdemo.parseapp.com/img/rift.png",
"buttons": [{
"type": "web_url",
"url": "https://www.messenger.com",
"title": "web url"
}, {
"type": "postback",
"title": "Postback",
"payload": "Payload for first element in a generic bubble",
}],
}, {
"title": "Second card",
"subtitle": "Element #2 of an hscroll",
"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
"buttons": [{
"type": "postback",
"title": "Postback",
"payload": "Payload for second element in a generic bubble",
}],
}]
}
}
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
// spin spin sugar
app.listen(app.get('port'), function() {
console.log('running on port', app.get('port'))
})
Any help would be highly appreciated.

Since you didn't share the error stack trace, I am not sure about the reason. But, there is an issue with your code.
For the following code snippet,
// for facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
res.send(req.query['hub.challenge'])
res.send('Sucess, Challenge loop crossed')
}
res.send('Error, wrong token')
})
You would definitely be getting Error: Can't set headers after they are sent.
So, update the code with the following.
// for facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
res.send(req.query['hub.challenge'])
console.log('Sucess, Challenge loop crossed')
} else{
res.send('Error, wrong token')
}
})

Here is a working solution:
// my_server.js
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const app = express();
app.set('port', process.env.PORT || 5000);
// parse application/json
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// spin spin sugar
app.listen(app.get('port'), function() {
console.log('running on port', app.get('port'));
});
/* for facebook verification */
app.get('/webhook', function(req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
console.log("Validating webhook");
res.status(200).send(req.query['hub.challenge']);
} else {
console.error("Verification failed. Make sure the validation tokens match.");
res.status(403).end();
}
});
Few things to take note:
When you setup the webhook at developers.facebook.com, make sure the Verification Token you provide their is exactly the same string as found in the above code (i.e. 'my_voice_is_my_password_verify_me')
If you wish to change this token, make sure you update it at both places. This is Very Important
If you deploy this code to Heroku, process.env.PORT will be your port. A hardcoded port number might not work!
You will notice app.use(bodyParser.json()); is used here. This is because Facebook sends JSON data (payload) in the request body
Note that you can't write 2 res.send() statements it will give you error as mentioned by Mukesh. Once the headers are sent it can't be modified
Finally as a best practice, you can try to run it locally using npm run start or node my_server.js and ensure it has no errors like a missing node module & etc although you won't get a success response while running it locally

Related

How to make use the Paypal Payouts API to make payments to nultiple people

I am trying to execute a PayPal Payout on a Node.Js environment, but I can't seem to wrap my head around it. The payment doesn't get made.
I think that I am not getting the parameters right, and, or maybe my code needs re-organizing.
Please help me wrap my head around it, and eventually start heading in the right direction?
Thank you all in advance.
LOCALLY ON THE CLIENT BROWSER:
<script>
paypal.Button.render({
env: 'sandbox', // Or 'production'
// Set up the payment:
// 1. Add a payment callback
payment: function(data, actions) {
// 2. Make a request to your server
return actions.request.post('/my-api/create-payment/')
.then(function(res) {
// 3. Return res.id from the response
return res.id;
});
},
// Execute the payment:
// 1. Add an onAuthorize callback
onAuthorize: function(data, actions) {
// 2. Make a request to your server
return actions.request.post('/my-api/execute-payment/', {
paymentID: data.paymentID,
payerID: data.payerID
})
.then(function(res) {
// 3. Show the buyer a confirmation message.
});
}
}, '#paypal-button');
</script>
ON THE NODE ENVIRONMENT
const path = require("path");
var express = require("express");
var cors = require("cors");
var app = express();
var request = require("request");
const port = process.env.PORT || 3000;
app.use(cors());
var bodyParser = require("body-parser");
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
app.get("/", function (req, res) {
res.sendFile(path.join(__dirname + "/index.html"));
});
/** - - - - - - - */
var requestBody = {
"sender_batch_header": {
"sender_batch_id": "Payouts_2018_100007",
"email_subject": "You have a payout!",
"email_message": "You have received a payout! Thanks for using our service!",
},
"items": [
{
"note": "Your 1$ Payout!",
"amount": {
"currency": "USD",
"value": "100.00",
},
"receiver": "john-doe#personal.example.com",
"sender_item_id": "Test_txn_1",
},
{
"note": "Your 1$ Payout!",
"amount": {
"currency": "USD",
"value": "200.00",
},
"receiver": "business.example.com",
"sender_item_id": "Test_txn_2",
},
],
};
// Add your credentials:
// Add your client ID and secret
var CLIENT = "abc-def-ZAFupw-kq6-ghi";
var SECRET = "xyz-ns0xjKT0dkbpJrkvnkMG4ZUZEHd-mnop567";
var PAYPAL_API = "https://api-m.sandbox.paypal.com";
var PAYOUTS_URL = "https://api-m.sandbox.paypal.com/v1/payments/payouts?";
// Set up the payment:
// 1. Set up a URL to handle requests from the PayPal button
app.post("/my-api/create-payment/", function (req, res) {
// 2. Call /v1/payments/payment to set up the payment
request.post(
PAYPAL_API + "/v1/payments/payment",
{
auth: {
user: CLIENT,
pass: SECRET,
},
body: {
intent: "sale",
payer: {
payment_method: "paypal",
},
transactions: [
{
amount: {
total: "300.00",
currency: "USD",
},
},
],
redirect_urls: {
return_url: "https://mighty-oasis-92039.herokuapp.com/",
cancel_url: "https://mighty-oasis-92039.herokuapp.com/",
},
},
json: true,
},
function (err, response) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
// 3. Return the payment ID to the client
res.json({
id: response.body.id,
});
}
);
});
/** START PAYOUTS */
app.post("/my-api/execute-payment/", function (req, res) {
// 2. Get the payment ID and the payer ID from the request body.
var paymentID = req.body.paymentID;
var payerID = req.body.payerID;
// 3. Call /v1/payments/payment/PAY-XXX/execute to finalize the payment.
request.post(
`${PAYOUTS_URL}paymentID`,
{
auth: {
user: CLIENT,
pass: SECRET,
},
requestBody,
},
function (err, response) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
// 4. Return a success response to the client
res.json({
status: "success",
});
}
);
});
/** END PAYOUTS */
app.listen(port, () => console.log(`listening on port ${port}!`));
The button code in your question is for checkout.js and v1/payments, both of which are deprecated integrations, and which are for receiving payments.
Your server side code is for Payouts, which is for sending payments from your own account. These are entirely separate things.
If you want buyers to be able to directly pay another account, first integrate the current version of PayPal Checkout.
Server side 'Create Order' and 'Capture Order' are documented here: https://developer.paypal.com/docs/business/checkout/server-side-api-calls/#server-side-api-calls
Pair those two routes that return JSON data with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
And in the create call, configure the payee who will receive the payment: https://developer.paypal.com/docs/checkout/integration-features/pay-another-account/

Error: Can't set headers after they are sent Ember/Nodejs

I am trying to fetch data from an API, if you see the console ,you will find that a huge chunk of JSON that is variable a2 is displayed in the console .
But I wish to do res.json(a2); to display all the json on the webpage as JSON data.
I am getting an error--
Error: Can't set headers after they are sent.
What do I do >
var express = require('express');
var app = express();
const port = 5000;
var gotit = [];
var Request = require("request");
Request.post({
"headers": {
"content-type": "application/json",
"Authorization": "34ca0e9b-ecdd-4736-a432-d87760ae0926"
},
"url": "https://www.lifeguard.insure/v1/quote",
"body": JSON.stringify({
"category": "Auto",
"zipcode": "90293",
"age": 35,
"gender": "Male",
"key": "a2bf34ab-8509-4aa6-aa9e-13ae7917e1b8"
})
}, (error, response, body) => {
if (error) {
return console.dir(error);
}
var a2 = (JSON.parse(body));
console.log(a2)
gotit = a2;
});
console.log("Gotiit")
console.log(gotit);
app.get('/api/customers', (req, res) => {
res.json(gotit);
});
app.listen(port, () => console.log("Server Started"));
It looks like your making that request when your server boots?
maybe it'll work if the request is made inside the route handler?
like,
app.get('/api/customers', (req, res) => {
var gotit = [];
// all that request code, but in here
res.json(gotit);
});

Paypal rest sdk does successful transaction but with no history of it on sandbox

I am working on this sdk for paypal here and I'm running into a bunch of errors like: "The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator, webmaster#paypal.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.
More information about this error may be available in the server error log"
when everything seems to go right, I get transferred to the /success with all the payment json back. the problem is that the console.log("payerId = " + payerId) never logs and when i log into my sandbox I have no history of any transaction even though I went though the motions of one. I get no error back so idk what I am doing wrong. THX!
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const path = require('path')
let port = 5007;
let app = express();
// const ejs = require('ejs');
const paypal = require('paypal-rest-sdk');
// const Paypal = require('./Server/Paypal_api.js')
// const Nodemailer = require('./Server/Nodemailer.js')
// app.use(express.static(path.join(__dirname, 'public')));
// app.use(express.static('assets'))
// app.use(cors())
// app.use(bodyParser.json())
paypal.configure({
'mode': 'sandbox', //sandbox or live
'client_id': 'AYoej9yvsPTO_giNMnI5pMecd4vbelcK_N',
'client_secret': 'EE8rJValbapV4Dk-g5yFFMG7pMC-bwwwv7sO'
});
client id & secret not real but you get it
app.post('/pay', (req, res) => {
const create_payment_json = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": "http://localhost:3000/success",
"cancel_url": "http://localhost:3000/cancel"
},
"transactions": [{
"item_list": {
"items": [{
"name": "Red Sox Hat",
"sku": "001",
"price": "25.00",
"currency": "USD",
"quantity": 1
}]
},
"amount": {
"currency": "USD",
"total": "25.00"
},
"description": "Hat for the best team ever"
}]
};
paypal.payment.create(create_payment_json, (error, payment) =>{
if (error) {
throw error;
} else {
// console.log(payment)
for(let i = 0;i < payment.links.length;i++){
if(payment.links[i].rel === 'approval_url'){
res.redirect(payment.links[i].href);
}
}
}
});
});
app.get('/success', (req, res) => {
const payerId = req.query.PayerID;
const paymentId = req.query.paymentId;
console.log("payerId = " + payerId)
const execute_payment_json = {
"payer_id": payerId,
"transactions": [{
"amount": {
"currency": "USD",
"total": "25.00"
}
}]
};
paypal.payment.execute(paymentId, execute_payment_json, (error, payment) =>{
if (error) {
console.log(error.response);
throw error;
} else {
console.log(JSON.stringify(payment));
res.send('Success');
}
});
});
app.get('/cancel', (req, res) => res.send('Cancelled'));
app.listen(port, () => {
console.log("resonating on port " + port)
})

Facebook Messenger Bot : Socket hang up exception while sending message back to user using nodejs?

I have taken a example fb mot from git set up the node js app and subscribed to webhooks.
Below is the code :
'use strict';
const express = require('express')
const bodyParser = require('body-parser')
const request = require('request')
const app = express()
const fs = require('fs')
const https = require('https')
app.set('port', (process.env.PORT || 5000))
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}))
// parse application/json
app.use(bodyParser.json())
// index
app.get('/', function (req, res) {
res.send('hello world i am a secret bot')
})
// for facebook verification
app.get('/webhook/', function (req, res) {
if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
res.send(req.query['hub.challenge'])
console.log("verified");
} else {
res.send('Error, wrong token')
}
})
// to post data
app.post('/webhook/', function (req, res) {
let messaging_events = req.body.entry[0].messaging
for (let i = 0; i < messaging_events.length; i++) {
let event = req.body.entry[0].messaging[i]
let sender = event.sender.id
if (event.message && event.message.text) {
let text = event.message.text
if (text === 'Generic'){
console.log("welcome to chatbot")
//sendGenericMessage(sender)
continue
}
sendTextMessage(sender, "Text received, echo: " + text.substring(0, 200))
}
if (event.postback) {
let text = JSON.stringify(event.postback)
sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token)
continue
}
}
res.send(200)
})
// recommended to inject access tokens as environmental variables, e.g.
// const token = process.env.FB_PAGE_ACCESS_TOKEN
const token = "<TOKEN>"
function sendTextMessage(sender, text) {
let messageData = { text:text }
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
function sendGenericMessage(sender) {
let messageData = {
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"elements": [{
"title": "First card",
"subtitle": "Element #1 of an hscroll",
"image_url": "http://messengerdemo.parseapp.com/img/rift.png",
"buttons": [{
"type": "web_url",
"url": "https://www.messenger.com",
"title": "web url"
}, {
"type": "postback",
"title": "Postback",
"payload": "Payload for first element in a generic bubble",
}],
}, {
"title": "Second card",
"subtitle": "Element #2 of an hscroll",
"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
"buttons": [{
"type": "postback",
"title": "Postback",
"payload": "Payload for second element in a generic bubble",
}],
}]
}
}
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
// Start server
// Webhooks must be available via SSL with a certificate signed by a valid
// certificate authority.
https.createServer({
}, app).listen(app.get('port'), function() {
console.log("Hello World.This is Airbot :)");
});
module.exports = app;
Link to github project : https://github.com/jw84/messenger-bot-tutorial
I am not not able to send the messages back to the user.
Getting the following error :
Error sending messages: { Error: socket hang up
at TLSSocket.onHangUp (_tls_wrap.js:1124:19)
at TLSSocket.g (events.js:291:16)
at emitNone (events.js:91:20)
at TLSSocket.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9) code: 'ECONNRESET' }
Appreciate help!

Firebase Cloud Messaging with Node.js server

I'm trying to send push notifications with FCM between individual devices using a node.js server and Swift 2.2 (based on Frank van Puffelen's Sending notifications between Android devices with Firebase Database and Cloud Messaging).
The notification request is successfully being handled by both Firebase Database and the Node.js server (adding request to database, fetching data from database, sending notification to topic) but I'm not getting any alert on my device.
When I launch the app, func application(application: UIApplication, didReceiveRemoteNotification) gets called and I'm able to print the notification but, compared to sending a notification through Firebase's interface, unfortunately no alert.
userInfo from Node.js notification (No Alert):
[aps: {
alert = {
title = "This should be the text";
};
}, gcm.message_id: 0:1475766502047698%d4d04c12d4d04c12]
userInfo from sending a notification through Firebase's interface (Alert works):
[gcm.notification.sound2: default, google.c.a.e: 1, aps: {
alert = This should be the text;
sound = default;
}, gcm.n.e: 1, google.c.a.c_id: ##Some Id###, google.c.a.udt: 0, gcm.message_id: 0:1475766412557820%d4d04c12d4d04c12, google.c.a.ts: ##Some Id 2##]
index.js:
var express = require('express');
var firebase = require("firebase");
var request = require('request');
var app = express();
var path = require("path");
var API_KEY = "Some Key"; // Your Firebase Cloud Server API key
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
// views is directory for all template files
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.get('/', function(request, response) {
response.render('pages/index')
});
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
firebase.initializeApp({
serviceAccount: path.resolve(__dirname, './credentials/someCredentials.json'),
databaseURL: "https://someURL.firebaseio.com"
});
ref = firebase.database().ref();
function listenForNotificationRequests() {
var requests = ref.child('notificationRequests');
requests.on('child_added', function(requestSnapshot) {
var request = requestSnapshot.val();
sendNotificationToUser(
request.username,
request.message,
function() {
requestSnapshot.ref.remove();
}
);
}, function(error) {
console.error(error);
});
};
function sendNotificationToUser(username, message, onSuccess) {
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :' application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
notification: {
title: message
},
to : '/topics/user_'+username
})
}, function(error, response, body) {
if (error) { console.error(error); }
else if (response.statusCode >= 400) {
console.error('HTTP Error: '+response.statusCode+' - '+response.statusMessage);
}
else {
onSuccess();
}
});
}
// start listening
listenForNotificationRequests();
I would really appreciate it if someone could help me out with this :)
Found the answer: I had to change the sendNotificationToUser function by replacing title to body in my notification object and set the priority to high.
function sendNotificationToUser(username, message, onSuccess) {
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :' application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
notification: {
body: message, // Send your message in 'body'
sound: 'default'
},
to : '/topics/user_'+username,
priority: 'high' // Set the priority to high
})
}, function(error, response, body) {
if (error) { console.error(error); }
else if (response.statusCode >= 400) {
console.error('HTTP Error: '+response.statusCode+' - '+response.statusMessage);
}
else {
onSuccess();
}
});
}

Resources