2

I'm totally stuck trying to receive SMSs from Twilio into SF. I can send out fine. This is what I've got so far, and all it returns is an invalid_session_id error.

@RestResource(urlMapping='/textlead/*')
global with sharing class TextLeadRestfulReceiver {

    @HttpGet
    global static String init() {
        String payload = ' -d "grant_type=password"' +
            ' -d "client_id=ID"' +
            ' -d "client_secret=secret"' +
            ' -d "username=here@there.com.staging"' +
            ' -d "password=whateverTOKEN"';

        HttpRequest req = new HttpRequest();
        req.setMethod('GET');
        req.setEndpoint('https://login.salesforce.com/services/oauth2/token');
        req.setHeader('Content-Type','application/x-www-form-urlencoded');
        req.setHeader('Content-Length', String.valueOf(payload.length()));
        req.setHeader('X-PrettyPrint', '1');
        req.setBody(payload);

        Http binding = new Http();
        HttpResponse res = binding.send(req);

        System.debug(String.valueOf(res));

        return String.valueOf(res);
    }

    global static String saveText() {
        String ACCOUNT_SID = 'what';
        String AUTH_TOKEN  = 'ever';

        TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);

        RestRequest request = RestContext.request;
        request.addHeader('Authorization', 'Bearer');
        String body         = 'Nada.';
        String leadNumber   = request.requestURI.substring(request.requestURI.lastIndexOf('/') + 1);
        List<Lead> result   = [SELECT Id, FirstName, MobilePhone
                               FROM Lead WHERE MobilePhone=:leadNumber];

        for (TwilioMessage message: client.getAccount().getMessages().getPageData()) {
            body = message.getBody();
        }

        for (Lead l: result) {
            Task task = new Task(WhoId = l.Id, OwnerId = l.OwnerId, Description = body, ActivityDate = Date.today(),
                                 Subject = 'Text received from ' + l.FirstName + ' on ' + leadNumber);
            insert task;
        }
        return body;
    }
}

A curl command to the endpoint returns this:

curl

The Twilio/Salesforce docs don't help with authorization at all: To receive a message, they say only this:

String ACCOUNT_SID = 'AXXXXXXXXXXXXXXXXX';
String AUTH_TOKEN = 'YYYYYYYYYYYYYYYYYY';
TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);

for (TwilioSms message : client.getAccount().getSmsMessages().getPageData()) {
    System.debug(message.getBody());
}

Can someone point me in the right direction?

Update

I've got a connection working okay, but I still can't send from Twilio to Salesforce.

@RestResource(urlMapping = '/textlead/')
global with sharing class TextLeadReceiver {

    @HttpGet
    global static String TextLeadReceiver() {
        RestRequest req         = RestContext.request;
        RestResponse res        = RestContext.response;
        String ACCOUNT_SID      = 'what';
        String AUTH_TOKEN       = 'ever';
        TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);

        String subject = 'Text received from {0} on {1}';
        String phone   = 'No phone';
        String body    = 'Nada.';

        req.addHeader('Accept', 'application/json');

        try {
            for (TwilioMessage message: client.getAccount().getMessages().getPageData()) {
                body  = message.getBody();
                phone = message.getFrom();
                System.debug('SMS body: ' + body);
                System.debug('SMS phone: ' + phone);
            }

            List<Lead> leads  = [SELECT Id, FirstName, MobilePhone, Phone, Phone_2__c
                                 FROM Lead WHERE MobilePhone = :phone
                                 OR Phone = :phone OR Phone_2__c = :phone];

            for (Lead l: leads) {
                List<String> args = new List<String>(new String[] { l.FirstName, phone });
                String newSubject = String.format(subject, args);
                Task task = new Task(WhoId = l.Id, OwnerId = l.OwnerId, Description = body,
                                     ActivityDate = Date.today(), Subject = newSubject);
                insert task;
            }
            System.debug('SMS saved: ' + body);

        } catch(System.CalloutException e) {
            System.debug('SMS error: ' + e);
        }
        return body;
    }
}

This gives me a 401 error in Twilio, which makes sense because I haven't authorized anything. No idea how to authorize the call though.

  • This error is related to your code calling Salesforce API (saveText) method, looks like you have hardcoded the session id there. Can you post your code snippet consuming SF api? – Salesforcesmarty Jan 25 '16 at 5:01
  • I've updated my question with some progress I've made. Still stuck on auth though. – okay56k Jan 25 '16 at 5:03
  • How are you making API calls to SF? Some code or Twilio provides UI interfaces and takes care of the callouts? – Salesforcesmarty Jan 25 '16 at 6:00
  • Twilio can be set to hit URLs on events, so I'm just pointing it to whatever.salesforce.com/services/apexrest/textlead/. – okay56k Jan 25 '16 at 6:03
  • Is this API has to be authenticated? I can suggest a workaround to make them public APIs. – Salesforcesmarty Jan 25 '16 at 6:06
2

Steps to setup a public facing API

  1. Goto sites and setup a public site https://help.salesforce.com/HTViewHelpDoc?id=sites_setup_overview.htm&language=en_US

  2. Create a sample vf page and add the webservice class as controller to this page.

    <apex:page controller="Whatever" action="{!actionName}" />

This action will execute when page loads.

Convert

 @RestResource(urlMapping = '/textlead/')
    global with sharing class TextLeadReceiver {

@HttpGet
    global static String TextLeadReceiver() {

to

Public with sharing class TextLeadReceiver {

    Public String TextLeadReceiver() {

And just make it a simple apex method.

3.Make this sample page as the Home page for site

4.Update your endpoint URL in your application from ".salesforce.com/services/apexrest/textlead/" to "siteaddress/{pageName}?parameters"

5.Consume the parameters in the method and do whatever you want to do.

ApexPages.currentPage().getParameters().get('paramName');

6.Make sure your Public access settings has access to object you want to modify or use without sharing keyword in your class definition.

Public access setting : https://help.salesforce.com/HTViewHelpDoc?id=sites_public_access_settings.htm&language=en_US

Note: I am assuming you know a bit of SF :)

  • The VF page should be like this, yeah? <apex:page standardController="Lead" extensions="TextLeadReceiver"></apex:page>? – okay56k Jan 25 '16 at 6:54
  • 1
    You wont be able to perform DMLs in your controllers. Let me verify the above answer. – Salesforcesmarty Jan 25 '16 at 6:55
  • So, after researching it, this method may not work because logins aren't able to be turned on: help.salesforce.com/apex/… Is there another solution? – okay56k Jan 25 '16 at 9:10
  • 1
    Just update your class with "Public without sharing class TextLeadReceiver" this and you won't need anything. – Salesforcesmarty Jan 25 '16 at 11:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.