GUURU for Developers

GUURU for Developers

  • Docs
  • Contacts

›Webhooks

Chat Loader

  • Getting Started
  • Best Practices
  • Public Interface
  • Handling Events
  • Conversion
  • Examples

Chat Widget

  • Getting started
  • Parameters

Smart Form

  • Getting Started

Admin API

  • Getting started
  • Examples
  • API Reference

    • Queries
    • Mutations
    • Types
    • Pagination

Webhooks

  • Getting started
  • Examples

Integrations

  • Facebook
  • Freshchat
  • Salesforce
  • Zendesk

Getting started

Webhooks allow you to build or set up internal applications which subscribe to certain events from Guuru. When one of those events is triggered, we will send a HTTP POST payload to the webhook's configured URL.

Initial configuration

To set up a webhook, visit the Partner Portal Developer page under Settings. Each supported event (e.g. Chat Rated) is shown there and at a minimum you should define a URL under your control for each event you are interested in receiving.

When the event occurs, if you have the corresponding webhook set as active and a non empty URL configured, we will send a HTTP POST request to your URL with a Content-Type: application/json encoded body.

Events

The request contains a X-Guuru-Chat-Id header with a unique chat identifier and a X-Guuru-Event header which identifies the kind of event that triggered the request.

EventDescription
chatTransferredguuru transferred the chat to a company representative
chatRatedcustomer has finished chating and rated the chat

Note that a chatTransferred event will eventually be followed by a chatRated event as the customer can rate chats that were transferred.

Payload structure

The request body is sent in JSON and follows the structure described below.

Fields are omitted when their value is not available.

{
  "user": {
    "name": String,
    "email": String,
    "isLead": Boolean,
    "isUser": Boolean,
    "locale": String // ISO 3166 2 letter country code
  },
  "expert": {
    "id": String,
    "name": String,
    "email": String,
  },
  "category": {
    "id": String,
    "title": String,
  },
  "question": String,
  "status": String, // either "closed" or "rated"
  "languageCode": String, // ISO 639-1 2 letter language code
  "transcriptURL": String,
  "rating": Number, // from 0 to 1
  "createdAt": Number, // in milliseconds since epoch
  "acceptedAt": Number, // in milliseconds since epoch
  "lastUserMessageAt": Number, // in milliseconds since epoch
  "lastExpertMessageAt": Number, // in milliseconds since epoch
  "closedAt": Number, // in milliseconds since epoch
  "ratedAt": Number, // in milliseconds since epoch
  "referer": String,
  "refererPath": String,
  "refererType": String,
  "refererTrigger": String,
  "customMeta": { // any custom keys defined in the chatloader
    "customKey": String
    // ...
  }
}

Securing your webhooks

Once your server is configured to receive payloads, it will listen for any request sent to the URL you configured. For security reasons, you probably want to limit requests to those coming from Guuru.

You need to set up a secret token (pre-shared key) in two places: Partner Portal and your server.

The pre-shared key should be used for anything else, i.e., it should not be a password or token that you use for other service. We recommend that you generate a strong random key using openssl rand -hex 20 but any sequence will do.

Once configured, we will start sending a X-Guuru-Hmac-Sha256 header in our HTTP POST requests. This is a signature computed using hash-based message authentication code (HMAC) with SHA-256 from the payload and the secret you provided.

To verify that the request was not tampered with (integrity) and was sent by us (authenticity) use the following steps:

  1. Extract the signature from the header: The signature is sent as the value of a request header with the key X-Guuru-Hmac-Sha256. Note that your programming language or library may expose the header key as a lower case string, i.e., x-guuru-hmac-sha256.

  2. Determine the expected signature: Compute an HMAC with the SHA256 hash function. Use the secret you configured in the Partner Portal as the key, and use the request body as the message and convert to a hex string representation.

  3. Compare signatures: Compare the signature in the header to the expected signature. If they match you can process the request, if they don't reject the request.

In the examples below, we could have used a simple comparison == to check if the computed signature matches the received signature and it would work, however, to protect against timing attacks we recommend using a constant-time string comparison, when available.

