Page title

Generate webhook signing key

Verify your webhooks by assigning them with a signing key.

Last updated
March 13, 2025

You can sign all your webhooks with a key generated in Easytools. It doesn’t affect the delivery or content of these webhooks in any way, but it allows the recipient to verify the signature using the key.

Generating webhook signing key

Here's how you can generate signing keys for your webhooks:

  1. Go to StoreStore settings
  2. Open the API & Webhooks tab
  3. Click +Generate webhook signing key
  4. Copy your key by clicking Copy key
Important: Make sure to copy and save the signing key, as you won't be able to access it after creating it.

After returning to the API & Webhooks dashboard, you will see information about your signing key. You can also decide to Delete it or generate a new key by clicking Change key.

Using signing key to verify webhooks

From now on, each request sent to the webhook includes an X-Webhook-Signature header. The receiving end must calculate this and compare the values to ensure they match.

To achieve this, calculate the SHA256 of the received request’s content using the previously generated key, then compare the values.

Check the following examples in different programming languages to see how it would work.

JavaScript (Node.js/Express)

const crypto = require('crypto');
const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhook', (req, res) => {
  // Get the signature from the headers
  const receivedSignature = req.headers['x-webhook-signature'];
  
  // Your webhook signing key (should be stored securely)
  const signingKey = 'your_secret_signing_key';
  
  // Get the raw body data
  const data = req.body;
  const jsonData = JSON.stringify(data);
  
  // Calculate signature using HMAC-SHA256
  const calculatedSignature = crypto
    .createHmac('sha256', signingKey)
    .update(jsonData)
    .digest('hex');
  
  // Verify the signature
  if (receivedSignature === calculatedSignature) {
    console.log('Signature verified successfully!');
    res.status(200).send('Webhook received and verified');
  } else {
    console.log('Signature verification failed!');
    res.status(401).send('Invalid signature');
  }
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

PHP

// Get the raw webhook payload without json_decode
$payload = file_get_contents('php://input');

// Get the signature from headers
$receivedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

// Your webhook signing key (should be stored securely)
$signingKey = 'your_secret_signing_key';

// Calculate signature using HMAC-SHA256 directly on the raw payload
$calculatedSignature = hash_hmac('sha256', $payload, $signingKey);

// Verify the signature
if (hash_equals($receivedSignature, $calculatedSignature)) {
    http_response_code(200);
    echo "Webhook received and verified";
} else {
    http_response_code(401);
    echo "Invalid signature";
}

Python (Flask)

from flask import Flask, request, jsonify
import hmac
import hashlib
import json

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    # Get the signature from headers
    received_signature = request.headers.get('X-Webhook-Signature')
    
    # Your webhook signing key (should be stored securely)
    signing_key = 'your_secret_signing_key'
    
    # Get the payload data
    payload = request.get_data()
    
    # Calculate signature using HMAC-SHA256
    calculated_signature = hmac.new(
        signing_key.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    # Verify the signature
    if hmac.compare_digest(received_signature, calculated_signature):
        return jsonify({"message": "Webhook received and verified"}), 200
    else:
        return jsonify({"message": "Invalid signature"}), 401

if __name__ == '__main__':
    app.run(debug=True, port=5000)

C# (.NET)

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseHttpsRedirection();

app.MapPost("/webhook", async context =>
{
    // Read the request body
    using var reader = new StreamReader(context.Request.Body);
    var payload = await reader.ReadToEndAsync();
    
    // Get the signature from headers
    context.Request.Headers.TryGetValue("X-Webhook-Signature", out var receivedSignature);
    
    // Your webhook signing key (should be stored securely)
    string signingKey = "your_secret_signing_key";
    
    // Calculate signature using HMAC-SHA256
    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(signingKey));
    var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
    var calculatedSignature = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
    
    // Verify the signature
    if (receivedSignature.Equals(calculatedSignature, StringComparison.OrdinalIgnoreCase))
    {
        context.Response.StatusCode = 200;
        await context.Response.WriteAsync("Webhook received and verified");
    }
    else
    {
        context.Response.StatusCode = 401;
        await context.Response.WriteAsync("Invalid signature");
    }
});

app.Run();
Get started with Easycart
Get started with Easycart
Fees and payment methods
Fees and payment methods
Migrating from other tools
Migrating from other tools
Checkout
Checkout
Prices
Prices
After purchase
After purchase
Digital downloads
Digital downloads
Checkout recovery
Checkout recovery
Discounts and upsells
Discounts and upsells
Policies, GDPR, Taxes
Policies, GDPR, Taxes
Affiliates
Affiliates
Analytics and ads
Analytics and ads
Waitlist
Waitlist
Automations and Integrations
Automations and Integrations
Orders and Customers
Orders and Customers
Webhooks
Webhooks
API
API
Pricing pages with Easyoffer
Pricing pages with Easyoffer
Testimonials with Easylove
Testimonials with Easylove
Legal pages with Easylegal
Legal pages with Easylegal
Video courses with Easyplayer
Video courses with Easyplayer
Cookie notifications with Easycookie
Cookie notifications with Easycookie
Donations with Easycoffee
Donations with Easycoffee
FAQ pages with Easyfaq
FAQ pages with Easyfaq
Time counters with Easytimer
Time counters with Easytimer