Connecting fb messenger to a chat on the site
Good afternoon. I’ll start with the fact that there was a site. In which there is a chat for users. Well, as in any chat service on websites, it also has a place for managers. Which should answer customer questions on the site.
During the development of the project, it was necessary to connect fb api
so that site managers can communicate with site clients not only from the admin panel, but also from their profiles fb messenger
.
So we started working on connecting the api to the site. After reading the documentation and articles in different sites, I realized that nowhere is there a complete step-by-step instruction.
And now that I have finished this whole thing, I wanted to share my experience. And write a detailed article for this.
I will not delve into the topic of creating a chat on the site. Much has been written on this subject on the Internet.
Let’s say we have a website with a chat already created (node.js, socket.io).
Let’s divide the article into 2 parts.
1. Resources that are needed.
2. Writing code.
1. Resources that are needed.
We need an application fb
with certain rights, which we must create with a verified fb profile. To create an application, you can go to this link. After creating the application, you will be taken to the main settings. Fill in everything as it says fb
.
After that, you need to set up authorization through Facebook. We go to the section and fill in the callback url. (For local testing, you can set the domain like this https://localhost/some-url
)
And the last part of the setup is the add-on URL
-a callback for webhook
. (this is so that messenger sends us messages to this address.)
Here pay attention to Confirmation token(token). This token is generated by you, it is not an authorization token.
It is used like this.
When you ask webhook url
, fb
requests this url
with the access token you wrote there. To understand if this exists url
and it belongs to you.
To do this, first create a route on your site that will accept requests from messenger.
2. Writing code.
Let’s start writing code.
We need to login to fb
and connect our page to the application we created. After that we will get an access token(token
) for the connected page (meaning that fb
there are many access tokens, we need exactly the access token for the page)
Read more about knife authorization in documentation.
Let’s write the code for authorization. (code written in php laravel
).
public function fbAuthorize(Request $request)
{
if (!auth()->user())
return redirect()->to('/');
$user_id = $request->get('user_id');
$code = $request->get('code');
$userMess="Internal Server Error. Please connect our support";
try {
if (!empty($code)) {
$userResponse = $this->fbService->getUserAccessToken($code);
if (!empty($userResponse)) {
$pageResponse = $this->fbService->getPageToken($userResponse->access_token);
if (!empty($pageResponse)) {
$pageProfile = $this->fbService->getPageProfilePicture($pageResponse->data[0]->id, $pageResponse->data[0]->access_token);
$profileImage = !empty($pageProfile->data) ? $pageProfile->data->url : '';
$data = [
'access_token' => $pageResponse->data[0]->access_token,
'page_id' => $pageResponse->data[0]->id,
'page_name' => $pageResponse->data[0]->name,
'page_image_url' => $profileImage,
'type' => 'page'
];
$this->fbService->createOrUpdateWithAuth($data, $user_id);
$this->fbService->subscribeWebHooks($pageResponse->data[0]->id, $pageResponse->data[0]->access_token);
$userMess="You fb page connected";
}
}
}
return redirect()
->back()
->with('success', $userMess);
} catch (Exception $e) {
return redirect()
->back()
->with('error', $e->getMessage());
}
}
As you can see from the code snippet, we have a written service for requests fb api
.
Let’s first understand this part of the code, then move on to writing a service (our service just has a few ready-made methods for sending a curl request to fb
).
How does authorization work fb
.
Get request for a specific url fb
with parameters.
https://www.facebook.com/v12.0/dialog/oauth?client_id={$fbAppId}&redirect_url={$redirectUrl}&scope=pages_messaging,pages_read_engagement&state={$customParams}
Pay attention to the last parameter in url
, named state
. This is an optional parameter. fb gives you the option to add it if you need some value after redirecting authorization to your site.
After this request, fb will prompt you to connect the page to the application.
Then there is a redirect to the specified url with the code parameter.
Now let’s go through the service written for fb, which I mentioned above.
As you can see in the code, I wrote these methods above there.
1.getUserAccessToken
2.getPageAccessToken
3.subscribeWebhooks
Fb api has many access tokens (token
), and in order for us to send a message to our page, we need exactly the access token for the page (with certain rights – scope
).
For this code, we have already received the code parameter from the first get
request, we need to use it to request a user access token (user access token
).
Detailed by link.
Here is the code to get the user access token. The code is written using the package guzzle http.
public function getUserAccessToken($code)
{
try {
$options = [
'headers' => [],
'query' => [
'code' => $code,
'client_id' => $this->fbAppId,
'client_secret' => $this->fbAppSecret,
'redirect_uri' => env('APP_URL') . '/api/fb-authorize'
]
];
$uri = "{$this->fbAppUrl}/oauth/access_token";
$response = $this->httpGet($uri, $options);
$response = $response->getBody()->getContents();
return json_decode($response);
} catch (Exception $e) {
return ['success' => false, 'code' => $e->getCode(), 'message' => $e->getMessage()];
}
}
There is nothing complicated here. Just send a curl request to fb api
, and get the user’s access token. Here is another example of a request from the documentation fb
to get a user token.
curl -X GET "https://graph.facebook.com/oauth/access_token
?client_id={your-app-id}
&client_secret={your-app-secret}
&grant_type=client_credentials"
Further, when we already have a user token, we need to get another page access token (user access token).
The second method is exactly for this. Here is a sample code.
public function getPageToken($userToken) {
$options = [
'headers' => [],
'query' => [
'access_token' => $userToken,
'scope' => 'pages_messaging'
]
];
$uri = $this->fbAppUrl.'/me/accounts';
$response = $this->httpGet($uri, $options);
$response = $response->getBody()->getContents();
return json_decode($response);
}
Here with help guzzle http similarly, we make a curl request and get the page token. Primary request from documentation fb.
curl -i -X GET "https://graph.facebook.com/me/accounts?access_token={user-access-token}
pay attention to curl
inquiry /me/accounts
. In the documentation you will see /{your-user-id}/accounts
. I don’t know the documentation is old or for another reason, if you make a request by fb id, you will get an error.
And the second moment, after this request fb
sends us not only a page marker(page access token
) but also id
pages. Save id
also. Next we need it.
At this stage, we have everything ready to send a message to our page.
Now we need to subscribe to message events. So that when we send a message from our messenger to the page then fb api
sent this message to us on the site at the specified name url
address (webhook url
) that we set in our application settings.
Here is the code for subscribing to message events.
public function subscribeWebHooks($pageId, $pageToken)
{
$options = [
'headers' => [],
'query' => [
'access_token' => $pageToken,
'subscribed_fields' => 'messages,messaging_optouts,messaging_payments,messaging_account_linking,messaging_feedback,messaging_postbacks,message_deliveries,messaging_pre_checkouts,messaging_referrals,message_reactions,messaging_customer_information,messaging_optins,message_reads,messaging_checkout_updates,message_echoes,messaging_handovers,inbox_labels'
]
];
$uri = $this->fbAppUrl.'/'.$pageId.'/subscribed_apps';
$response = $this->httpPost($uri, $options);
$response = $response->getBody()->getContents();
return $response;
}
As you can see from the code, we send get
endpoint request fb
/page_id/subscribed_apps
. That’s why I emphasized above that you need to save more and id
pages, not only token
.
Here documentation by subscription.
Now when we send a message from our messenger to our page, our api
will send a message to our site.
Here is an important note on the webhook url that we set in our application settings.
In the first part, I said that this endpoint should already be on your site. Because when you set the subscription url, fb
sends get
request for this url
with a confirmation token that you write in a specific location. See picture above.
That is, we need 2 endpoints with the same name ( get, post
)
The first is for checking, the second is for receiving messages from fb api
Here is the code I wrote in node.js
for this. (you can write this in any language.)
code for http
server.
const http = require("http");
const app = require("express")();
const cors = require("cors");
const bodyParser = require("body-parser");
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const server = http.createServer(app);
server.listen(port, function() {
console.log("listening port CHECK: " + port);
});
module.exports.app = app;
module.exports.server = server;
Here is the code for the endpoint itself.
const { app } = require('./config/httpServer');
app.get('/webhook', (req, res) => {
console.log('GET /webhook: ', req);
if (req.query['hub.mode'] && req.query['hub.verify_token'] === facebookHubVerifyToken) {
res.status(200).send(req.query['hub.challenge']);
} else {
res.status(403).end();
}
});
/**
* Handling all messages from Messenger (Facebook)
*/
app.post('/webhook', messangerAppController);
Now we only have to send the message itself from our site to messenger and back.
In order for us to send a message to the user messenger
we need to know him psid
. It’s unique id
each user messenger
, not fb id
. In order for us to take psid, we need something
As you can see from the code we have node
there is a controller for processing incoming messages. Let’s look at it in detail.
/**
* @param req
* @param res
* @returns {Promise<void>}
*/
const messangerAppController = async function (req, res) {
if (req.body.object !== 'page') {
res.status(400).end();
return;
}
if (!Array.isArray(req.body.entry)) {
res.status(200).end();
console.log('What is it?');
return;
}
req.body.entry.forEach((entry) => {
entry.messaging.forEach(async (event) => {
if (event.message && event.message.text) {
const sid = event.sender.id;
const message = event.message.text;
const replyId = event.message.reply_to ? event.message.reply_to.mid : false
try {
let facebook = await Facebook.findOne({ where: { psid: sid } });
if (facebook && replyId) {
const newMessage = await Message.create({
chat_id: chat.id,
from_support: user.id,
type_id: Message.TYPE_MESSAGE,
unread: 1,
content: message
});
//Здесь уже обработка кода как вам угодно.
} else {
let fb = await Facebook.connectUser(sid, message);
let fbAuth = await FbAuth.findOne({where: {id: fb.fb_auth_id}});
let fb_page_token = fbAuth && fbAuth.access_token ? fbAuth.access_token : false;
sendMessage(fb_page_token, sid, 'You successfully connected your Messenger.');
}
} catch (error) {
const errorMessage = `Error: ${error.message}`;
sendMessage(sid, errorMessage);
console.log('Messenger Webhook: ', errorMessage);
}
}
});
});
res.status(200).end();
}
module.exports = messangerAppController;
As you can see from line 20 we have taken psid
messenger user. This means that after connecting the api to the page, we need to send the first message to the page fb
what to learn from webhook psid
user messenger
, for future reference.(sending a message to messenger
) .
Let’s say we have multiple helpdesk managers on our site.
On the site, let’s create a page for connecting the messenger manager.
After clicking on the button, we will generate a unique code for it. And we say that he would send this code from his messenger to our connected page.
After submitting, we will get the psid of the given fb user. And now we can send him a message.
The same is written in the code above.
And lastly, let’s look at the code for sending the message itself (function sendMessage в коде выше
) to this user fb
.
function sendMessage(accessToken, recipient, messege="") {
request({
url: 'https://graph.facebook.com/v12.0/me/messages',
qs: {
access_token: accessToken
},
method: 'POST',
json: {
recipient: {id: recipient},
message: {text: messege}
}
}, function (error, response) {
if (error) {
console.log('Error sending message: ', error);
} else if (response.body.error) {
console.log('Error: ', response.body.error);
}
});
}
module.exports.sendMessage = sendMessage;
It seems to me that this code is clear, using the page access token we send a message to the user messenger
.
And at the end here documentation by sending messages to messenger
. For a detailed study of all the possibilities that gives us Fb Graph Api
.
OK it’s all over Now. We connected fb messenger
.
Thank you for reading.