Why does the webhook callback signing key change with every call as opposed to using mine?

  • 14 November 2023
  • 3 replies

I successfully used the webhook callback API with signing_key verification a few days ago. But now, for some reason, the signing key changes with every callback making me reject the call.

What could possibly be the cause? I did follow the docs @ 

Below is my successful webhook I created:

    "collection": [


            "callback_url": "https://TO_SOME_PLACE/",

            "created_at": "2023-11-14T18:45:52.610226Z",

            "creator": "",

            "events": [





            "organization": "",

            "retry_started_at": null,

            "scope": "user",

            "state": "active",

            "updated_at": "2023-11-14T18:45:52.610226Z",

            "uri": "",

            "user": ""



Thank you in advance



Best answer by anolson 14 November 2023, 20:31

View original

This topic has been closed for comments

3 replies

Userlevel 1

Hey Andreas!


We don’t send the signing key with each webhook payload. What we send instead is signature that’s computed by:

  • Combining a timestamp and the request body 
  • Then generating a HMAC digest with the webhook signing key


You’ll need to do this same computation on your end to verify each payload. We have a few different code examples here:

I somewhat skipped the code examples and simply assumed it’s a simple comparison but what you describe and actually do makes much more sense of course. I changed the code and it works as expected now. My earlier success stemmed from internal testing where I artificially fabricated the headers, thereby cheating.

Again, thank you for the speedy reply. Everything is now fully integrated as we’d like and works as expected. 


P.S. For those in need of a Python way to implement the HMAC digest verification, here it is:


# Assuming you got headers in dict form and body as byte


# Get your assigned signing key

webhook_signing_key = os.getenv("WEBHOOK_SIGNING_KEY")

# Split signature header by time and signature

signature_header = headers['Calendly-Webhook-Signature'].split(',')

t = signature_header[0].split('=')[1]

signature = signature_header[1].split('=')[1]


# Construct payload to sign

payload = t + '.' + body.decode('UTF-8')


# Generate signature with secret key

hexdigest ='UTF-8'), payload.encode('UTF-8'), hashlib.sha256).hexdigest()


# Verify signatures

if hexdigest != signature:

    raise Exception(‘Invalid Signature’)

Userlevel 1

That’s great to hear!