GUURU for Developers

GUURU for Developers

  • Docs
  • Contacts

›Webhooks

Chat Button

  • Getting Started
  • Public Interface
  • Handling Events
  • Conversion
  • Cookies
  • Examples

SmartChat

  • Getting started
  • Chat Window

    • Getting started
    • Parameters

SmartForm

  • Getting Started

Admin API

  • Getting started
  • Examples
  • API Reference

    • Queries
    • Mutations
    • Types
    • Pagination

Webhooks

  • Getting started
  • Examples

Integrations

  • Facebook
  • Freshchat
  • Salesforce
  • Zendesk
  • Microsoft
  • Third Party Messaging

Webhooks Examples

In the examples below we implement a simple HTTP server that listens for connections and verifies the integrity and authenticity of the request using a hash-based message authentication code (HMAC) with SHA256 with the secret you define as key and the request body as message.

To define a secret go to Partner Portal → Settings → Developer, expand the Webhooks section and type a Secret. In the examples we use secr3t but you should choose a strong, randomly generated password.

Although these are working examples, you should not deploy them directly to production. They are intended to give you a quick working version to help you get started.

Code examples with integrity validation

In the examples below we implement a simple HTTP server in various languages without any third-party dependencies that receives HTTP POST requests and computes the HMAC with the SHA256 hash function using secr3t as the key and the body of the request as the message and compares it against the signature received in the X-Guuru-Hmac-Sha256 header.

For simplicity the examples below assume the presence of the header X-Guuru-Hmac-Sha256 but your production code should check for it.

Node.js
Python
Ruby
Go
Java
const http = require('http');
const crypto = require('crypto');
const port = 8000;

const requestHandler = (req, resp) => {
let body = [];
req.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
const digest = crypto.createHmac('SHA256', 'secr3t')
.update(Buffer.from(body, 'utf8'))
.digest('hex');

if (!crypto.timingSafeEqual(
Buffer.from(digest),
Buffer.from(req.headers['x-guuru-hmac-sha256']),
)) {
resp.statusCode = 400;
return resp.end('Invalid request, non-matching HMAC-SHA256 received');
}

return resp.end('Success!');
});
};

const server = http.createServer(requestHandler);

server.listen(port, (err) => {
if (err) {
return console.log('Error starting HTTP server', err);
}

console.log(`HTTP server listening on ${port}`);
});
from http.server import BaseHTTPRequestHandler, HTTPServer
import hashlib
import hmac

PORT = 8000

class requestHandler(BaseHTTPRequestHandler):
def do_POST(self):
body_len = int(self.headers.get('Content-Length', 0))
body = self.rfile.read(body_len)

hash = hmac.new(b'secr3t', body, hashlib.sha256)
digest = hash.hexdigest()

if not hmac.compare_digest(digest, self.headers.get('X-Guuru-Hmac-Sha256')):
self.send_response(400)
self.end_headers()
self.wfile.write(b'Invalid request, non-matching HMAC-SHA256 received')
return

self.send_response(200)
self.end_headers()
self.wfile.write(b'Success!')
return

try:
server = HTTPServer(('', PORT), requestHandler)
print('HTTP server listening on', PORT)
server.serve_forever()
except KeyboardInterrupt:
server.socket.close()
require 'openssl'
require 'webrick'

PORT = 8000

class WebhookServer < WEBrick::HTTPServlet::AbstractServlet
def do_POST(request, response)
hash = OpenSSL::Digest.new('sha256')
digest = OpenSSL::HMAC.hexdigest(hash, 'secr3t', request.body())

unless digest == request.header['x-guuru-hmac-sha256'].join
response.status = 400
response.body = 'Invalid request, non-matching HMAC-SHA256 received'
return
end

response.status = 200
response.body = 'Success!'
end
end

server = WEBrick::HTTPServer.new(:Port => 8000)
server.mount '/', WebhookServer
trap 'INT' do server.shutdown end
server.start
package main

import (
"io/ioutil"
"net/http"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)

func requestHandler(w http.ResponseWriter, r *http.Request) {
body, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()

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"))) {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Invalid request, non-matching HMAC-SHA256 received"))
return
}

w.Write([]byte("Success!"))
}

func main() {
http.HandleFunc("/", requestHandler)
if err := http.ListenAndServe(":8000", nil); err != nil {
panic(err)
}
}

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.MessageDigest;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;

public class Main {
private final static int PORT = 8000;

public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(PORT), 0);
server.createContext("/", new RequestHandler());
server.setExecutor(null);
server.start();
}

static class RequestHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
InputStream is = t.getRequestBody();
String body = new String(is.readAllBytes());
String digest = getSignature("secr3t", body);
String response;

if (!MessageDigest.isEqual(
digest.getBytes(),
t.getRequestHeaders().getFirst("x-guuru-hmac-sha256").getBytes()
)) {
response = "Invalid request, non-matching HMAC-SHA256 received";
t.sendResponseHeaders(400, response.length());
} else {
response = "Success!";
t.sendResponseHeaders(200, response.length());
}

OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}

private 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);

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

Requests and expected signatures

Below are some example payloads and the expected HMAC-SHA256 signatures for each, assuming that the token secr3t is being used.

These examples are JSON without spaces or new lines, just like the payload our webhooks send in the body of each request. For a human friendly example see this test request.

Example 1

{"user":{"name":"joao","email":"","locale":"en"},"question":"My router lights are all yellow and blinking and I can't connect to the Internet from my laptop, what can I do?","status":"rated","language":"en","transcriptURL":"https://chat.guuru.com/guuru-qa/transcripts/-LZu0Bo-008GtlT9A5Oj","rating":1,"category":"general","createdAt":1551456587480,"acceptedAt":1551456623552,"closedAt":1551456680711,"ratedAt":1551456684623}

X-Guuru-Hmac-Sha256: b354f1d1c6586dacd3d578ee59e82d9829761cbe65ba2a9c948f99a34009792a

Example 2

{"user":{"name":"João","email":"","locale":"en"},"question":"Is shipping free for Portugal?","status":"rated","language":"en","transcriptURL":"https://chat.guuru.com/guuru-qa/transcripts/-LZu-ZrIBzpNHGswVFuP","rating":1,"category":"general","createdAt":1551456423860,"acceptedAt":1551456435840,"closedAt":1551456470489,"ratedAt":1551456472882}

X-Guuru-Hmac-Sha256: e3671b73d2c6ef0c0a32cb07db50981ac1eab733632d3915d9a4bebd7454cbeb

Example 3

{"user":{"name":"joao","email":"","locale":"en"},"question":"hello 123","status":"rated","language":"en","transcriptURL":"https://chat.guuru.com/guuru-qa/transcripts/-LZu--MHQ3xLy1RvHqv4","rating":1,"category":"general","createdAt":1551456274349,"acceptedAt":1551456289259,"closedAt":1551456338034,"ratedAt":1551456341040}

X-Guuru-Hmac-Sha256: 7480a83edb7109f9f0021f6150383879f97e926654b91ac3e2aa591dd8fad851

← Getting startedFacebook →
  • Code examples with integrity validation
  • Requests and expected signatures
    • Example 1
    • Example 2
    • Example 3
GUURU for Developers
Docs
SmartChatSmartFormAPI Reference
Community
GitLabFacebookLinkedIn
Copyright © 2025 GUURU Solutions Ltd.