Using Webhooks

The following steps are required to implement a webhook for GoToWebinar. The data examples are complete to show an exact example, however some strings have been modified to protect sensitive data. Modified data is in italic.

Create a developer account at GoToDev

A developer account is required to establish a development relationship with LogMeIn and the GoTo products.

At the GoTo Developer site, choose Sign-Up on the upper right menu bar.

Create a development app

A development app connects your developer account with a specific GoTo product and generates a ‘consumer key’ and ‘consumer secret’ that can be combined to create a Base64 encoded authentication string.

More detailed steps are documented at Create a Developer App.

Authenticate the Development user

Authenticating the development user creates a token that can be used to make API requests.

Use Create an Access Token to authenticate the developer. The following is an abbreviated version:

Import the Postman Collection

The Postman collection contains all the webhook calls and has the capability to retain your edits and data for future use and reference.

Import Postman collection.

Create Secret Key

The secret webhook key provides your development account with a code that can be used to validate data output. This ensures your program can validate the data received as safe.

Curl example

curl -X POST \
  https://api.getgo.com/G2W/rest/v2/webhooks/secretkey \
  -H 'Accept: application/json' \
  -H 'Authorization: OAuth oauth_token=4CVVlFAKeVaorni30Sj045qe7yOx' \
  -H 'Content-Type: application/json' 

Successful response example

{
    "value": "f1679e36-17fe-48fa-93da-44195fd9e293",
    "validFrom": "2019-03-14T18:03:58.317Z",
    "id": 63
}

Create Webhook

You can now create a webhook for a specific event in the associated GoTo product. You will use the webhookKey that is returned to activate or update the webhook. You will also use the webhookKey to subscribe users to the events.

Curl example

curl -X POST \
  https://api.getgo.com/G2W/rest/v2/webhooks \
  -H 'Authorization: OAuth oauth_token=4CVVlFAKeVaorni30Sj045qe7yOx' \
  -H 'Content-Type: application/json' \
  -d '[
    {
     "callbackUrl":"https://en1vd6q5jmpqb.x.pipedream.net",
     "eventName":"registrant.added",
     "eventVersion":"1.0.0",
     "product":"g2w"
    }
]'

Successful response example

{
    "_embedded": {
        "webhooks": [
            {
                "eventName": "registrant.added",
                "eventVersion": "1.0.0",
                "callbackUrl": "https://en1vd6q5jmpqb.x.pipedream.net",
                "product": "g2w",
                "webhookKey": "dff781bc-fake-4361-81ff-d5e9861fb0e1",
                "state": "INACTIVE",
                "createTime": "2019-03-14T18:06:30.365Z"
            }
        ]
    }
}

Activate the webhook

The webhooks are created in an inactive state. An explicit call must be sent to activate the webhook. You can switch the webhook between active and inactive at any time.

Curl example

curl -X PUT \
  https://api.getgo.com/G2W/rest/v2/webhooks \
  -H 'Authorization: OAuth oauth_token=4CVVlFAKeVaorni30Sj045qe7yOx' \
  -H 'Content-Type: application/json' \
  -d '[
    {
        "state":"ACTIVE",
        "webhookKey":"dff781bc-fake-4361-81ff-d5e9861fb0e1"
    }
]'

Successful response example

204 No Content

Review webhook status

At any time, you can use the GET webhook call to review status and other webhook details.

Curl example

curl -X GET \

  https://api.getgo.com/G2W/rest/v2/webhooks/dff781bc-fake-4361-81ff-d5e9861fb0e1 \

  -H 'Authorization: OAuth oauth_token=4CVVlFAKeVaorni30Sj045qe7yOx' \

  -H 'Content-Type: application/json' \

​Successful response example

200 OK
{
    "eventName": "registrant.added",
    "eventVersion": "1.0.0",
    "callbackUrl": "https://enih2xxhnu6.x.pipedream.net/",
    "product": "g2w",
    "webhookKey": "dff781bc-fake-4361-81ff-d5e9861fb0e1",
    "state": "ACTIVE",
    "createTime": "2019-03-14T18:06:30.365Z"
}

Authenticate application end-user

As mentioned earlier, both roles - developer and end-user - must be authenticated in the system. This step authenticates the end user.

Curl example

curl -X POST \
  https://api.getgo.com/oauth/v2/token \
  -H 'Authorization: Basic ZzgxY2t5VXpmVzVPOUd2blF5cUc5eXFHQTRyZ2hQVGE6Q2Q2NWVFVHNHNlpZVmtnSg==' \
  -H 'Content-Type: application/x-www-form-urlencoded' \

