# Verifying a webhook subscription

If you have created your [webhook subscription](/api/notifications-api/api-reference/webhook-subscriptions/create-a-webhook-subscription.md) using a signingKey you can validate the authenticity of the webhook by validating the request signature sent in the request header.

From the incoming webhook, parse the following request headers:&#x20;

`messagebird-signature`&#x20;

`messagebird-request-timestamp`&#x20;

In addition, parse the request `URL` and the request `Body`.&#x20;

To calculate the request signature:&#x20;

1. Base64 decode the `messagebird-signature` header;&#x20;
2. Create a SHA256 hash checksum of the request `body` as a binary result;&#x20;
3. Join the request timestamp (`messagebird-request-timestamp` header) with the request URL and `request body` checksum computed in step 2, separated by a new line (`\n`);&#x20;
4. Calculate HMACSHA256 using the signing key as the secret and the joined payload from step 3 to calculate the signature;&#x20;
5. Compare the output of Step 4 with the signature from Step 1. The code snippets below illustrate the intended process. We recommend tailoring these examples to fit your preferred programming language, codebase, or framework.

<figure><img src="/files/Uv8XBDveff6VP7NHn8XQ" alt=""><figcaption><p>Example of header content used for validation. You can see the messagebird-signature and the messagebird-request-timestamp, which are used to validate the request. The event reference is the messagebird-request-id, which can be used for debugging failures using Webhook subscription logs. For more information regarding logs, refer to <a data-mention href="/pages/9m0rJnR7aMCDh0ScHLLA">/pages/9m0rJnR7aMCDh0ScHLLA</a>.</p></figcaption></figure>

**Examples**

The following code snippets are provided to illustrate the intended process. We recommend adapting them to your preferred programming language, codebase, or framework to ensure compatibility.

{% tabs %}
{% tab title="PHP" %}

```
<?php

function verifyWebhookSignature(
    string $headerSignature,
    string $headerTimestamp,
    string $receivedBody,
    string $requestedUrl,
    string $signingKey
): bool {
    $receivedDecodedSignature = base64_decode($headerSignature);

    $bodyHash = hash('sha256', $receivedBody, true);
    $computedSignature = hash_hmac(
        'sha256',
        sprintf("%s\n%s\n%s", $headerTimestamp, $requestedUrl, $bodyHash),
        $signingKey,
        true
    );

    return hash_equals($computedSignature, $receivedDecodedSignature);
}

// Example usage
$isVerified = verifyWebhookSignature(
    $_SERVER['HTTP_MESSAGEBIRD_SIGNATURE'],
    $_SERVER['HTTP_MESSAGEBIRD_REQUEST_TIMESTAMP'],
    file_get_contents('php://input'),
    'https://domain.com/webhook/bird',
    'secureSigningKey'
);
```

{% endtab %}

{% tab title="Golang" %}

```
package main

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

func main() {
    var key string
    var signatureHeader string
    var timestampHeader string
    var url string
    var body []byte

    // Example usage
    match, err := checkSignature(key, signatureHeader, timestampHeader, url, body)
    if err != nil {
       // Error out
       fmt.Printf("something went wrong: %v", err)
       os.Exit(1)
    }

    if !match {
       // Signature doesn't match
       fmt.Println("Signatures don't match!")
    } else {
       // Signature matches
       fmt.Println("Signatures match!")
    }
}

// checkSignature verifies the Bird style HMAC-SHA256 signature for the given data.
func checkSignature(signingKey, signatureHeader, timestampHeader, requestURL string, data []byte) (bool, error) {
    // Step 1: Decode the signature from the header
    actualSignature, err := base64.StdEncoding.DecodeString(signatureHeader)
    if err != nil {
       return false, err
    }

    // Step 2 - 4: Calculate the expected signature
    expectedSignature, err := signSha256(signingKey, timestampHeader, requestURL, data)
    if err != nil {
       return false, err
    }

    // Step 5: Compare the expected signature with the actual signature
    return hmac.Equal(expectedSignature, actualSignature), nil
}

// signSha256 returns the Bird style HMAC-SHA1 signature for the given data.
func signSha256(signingKey, timestamp, requestURL string, data []byte) ([]byte, error) {
    // Step 2: Calculate the SHA256 hash for the given data
    bh := sha256.Sum256(data)

    // Step 3: Concatenate the timestamp, request URL, and the SHA256 hash, separated by a newline character
    var m bytes.Buffer
    _, err := fmt.Fprintf(&m, "%s\n%s\n%s", timestamp, requestURL, bh)
    if err != nil {
       return []byte{}, err
    }

    // Step 4: Calculate the HMAC-SHA256 hash for the concatenated string using the signing key
    mac := hmac.New(sha256.New, []byte(signingKey))
    if _, err := mac.Write(m.Bytes()); err != nil {
       return []byte{}, err
    }
    return mac.Sum(nil), nil
}
```

{% endtab %}

{% tab title="Python" %}

```
import hashlib
import hmac
import base64
import time

class SignedRequest:
    def __init__(self, requestSignature, requestTimestamp, requestBody, requestUrl):
        self._requestSignature = requestSignature
        self._requestTimestamp = str(requestTimestamp)
        self._requestBody = requestBody
        self._requestUrl = requestUrl

    def verify(self, signing_key):
        payload = self._build_payload()
        expected_signature = base64.b64decode(self._requestSignature)
        calculated_signature = hmac.new(signing_key.encode('latin-1'), payload.encode('latin-1'),
                                        hashlib.sha256).digest()
        return expected_signature == calculated_signature

    def is_recent(self, offset=10):
        return int(time.time()) - int(self._requestTimestamp) < offset

    def _build_payload(self):
        checksum_body = hashlib.sha256(self._requestBody.encode('latin-1')).digest()
        str_checksum_body = checksum_body.decode('latin-1')
        parts = [self._requestTimestamp, self._requestUrl, str_checksum_body]
        return "\n".join(parts)
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.bird.com/api/notifications-api/api-reference/webhook-subscriptions/verifying-a-webhook-subscription.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
