Webhooks verification

Webhook Verification

To ensure the security and authenticity of webhook requests, you should verify that incoming webhook calls are genuinely from Gett. This verification process uses HMAC-SHA256 signatures with the secret_id provided when you register your webhook subscription.

🔒

Always verify webhook signatures to prevent malicious actors from sending fake webhook events to your endpoint.

How Webhook Verification Works

To verify the authenticity of a webhook, you need to calculate a signature using the provided secret key and the request body (payload). This process is standard for HMAC-SHA256 signatures and can be reproduced in any programming language with a crypto library.

Step 1: Prepare the Data

You will need two components:

  1. Secret Key: The secret_id returned when you registered your webhook subscription. This is a UUID string known only to you and Gett. For example:

    97cea50e-9358-4504-b612-d0179d029692
    
  2. Payload: The exact, byte-for-byte request body received in the webhook. Any alteration, including extra whitespace, will result in an invalid signature. For example (see webhook events for more event types):

    {"id":"01e829ee-5d79-467b-89e1-1cd1741ab177","event_type":"status_changed","env":"","message":"{\"order_id\":70692316,\"product_id\":\"ee5fd157-c16d-4fe8-838a-a6ca6fa08956\",\"status\":\"Cancelled\"}","timestamp":"2025-09-15T15:11:51.740212996Z"}
    

Step 2: Compute the HMAC Hash

Using your language's crypto library, generate an HMAC hash with the SHA256 algorithm.

Provide two arguments to the function:

  • key: Your secret key (secret_id)
  • message: The payload string

The result of this step will be a raw sequence of bytes (a binary digest).

Step 3: Base64 Encode the Hash

Take the raw byte sequence from Step 2 and encode it into a string using standard Base64 encoding. This is necessary to represent the binary data in a text format.

Step 4: Format the Final Signature String

Prepend the prefix sha256= to the Base64 encoded string from Step 3.

Expected Result

For the example data provided above, the final signature must be:

sha256=11psCFAijXoeXXloXhsjg1b5FgU+2nfJKERCd0PYT3A=

You can use this expected result to verify that your implementation is correct.

Implementation Example (Go)

package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
)

func main() {
	secret := "97cea50e-9358-4504-b612-d0179d029692"
	mac := hmac.New(sha256.New, []byte(secret))

	payload := `{"id":"01e829ee-5d79-467b-89e1-1cd1741ab177","event_type":"status_changed","env":"","message":"{\"order_id\":70692316,\"product_id\":\"ee5fd157-c16d-4fe8-838a-a6ca6fa08956\",\"status\":\"Cancelled\"}","timestamp":"2025-09-15T15:11:51.740212996Z"}`
	_, err := mac.Write([]byte(payload))
	if err != nil {
		fmt.Println(err)
		return
	}
	result := "sha256=" + base64.StdEncoding.EncodeToString(mac.Sum(nil))
	fmt.Println(result)
	// Output: sha256=11psCFAijXoeXXloXhsjg1b5FgU+2nfJKERCd0PYT3A=
}

Best Practices

  • Always verify signatures: Never trust webhook data without verification
  • Use constant-time comparison: When comparing signatures, use a constant-time comparison function to prevent timing attacks
  • Store secrets securely: Keep your secret_id in a secure configuration management system, not in your source code
  • Handle verification failures: Log and alert on signature verification failures, as they may indicate malicious activity
  • Preserve the raw payload: Ensure you verify the signature against the exact bytes received, before any parsing or transformation

Next Steps