Successful response example

200 OK
{
    "access_token": "nEZGXNdZL96OkFakEIUrTvBYOdLw",
    "token_type": "Bearer",
    "refresh_token": "gilVeRVwrfakETRZEMLC1lapq6Py6rxo",
    "expires_in": 3600,
    "version": "3",
    "account_key": "5969036666643453962",
    "account_type": "",
    "email": "fakeOrganizer@jedix.com",
    "firstName": "A",
    "lastName": "Peer",
    "organizer_key": "7991800008309466634"
}

Subscribe to the webhook

Once the user is authenticated, the user can be subscribed to any events that are defined with webhooks in the system. The webhook key returned:

Curl example

curl -X POST \
  https://api.getgo.com/G2W/rest/v2/userSubscriptions \
  -H 'Authorization: OAuth oauth_token=nEZGXNdZL96OkFakEIUrTvBYOdLw' \
  -H 'Content-Type: application/json' \
  -d '[
    {
        "webhookKey": "dff781bc-fake-4361-81ff-d5e9861fb0e1",
        "userSubscriptionState": "ACTIVE"
    }
]'

Successful response example

200 OK
{
    "_embedded": {
        "userSubscriptions": [
            {
                "webhookKey": "dff781bc-fake-4361-81ff-d5e9861fb0e1",
                "callbackUrl": "https://enih2xxhnu6.x.pipedream.net/",
                "userSubscriptionState": "ACTIVE",
                "activationState": "ACTIVE",
                "userSubscriptionKey": "8e33dfee-c7b3-4f67-96ac-e3fakeb54f3f",
                "eventName": "registrant.added",
                "product": "g2w",
                "eventVersion": "1.0.0",
                "createTime": "2019-03-14T18:18:45.442Z"
            }
        ]
    }
}

Signature verification steps

Webhook infrastructure signs all the events sent to the callback URL. The signature is included in X-Webhook-Signature header. This allows external developers to validate that the event is sent by LogMeIn webhook infrastructure, not by a third party.

  1. Sample event posted to callback url
     Headers :
 
     Accept: application/json, application/*+json
     Content-Type: application/json 
     X-Webhook-SecretKey-Id: 1
     X-Webhook-Signature: OfpnJDFpdMKYS8tM8q7RxT/ynw5HDenv4NdU+vEtoGo=
     X-Webhook-Signature-Timestamp: 1554356824634
     X-Webhook-Signature-Version: 0
     Content-Length: 468

     Body :
     {
     "eventName":"registrant.joined",
     "eventVersion":"1.0.0",
     "product":"g2w",
     "eventKey":"74d38461-9db8-4e41-8f59-d99f00b82411",
     "sessionKey":15887209,
     "webinarKey":5620084814059709442,
     "firstName":"Abhinav",
     "lastName":"Gandhi",
     "email":"a@g.com",
     "timestamp":"2019-04-04T05:47:04.517Z",
     "webinarCreatorKey":710161738256079372,
     "webinarTitle":"New Webinar!!",
     "experienceType":"CLASSIC",
     "recurrenceType":"single_session",
     "registrantKey":8325357307900339981,
     "joinTime":1554356793898
      }
  1. Extract X-Webhook-Signature, X-Webhook-Signature-Timestamp.
  2. Prepare payload for signature generation. This can be done by concatenating:
    1. X-Webhook-Signature-Timestamp header value
    2. The colon character ":"
    3. Event received as string:
1554356824634:{"eventName":"registrant.joined","eventVersion":"1.0.0","product":"g2w","eventKey":"74d38461-9db8-4e41-8f59-d99f00b82411","sessionKey":15887209,"webinarKey":5620084814059709442,"firstName":"Abhinav","lastName":"Gandhi","email":"a@g.com","timestamp":"2019-04-04T05:47:04.517Z","webinarCreatorKey":710161738256079372,"webinarTitle":"New Webinar!!","experienceType":"CLASSIC","recurrenceType":"single_session","registrantKey":8325357307900339981,"joinTime":1554356793898}
  1. Calculate expected signature. Compute an HMAC with the SHA256 hash function. Use the secret key with id X-Webhook-SecreteKey-Id, and use the payload from previous step as the message.
  2. Compare the signature in the header to the expected signature. If a signature matches, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.