# Webhooks Reference beta
Webhooks enable organizations to trigger automated operations outside of the SalesTim platform, such as in a custom application, or in an automation tool such as Power Automate or Zapier.
WARNING
Due to the fact that data may be exchanged outside of your Microsoft 365 environment, webhooks have to be considered as highly sensitive. Therefore, the SalesTim platform controls webhooks management through RBAC, making any operation related to webhooks accessible only to users granted with one of the following roles:
Global admin
(Microsoft 365) roleTeams service admin
(Microsoft 365) roleIntegration Manager
(SalesTim) role
Table of Contents:
# Anatomy of a Webhook
A wehbook is defined by the following properties:
{
id: '7f105c7d-2dc5-4532-97cd-4e7ae6534c07', // {string} Webhook UUID automatically generated during its creation - ReadOnly
name: 'Example Webhook', // {string} Webhook name - Read/Write
description: 'This is a new webhook', // {string} Webhook description - Read/Write
active: true, // {boolean} Webhook status - Read/Write
events: [ // {array} Array of events codes that will trigger the webhook - Read/Write
'team_provisioning_complete', // {string} Event code - Read/Write
...
],
config: { // {object} Webhook http configuration
verb: 'post', // {string} Http verb used by the the webhook - ReadOnly as currently only `post` is supported
url: 'https://example.com/webhook', // {string} Target URL of the webhook - Read/Write
content_type: 'json', // {string} Http content-type used by the webhook - ReadOnly as currently only `json` (matching to `application/json`) is supported
secret:'secretClientValue' // {string} Secret value used to authentify the wehbook emitter by the consumer - Read/Write
}
}
# Anatomy of a Request
When triggered, the webhook generates an http POST
request to its configured url.
# Headers
The following headers are systematically included in the request:
'X-SalesTim-Hook': '', // {string} UUID of the webhook that triggered the request.
'X-SalesTim-Event': '', // {string} Code of the event that triggered the request.
'X-SalesTim-Delivery': '', // {string} An automatically generated UUID to identify the request.
'X-SalesTim-Signature': '' // {string} This header is sent if the webhook is configured with a secret.
# Payload
A webhook payload has always the same structure:
@odata.context: 'https://developers.salestim.com/api/webhooks', // {string} Link to the webhook online help
tenant_id: '', // {string} The tenant ID from where the event originates
value: {} // {object} Data associated with the event. See the related chapter dedicated to each event for more details.
metadata: {} // {object} - See the "Metadata" chapter below
TIP
For readibility, in the next chapters, we're only describing the structure of the value
property, as the other properties are always included and following the same pattern.
Here is a sample data payload for each supported event.
# team_provisioning_complete
Category: provisioning
Description: Triggered when a team provisioning request based on a template is complete (wether successfully or not).
{
team: {
id: '' // Team ID
},
template: { // {object}
id: '', // Template ID
name: '' // Template name
}
}
# Metadata
In addition to the event data, the payload may contain additional metadata. Here is a sample:
metadata: { // {object} - Collection of `system` and `custom` metadata associated with the event
'system': { // {object} The `system` metadata object is comprised of data managed by the SalesTim platform itself, for instance, additional information passed to the provisioning request that could be used by our naming convention engine.
'division': '' // {string} Division the team belongs to
'data_location': '' // {string} Data location of the team and its associated resources
...
}
... // N.B: The payload may also contain additional `custom` metadata managed by your `connected apps`.
},
}
# User-Agent
The User-Agent for the requests will have the prefix SalesTim-Hook/
and include the SalesTim current version number.
For instance SalesTim-Hook/2.1.193
# Endpoints Requirements
# Security
Your endpoint must be an HTTPS URL with a valid SSL certificate that can correctly process event notifications.
# Responses
The expected success response codes from the target endpoint are 200
, 201
, 202
. If any other code is received, our webhook engine will retry the request following this retry policy:
MAX_RETRY = 2 // Maximum number of retry before flagging the delivery as `failed`
RETRY_INTERVAL = 10000 // Number of milliseconds between each retry
# Verifying Webhooks
Webhooks sent by SalesTim can be verified by calculating a digital signature. Each webhook request includes a X-SalesTim-Signature
header.
To verify that the request came from SalesTim, compute the HMAC hex digest of the request body, generated using the SHA-256 hash function and the secret as the HMAC key. If they match, then you can be sure that the webhook was sent from SalesTim.
Here are a comprehensive list of examples for multiple languages:
# Node
const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'secret');
hmac.update('Message');
console.log(hmac.digest('hex'));
# PHP
<?php
echo hash_hmac('sha256', 'Message', 'secret');
?>
# Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class Test {
public static void main(String[] args) {
try {
String secret = "secret";
String message = "Message";
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] hash = (sha256_HMAC.doFinal(message.getBytes()));
StringBuffer result = new StringBuffer();
for (byte b : hash) {
result.append(String.format("%02x", b));
}
System.out.println(result.toString());
}
catch (Exception e){
System.out.println("Error");
}
}
}
# C#
using System.Security.Cryptography;
namespace Test
{
public class MyHmac
{
public static void Main(string[] args){
var hmac = new MyHmac ();
System.Console.WriteLine(hmac.CreateToken ("Message", "secret"));
}
private string CreateToken(string message, string secret)
{
secret = secret ?? "";
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
var sb = new System.Text.StringBuilder();
for (var i = 0; i <= hashmessage.Length - 1; i++)
{
sb.Append(hashmessage[i].ToString("x2"));
}
return sb.ToString();
}
}
}
}
# Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
func ComputeHmac256(message string, secret string) string {
key := []byte(secret)
h := hmac.New(sha256.New, key)
h.Write([]byte(message))
return hex.EncodeToString(h.Sum(nil))
}
func main() {
fmt.Println(ComputeHmac256("Message", "secret"))
}
# Ruby
require 'openssl'
OpenSSL::HMAC.hexdigest('sha256', "secret", "Message")
# Python (3.x)
import hashlib
import hmac
KEY = "secret"
KEY_BYTES=KEY.encode('ascii')
MESSAGE = "Message"
MESSAGE_BYTES=MESSAGE.encode('ascii')
result = hmac.new(KEY_BYTES, MESSAGE_BYTES, hashlib.sha256).hexdigest()
print (result)
# Managing Webhooks
Organizations can manage webhooks from the SalesTim App UI:
- Open the
Integration
tab - Select the
Webhooks
section.