Send SMS from Zoho Creator with the GoTo Connect API and Deluge

Send Text Messages from Zoho Creator with GoTo Connect (formerly LogMeIn Jive)

Two functions send a text message from inside a Zoho Creator app through GoTo Connect: one keeps an OAuth access token fresh, the other sends the message. Wire the second to a button and your users can text a contact without leaving the record.

Updated for the GoTo rebrand. LogMeIn became GoTo and Jive became GoTo Connect, so the messaging host moved — the original posted to api.jive.com/messaging/v1/messages, and the documented endpoint is now api.goto.com/messaging/v1/messages. The old host still answers, but it is undocumented legacy infrastructure with no published shutdown date; do not build on it. The auth host is unchanged and still correct at authentication.logmeininc.com, which is counterintuitive but confirmed against GoTo’s current docs. The request body shape did not change. Both functions have also been moved off the legacy postUrl() onto invokeurl.

Before you start

  • A GoTo developer app with the messaging.v1.send scope and an initial refresh token. Start at the GoTo Developer Center.
  • A single-record form GOTO_Token with Access_Token and Refresh_Token (both multi line). Seed Refresh_Token by hand the first time.
  • A form holding your users and their sending numbers — Care_Coordinators with Work_Email and Work_Phone in this example.

Function 1 — get an access token

string GOTO.getAccessToken()
{
    CLIENT_ID     = "YOUR_GOTO_CLIENT_ID";
    CLIENT_SECRET = "YOUR_GOTO_CLIENT_SECRET";

    stored = GOTO_Token[ID != null] sort by Added_Time desc range from 0 to 1;

    headerMap = Map();
    headerMap.put("Authorization","Basic " + zoho.encryption.base64Encode(CLIENT_ID + ":" + CLIENT_SECRET));
    headerMap.put("Content-Type","application/x-www-form-urlencoded");

    bodyMap = Map();
    bodyMap.put("grant_type","refresh_token");
    bodyMap.put("refresh_token",stored.Refresh_Token);

    response = invokeurl
    [
        url    : "https://authentication.logmeininc.com/oauth/token"
        type   : POST
        parameters : bodyMap
        headers: headerMap
    ];

    accessToken  = response.getJSON("access_token");
    refreshToken = response.getJSON("refresh_token");

    if(accessToken == null || accessToken == "")
    {
        info "GoTo auth failed: " + response.toString();
        return "";
    }

    stored.Access_Token = accessToken;
    // GoTo rotates the refresh token. Persist it or the integration dies at day 30.
    if(refreshToken != null && refreshToken != "")
    {
        stored.Refresh_Token = refreshToken;
    }
    return accessToken;
}

Function 2 — send the message

void GOTO.sendSMS(string msg, string toPhone)
{
    // Sender number comes from the logged-in user's record
    getUser = Care_Coordinators[Work_Email == zoho.loginuserid];
    if(getUser.count() == 0 || getUser.Work_Phone == null || getUser.Work_Phone == "")
    {
        info "No sending number configured for " + zoho.loginuserid;
        return;
    }
    fromPhone = "+1" + getUser.Work_Phone.replaceAll("[^0-9]","");

    accessToken = thisapp.GOTO.getAccessToken();
    if(accessToken == "")
    {
        return;
    }

    headerMap = Map();
    headerMap.put("Authorization","Bearer " + accessToken);
    headerMap.put("Content-Type","application/json");

    contacts = List();
    contacts.add(toPhone);

    payload = Map();
    payload.put("ownerPhoneNumber",fromPhone);
    payload.put("contactPhoneNumbers",contacts);
    payload.put("body",msg);

    response = invokeurl
    [
        url    : "https://api.goto.com/messaging/v1/messages"
        type   : POST
        parameters : payload.toString()
        headers: headerMap
    ];

    info "GoTo SMS response: " + response.toString();
}

The 30-day trap. GoTo refresh tokens expire after 30 days and rotate — a new one comes back in the response and the old one stops working. If you do not write the new value back, everything runs perfectly for a month and then fails silently. That write-back is the stored.Refresh_Token = refreshToken line, and it is the single most important line in the first function.

Wiring it to a button

Open a stateless form from a report button so the user can compose the message:

void Open.txtMessage(int recordId)
{
    openUrl("#Form:TXT_MSG?LID=" + recordId,"popup window");
}

The stateless form collects the message body and calls thisapp.GOTO.sendSMS(input.Message, input.To_Phone); on submit.

Notes

  • E.164 or nothing. Both numbers must be +1XXXXXXXXXX. The replaceAll("[^0-9]","") strips whatever formatting your users typed.
  • The sending number must belong to your GoTo account and be SMS-enabled. A number that is voice-only will authenticate fine and then fail at send.
  • US carriers require 10DLC registration for application-to-person messaging. Unregistered traffic gets filtered, often without an error you can see.

This script is part of the free Creator Scripts Deluge Library.

All 39 Deluge scripts, the full Zoho Creator course, and every downloadable asset are now free. Get free access →