How Webhooks Work
Language

Webhooks

Learn how to set up webhooks for your application.

How Webhooks Work

cside Webhooks are an easy way to get notifications about important events in your cside account. Webhooks can be used to trigger actions in your application, send messages to your Discord or Slack channels, and more.

When you create a webhook endpoint, we will send a POST request to the URL you have specified. The request will contain a JSON payload with information about the event that triggered the webhook.

The Data Structure

We will always send you a structured JSON payload with the following fields:

Prop
Type
event
"alert.created"
The event code
sent_at
string
When the event was sent in ISO 8601 format
data
AlertCreatedObject
The data of the event
domain_id
string
The domain ID that the event is for
destination_id
string
The ID of the endpoint destination

Events

Below is the event IDs and their payloads that will be sent with webhooks.

Event IDs

IDNamedata Object
alert.createdAlert CreatedAlert Object

Event Objects

HMAC Secret (aka x-cside-signature)

We compute an HMAC on the fly, using a SHA256 hash of the payload and your webhook secret that was provided to you when you first created the webhook endpoint. This signature is included in the x-cside-signature header of the request.

WE HIGHLY SUGGEST YOU USE THIS TO VERIFY THE REQUEST IS COMING FROM cside: Not doing so could leave you vulnerable to replay attacks.

Verifying the HMAC secret

If you are using JavaScript, we suggest you use our JavaScript Package to help you verify the signature. We have provided examples on that page that will help you get started with it.

If you are not using JavaScript, you can verify the signature by computing the HMAC SHA256 hash of the request body using your webhook secret, and comparing it to the header (x-cside-signature) that we send with every request.

Here are a few examples in different languages:

async function verifyHmac(body: string, signature: string, secret: string) {
	const encoder = new TextEncoder();
	const encodedBody = encoder.encode(body);

	const key = await crypto.subtle.importKey(
		"raw",
		encoder.encode(secret),
		{ name: "HMAC", hash: "SHA-256" },
		false,
		["sign"]
	);

	const signatureBuffer = await crypto.subtle.sign("HMAC", key, encodedBody);

	const finalSig = Array.from(new Uint8Array(signatureBuffer))
		.map((byte) => byte.toString(16).padStart(2, "0"))
		.join("");

	return signature.toLowerCase() === finalSig;
}
fn verify_hmac(body: &str, signature: &str, secret: &str) -> Result<(), &'static str> {
      let mut mac = HmacSha256::new_from_slice(secret.as_bytes()).map_err(|_| "Invalid secret")?;
      mac.update(body.as_bytes());
      let result = mac.finalize();
      let code_bytes = result.into_bytes();
      let final_sig = hex::encode(code_bytes);

      if signature.to_lowercase() == final_sig {
          Ok(())
      } else {
          Err("Invalid signature")
      }
  }

  // Add to Cargo.toml:
  // [dependencies]
  // hmac = "0.12"
  // sha2 = "0.10"
  // hex = "0.4"
package main

import (
  "crypto/hmac"
  "crypto/sha256"
  "encoding/hex"
  "strings"
)

func verifyHmac(body, signature, secret string) bool {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(body))
	finalSig := hex.EncodeToString(h.Sum(nil))

	return strings.ToLower(signature) == finalSig
}
defmodule HmacVerifier do
	def verify_hmac(body, signature, secret) do
		final_sig =
			:crypto.mac(:hmac, :sha256, secret, body)
			|> Base.encode16(case: :lower)

			String.downcase(signature) == final_sig
	end
end
import hmac
import hashlib
import secrets

def verify_hmac(body: str, signature: str, secret: str) -> bool:
	final_sig = hmac.new(
		secret.encode('utf-8'),
		body.encode('utf-8'),
		hashlib.sha256
	).hexdigest()

	return signature.lower() == final_sig
Was this page helpful?