The following examples illustrate this.

JavaScript
Python
Ruby
Go
Java
const crypto = require('crypto');

const digest = crypto.createHmac('SHA256', SECRET)
.update(Buffer.from(req.body, 'utf8'))
.digest('hex');

if (crypto.timingSafeEqual(
Buffer.from(digest),
Buffer.from(req.headers['x-guuru-hmac-sha256']),
)) {
// ...
}
import hashlib
import hmac

hash = hmac.new(SECRET, request.data, hashlib.sha256)
digest = hash.hexdigest()

if hmac.compare_digest(digest, request.headers['X-Guuru-Hmac-Sha256']):
# ...
require 'openssl'

hash = OpenSSL::Digest.new('sha256')
digest = OpenSSL::HMAC.digest(hash, SECRET, req.data)

if digest == request.header['x-guuru-hmac-sha256'].join
# ...
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)

hash := hmac.New(sha256.New, []byte("secr3t"))
hash.Write([]byte(body))
digest := hex.EncodeToString(hash.Sum(nil))

if hmac.Equal([]byte(digest), []byte(r.Header.Get("X-Guuru-Hmac-Sha256"))) {
// ...
}
public class Example {
public static String getSignature(String secret, String body) {
String digest;

try {
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
secret.getBytes(),
"HmacSHA256"
);
hmac.init(secretKey);

// hex digest of the hmac signature
digest = String.format(
"%x",
new BigInteger(1, hmac.doFinal(body.getBytes()))
);
} catch (Exception e) {
throw new RuntimeException(e);
}
return digest;
}

// ...
public void example(/* ... */) {
String digest = getSignature("secr3t", body);
if (!MessageDigest.isEqual(
digest.getBytes(),
t.getRequestHeaders().getFirst("x-guuru-hmac-sha256").getBytes()
)) {
// ...
}
}
}

Making a test request

The command below sends an example payload corresponding to a Chat Rated event, that would be sent to the configured URL when the user rates a chat.

You can use it to test your implementation before configuring the webhook.

In the example below the X-Guuru-Hmac-Sha256 is computed with the secret secr3t as an example. Never use this secret or any other weak one in production.

curl -X POST -H 'Content-Type: application/json' \
-H 'X-Guuru-Chat-Id: -L98hdjh8Ehuhd' \
-H 'X-Guuru-Event: chatRated' \
-H 'X-Guuru-Hmac-Sha256: 97f4fa22d350e6208c2e3ac56ab9ce6277412c5595c95ede77c4b8464df7c365' \
-d '{
  "user": {
    "email": "john.doe@example.com",
    "locale": "de",
    "name": "John",
    "isUser": false,
    "isLead": true
  },
  "question": "I did not receive last month bill, how can I pay?",
  "status": "rated",
  "language": "de",
  "transcriptURL": "https://chat.guuru.com/apple/transcripts/-L98hdjh8Ehuhd",
  "rating": 1,
  "category": "general",
  "createdAt": 1533795300000,
  "acceptedAt": 1533795320000,
  "lastUserMessageAt": 1533795480000,
  "lastExpertMessageAt": 1533795480000,
  "closedAt": 1533795480000,
  "ratedAt": 1533795480000,
  "referer": "https://support.apple.com/en-us/HT204247",
  "refererPath": "/en-us/HT204247"
}' <URL>

Retry window

If there is any problem delivering the request to your endpoint, e.g., network problems or your endpoint is down for maintenance, deploys or any other reason, it will not be lost as we will keep retrying.

For any given chat that we were unable to send, we will retry every 10 minutes (600 seconds) for up to 7 days.

We use At-Least-Once delivery semantics, meaning that in some circumstances we may send the same chat twice.

You can handle this by using the X-Guuru-Chat-Id header that is unique per chat.

← PaginationExamples →
  • Initial configuration
  • Events
  • Payload structure
  • Securing your webhooks
  • Making a test request
  • Retry window
GUURU for Developers
Docs
Getting StartedExamplesAPI Reference
Community
GitLabFacebookLinkedIn
Copyright © 2021 GUURU Solutions Ltd.