├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── heroku ├── README.md └── index.js ├── hubot ├── README.md └── graph-api-webhooks.coffee └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Node build artifacts 2 | node_modules 3 | npm-debug.log 4 | 5 | # Local development 6 | *.env 7 | *.dev 8 | .DS_Store 9 | 10 | # Docker 11 | Dockerfile 12 | docker-compose.yml 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `graph-api-webhooks-samples` 2 | We want to make contributing to this project as easy and transparent as 3 | possible. 4 | 5 | ## Pull Requests 6 | We actively welcome your pull requests. 7 | 8 | 1. Fork the repo and create your branch from `master`. 9 | 1. If you've changed APIs, update the documentation. 10 | 1. If you haven't already, complete the Contributor License Agreement ("CLA"). 11 | 12 | ## Contributor License Agreement ("CLA") 13 | In order to accept your pull request, we need you to submit a CLA. You only need 14 | to do this once to work on any of Facebook's open source projects. 15 | 16 | Complete your CLA here: 17 | 18 | ## Issues 19 | We use GitHub issues to track public bugs. Please ensure your description is 20 | clear and has sufficient instructions to be able to reproduce the issue. 21 | 22 | Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe 23 | disclosure of security bugs. In those cases, please go through the process 24 | outlined on that page and do not file a public issue. 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-present, Facebook, Inc. All rights reserved. 2 | 3 | You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4 | copy, modify, and distribute this software in source code or binary form for use 5 | in connection with the web services and APIs provided by Facebook. 6 | 7 | As with any software that integrates with the Facebook platform, your use of 8 | this software is subject to the Facebook Developer Principles and Policies 9 | [http://developers.facebook.com/policy/]. This copyright notice shall be 10 | included in all copies or substantial portions of the software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 14 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 16 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node heroku/index.js 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Graph API Webhooks Samples 2 | 3 | These are sample clients for Facebook's [Webhooks](https://developers.facebook.com/docs/graph-api/webhooks/) product, Instagram's [Subscriptions API](https://www.instagram.com/developer/subscriptions/), and Threads' [Webhooks](https://developers.facebook.com/docs/threads/webhooks). 4 | 5 | 1. [Heroku](heroku) - A sample client that receives Webhook events. 6 | 1. [Hubot](hubot) - A script that messages a chat room when a Facebook Page post is published using Webhooks. 7 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Graph API Webhooks Sample", 3 | "repository": "https://github.com/fbsamples/graph-api-webhooks-samples" 4 | } 5 | -------------------------------------------------------------------------------- /heroku/README.md: -------------------------------------------------------------------------------- 1 | # Graph API Webhooks Heroku Sample 2 | 3 | This is a sample client for Facebook's [Webhooks](https://developers.facebook.com/docs/graph-api/webhooks/) product and Instagram's [Subscriptions API](https://www.instagram.com/developer/subscriptions/), powered by [Node.js on Heroku](https://devcenter.heroku.com/articles/getting-started-with-nodejs). 4 | 5 | ## Setup 6 | 7 | ### Facebook Webhooks 8 | 9 | 1. Refer to Facebook's [Webhooks sample app documentation](https://developers.facebook.com/docs/graph-api/webhooks/sample-apps) to see how to use this app. 10 | 1. Deploy the sample app on Heroku with this button: 11 | 12 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://www.github.com/fbsamples/graph-api-webhooks-samples) 13 | 14 | ### Instagram Subscription API 15 | 1. Register an [Instagram API client](https://instagram.com/developer/clients/manage/). 16 | 1. Deploy the sample app on Heroku with this button: 17 | 18 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/fbsamples/graph-api-webhooks-samples/) 19 | 20 | 1. Set up your client's [subscription](https://www.instagram.com/developer/subscriptions/) using your `https://.herokuapp.com/instagram` as the callback URL. It is recommended that you set a `TOKEN` [config var](https://devcenter.heroku.com/articles/config-vars) as part of the set up of your Heroku app to secure requests. If you choose not to set a config var, then you will need to set a verify token of 'token' when configuring the callback URL. 21 | 22 | ### Threads Webhooks 23 | 1. Deploy the sample app on Heroku with this button: 24 | 25 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/fbsamples/graph-api-webhooks-samples/) 26 | 27 | 1. Refer to [Threads' Webhooks Documentation](https://developers.facebook.com/docs/threads/webhooks) and set up Threads Webhooks product as a sub use case under the Threads API main use case. Also, set up your webhooks callback URL as `https://.herokuapp.com/threads`. It is recommended that you set a `TOKEN` [config var](https://devcenter.heroku.com/articles/config-vars) as part of the set up of your Heroku app to secure requests. If you choose not to set a config var, then you will need to set a verify token of 'token' when configuring the callback URL. 28 | -------------------------------------------------------------------------------- /heroku/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | */ 8 | 9 | var bodyParser = require('body-parser'); 10 | var express = require('express'); 11 | var app = express(); 12 | var xhub = require('express-x-hub'); 13 | 14 | app.set('port', (process.env.PORT || 5000)); 15 | app.listen(app.get('port')); 16 | 17 | app.use(xhub({ algorithm: 'sha1', secret: process.env.APP_SECRET })); 18 | app.use(bodyParser.json()); 19 | 20 | var token = process.env.TOKEN || 'token'; 21 | var received_updates = []; 22 | 23 | app.get('/', function(req, res) { 24 | console.log(req); 25 | res.send('
' + JSON.stringify(received_updates, null, 2) + '
'); 26 | }); 27 | 28 | app.get(['/facebook', '/instagram', '/threads'], function(req, res) { 29 | if ( 30 | req.query['hub.mode'] == 'subscribe' && 31 | req.query['hub.verify_token'] == token 32 | ) { 33 | res.send(req.query['hub.challenge']); 34 | } else { 35 | res.sendStatus(400); 36 | } 37 | }); 38 | 39 | app.post('/facebook', function(req, res) { 40 | console.log('Facebook request body:', req.body); 41 | 42 | if (!req.isXHubValid()) { 43 | console.log('Warning - request header X-Hub-Signature not present or invalid'); 44 | res.sendStatus(401); 45 | return; 46 | } 47 | 48 | console.log('request header X-Hub-Signature validated'); 49 | // Process the Facebook updates here 50 | received_updates.unshift(req.body); 51 | res.sendStatus(200); 52 | }); 53 | 54 | app.post('/instagram', function(req, res) { 55 | console.log('Instagram request body:'); 56 | console.log(req.body); 57 | // Process the Instagram updates here 58 | received_updates.unshift(req.body); 59 | res.sendStatus(200); 60 | }); 61 | 62 | app.post('/threads', function(req, res) { 63 | console.log('Threads request body:'); 64 | console.log(req.body); 65 | // Process the Threads updates here 66 | received_updates.unshift(req.body); 67 | res.sendStatus(200); 68 | }); 69 | 70 | app.listen(); 71 | -------------------------------------------------------------------------------- /hubot/README.md: -------------------------------------------------------------------------------- 1 | # Graph API Webhooks Hubot Sample 2 | 3 | This example is a [Hubot](https://hubot.github.com/) script that messages a chat room when a Facebook Page post is published using Facebook's [Graph API Webhooks](https://developers.facebook.com/docs/graph-api/webhooks/). The message includes a link to the Facebook post. The bot will post another message with the number of likes on the post after a configurable number of minutes. 4 | 5 | These instructions assume you have already set up [Hubot on Heroku](https://hubot.github.com/docs/deploying/heroku/) or Hubot on another platform. 6 | 7 | ## Setup 8 | 9 | 1. Download `graph-api-webhooks.coffee`. 10 | 1. Add a line to `hubot-scripts.json` with `graph-api-webhooks`. 11 | 1. Create a new [Facebook application](https://developers.facebook.com/apps) and/or register an [Instagram API client](https://instagram.com/developer/clients/manage/). 12 | 1. Using `token` as the verify_token, set up your Facebook application's [Graph API Webhooks subscription](https://developers.facebook.com/docs/graph-api/webhooks/#setup) using `https://.herokuapp.com/facebook` as the callback URL, and/or your Instagram client's [subscription](https://www.instagram.com/developer/subscriptions/) using your `https://.herokuapp.com/instagram` as the callback URL. 13 | 1. Set the Heroku configuration values defined at the top of `graph-api-webhooks.coffee` before deploying. 14 | - `FACEBOOK_APP_ACCESS_TOKEN` - [access token](https://developers.facebook.com/docs/facebook-login/access-tokens#apptokens) for your Facebook app 15 | - `REAL_TIME_ROOM` - chat room for Hubot to post in 16 | - `WAIT_MINUTES` - number of minutes to wait before retrieving the number of likes on the post 17 | 1. Install the Facebook app on your Facebook Page using the [Page subscribed apps endpoint](https://developers.facebook.com/docs/graph-api/reference/page/subscribed_apps). 18 | -------------------------------------------------------------------------------- /hubot/graph-api-webhooks.coffee: -------------------------------------------------------------------------------- 1 | # Description: 2 | # Copyright 2015-present, Facebook, Inc. 3 | # All rights reserved. 4 | # 5 | # This source code is licensed under the license found in the 6 | # LICENSE file in the root directory of this source tree. 7 | # 8 | # Router for Facebook's Graph API Webhooks and Instagram's Real-time Photo Updates. 9 | # 10 | # Configuration: 11 | # FACEBOOK_APP_ACCESS_TOKEN 12 | # REAL_TIME_ROOM 13 | # WAIT_MINUTES 14 | # 15 | # Notes: 16 | # Set up your updates as descried here: https://developers.facebook.com/docs/graph-api/webhooks/ 17 | # And here: https://www.instagram.com/developer/subscriptions/ 18 | # 19 | # The `verify_token` is "token". 20 | # 21 | # Author: 22 | # adamgross42 23 | 24 | module.exports = (robot) -> 25 | 26 | robot.router.get ['/facebook', '/instagram'], (req, res) -> 27 | if req.param('hub.mode') == 'subscribe' and req.param('hub.verify_token') == 'token' 28 | res.send req.param('hub.challenge') 29 | else 30 | res.send 400 31 | 32 | robot.router.post '/facebook', (req, res) -> 33 | if req.body.entry[0].changes[0].value.verb == 'add' and req.body.entry[0].changes[0].value.item == 'status' 34 | res.send 200 35 | pageId = req.body.entry[0].id 36 | postId = req.body.entry[0].changes[0].value.post_id 37 | robot.http("https://graph.facebook.com/#{pageId}?access_token=" + process.env.FACEBOOK_APP_ACCESS_TOKEN) 38 | .header('Accept', 'application/json') 39 | .get() (err, res, body) -> 40 | body = JSON.parse body 41 | robot.messageRoom "#{process.env.REAL_TIME_ROOM}", "New post on #{body.name} Page: https://www.facebook.com/#{postId.split('_')[1]}." 42 | # Wait some time before pulling post stats 43 | setTimeout () -> 44 | robot.http("https://graph.facebook.com/#{postId.split('_')[1]}/likes?summary=true&access_token=" + process.env.FACEBOOK_APP_ACCESS_TOKEN) 45 | .header('Accept', 'application/json') 46 | .get() (err, res, body) -> 47 | body = JSON.parse body 48 | if body.summary 49 | likes = body.summary.total_count 50 | else 51 | likes = 0 52 | robot.messageRoom "#{process.env.REAL_TIME_ROOM}", "After #{process.env.WAIT_MINUTES} minutes, the Facebook post https://www.facebook.com/#{postId.split('_')[1]} has #{likes} likes." 53 | , process.env.WAIT_MINUTES * 60000 54 | 55 | robot.router.post '/instagram', (req, res) -> 56 | robot.messageRoom "#{process.env.REAL_TIME_ROOM}", "New post on Instagram." 57 | res.send 200 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graph-api-webhooks-samples", 3 | "version": "0.1.1", 4 | "description": "Graph API Webhooks Sample", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node heroku/index.js" 8 | }, 9 | "dependencies": { 10 | "body-parser": "~1.20.3", 11 | "express": "~4.13.3", 12 | "express-x-hub": "^1.0.4" 13 | }, 14 | "engines": { 15 | "node": "0.12.7" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/fbsamples/graph-api-webhooks-samples" 20 | }, 21 | "keywords": [ 22 | "node", 23 | "heroku", 24 | "express", 25 | "graph api" 26 | ], 27 | "license": "https://github.com/fbsamples/graph-api-webhooks-samples/blob/master/LICENSE", 28 | "bugs": "https://github.com/fbsamples/graph-api-webhooks-samples/issues" 29 | } 30 | --------------------------------------------------------------------------------