├── .github └── workflows │ └── fossa-license-scan.yml ├── .gitignore ├── LICENSE ├── app.rb └── readme.md /.github/workflows/fossa-license-scan.yml: -------------------------------------------------------------------------------- 1 | # More information on this workflow can be found here: https://stackoverflow.com/c/intercom/questions/1270 2 | 3 | name: FOSSA License Scan 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | fossa: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | - name: Attempt build 17 | uses: intercom/attempt-build-action@main 18 | continue-on-error: true 19 | - name: Run FOSSA 20 | uses: intercom/fossa-action@main 21 | with: 22 | fossa-api-key: ${{ secrets.FOSSA_API_KEY }} 23 | fossa-event-receiver-token: ${{ secrets.FOSSA_EVENT_RECEIVER_TOKEN }} 24 | datadog-api-key: ${{ secrets.DATADOG_API_KEY }} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Bob Long 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /app.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'intercom' 3 | require 'twilio-ruby' 4 | require 'sinatra' 5 | require 'nokogiri' 6 | 7 | INTERCOM = Intercom::Client.new( 8 | app_id: ENV['INTERCOM_APP_ID'], 9 | api_key: ENV['INTERCOM_API_KEY'] 10 | ) 11 | 12 | Twilio.configure do |config| 13 | config.account_sid = ENV['TWILIO_SID'] 14 | config.auth_token = ENV['TWILIO_AUTH_TOKEN'] 15 | end 16 | 17 | TWILIO = Twilio::REST::Client.new 18 | 19 | post '/incoming_from_twilio' do 20 | from = params[:From] 21 | body = params[:Body] 22 | 23 | # Create or update the user 24 | user = INTERCOM.users.create( 25 | user_id: from 26 | ) 27 | 28 | # Start a new conversation 29 | INTERCOM.messages.create( 30 | from: { 31 | type: 'user', 32 | id: user.id 33 | }, 34 | body: body 35 | ) 36 | 37 | "ok" 38 | end 39 | 40 | post '/incoming_from_intercom' do 41 | request.body.rewind 42 | intercom_params = JSON.parse(request.body.read) 43 | 44 | # Extract the new message, and convert it to plaintext 45 | last_message_html = intercom_params['data']['item']['conversation_parts']['conversation_parts'][-1]['body'] 46 | last_message = Nokogiri::HTML(last_message_html).text 47 | 48 | # Load the user who we will SMS 49 | user = INTERCOM.users.find(id: intercom_params['data']['item']['user']['id']) 50 | 51 | # Send the response to Twilio 52 | unless last_message.strip.empty? 53 | TWILIO.messages.create( 54 | from: ENV['TWILIO_NUMBER'], 55 | to: user.user_id, 56 | body: last_message 57 | ) 58 | end 59 | "ok" 60 | end 61 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Integrating Intercom with Twilio 3 | date: 2015-10-12 15:00 +0000 4 | author: bob 5 | tags: 6 | --- 7 | 8 | Intercom's powerful [Conversations API](https://doc.intercom.io/api/#conversations) and [Webhooks](https://doc.intercom.io/api/#webhooks-and-notifications) makes it a breeze to build support and engagement workflows with other channels such as SMS. 9 | 10 | # SMS in 2015 11 | 12 | SMS (or "texts") have an extremely low barrier to entry, and yet are reported as one of the most [engaging channels for quick communication](http://thenextweb.com/future-of-communications/2015/02/09/sms-vs-push-vs-email/). Customers frequently ask us how our [Support](https://www.intercom.io/team-inbox) product can be used alongside a webservice like [Twilio](http://twilio.com/) to apply support over SMS. 13 | 14 | # A simple workflow 15 | 16 | Let's imagine a simple series of actions we want to neatly support: 17 | 18 | * Customer sends in an SMS to our helpline number 19 | * A user is automatically created in Intercom, and the phone number is stored 20 | * A new conversation is created in Intercom 21 | * Admin replies to that conversation get sent to the user over SMS 22 | 23 | Using Twilio's webhooks, we can write a handler to accomplish the first 3 steps via the Intercom API: 24 | 25 | ```ruby 26 | # Handle incoming SMS from Twilio, using a Sinatra handler: 27 | post '/incoming_from_twilio' do 28 | from = params[:From] 29 | body = params[:Body] 30 | 31 | # Create or update the user, setting user_id = phone_number 32 | user = INTERCOM.users.create(user_id: from) 33 | 34 | # Start a new conversation 35 | INTERCOM.messages.create( 36 | from: { 37 | type: 'user', 38 | id: user.id 39 | }, 40 | body: body 41 | ) 42 | 43 | "ok" 44 | end 45 | ``` 46 | 47 | Now we'll suddenly start tracking these SMS users as Intercom users, and start logging their conversations in Intercom. 48 | 49 | # Handling Admin Replies 50 | 51 | Once one of our teammates responds to the SMS via Intercom, we need to channel that response back to the end-user via Twilio. We can subscribe to the `Reply from a Teammate` and `Conversation assigned to Teammate` topics using [Intercom's webhooks](http://docs.intercom.io/integrations/webhooks), and provide another handler that does the reverse process of turning Intercom replies into SMS messages: 52 | 53 | ```ruby 54 | post '/incoming_from_intercom' do 55 | request.body.rewind 56 | intercom_params = JSON.parse(request.body.read) 57 | 58 | # Extract the new message, and convert it to plaintext 59 | last_message_html = intercom_params['data']['item']['conversation_parts']['conversation_parts'][-1]['body'] 60 | last_message = Nokogiri::HTML(last_message_html).text 61 | 62 | # Load the user who we will SMS 63 | user = INTERCOM.users.find(id: intercom_params['data']['item']['user']['id']) 64 | 65 | # Send the response to Twilio 66 | unless last_message.strip.empty? 67 | TWILIO.messages.create( 68 | from: ENV['TWILIO_NUMBER'], 69 | to: user.user_id, 70 | body: last_message 71 | ) 72 | end 73 | "ok" 74 | end 75 | ``` 76 | 77 | This constitutes a quick way to begin supporting your users over SMS. All of this code is available on [GitHub](https://github.com/intercom/intercom-twilio-demo). Please reach out if you have any questions or problems when integrating Intercom with your chosen support workflow. 78 | --------------------------------------------------------------------------------