> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.synthesia.io/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.synthesia.io/docs/_mcp/server.

# Verifying Synthesia Signatures

> Ensure the authenticity of events received from Synthesia by verifying signatures included in webhook requests. This guide provides step-by-step instructions to construct and validate signatures using your unique webhook secret, enhancing the security of your integrations.

In order to verify that events you receive were sent by Synthesia, they include a signature in the `Synthesia-Signature` header of each event. Construct and verify this signature using a unique secret that we provide for each webhook subscription.

Note that if this signature is compromised, it is critical that you recreate the webhook subscription, else a bad actor would be able to send events to your systems under the guise of Synthesia.

## How do you verify our signatures?

The following steps describe how you may construct the signing signature, allowing for a comparison with the one we provide. If they are the same, you can be confident the event was sent by us.

### Step 1: Fetch the request contents

You need two things from the request; the request timestamp, found in the `Synthesia-Timestamp` header, and the request body.

```python
from flask import request

request_timestamp = request.headers["Synthesia-Timestamp"]
request_body = request.data.decode("utf-8")
```

### Step 2: Create the message

To create the message to be signed, concatenate the timestamp and the request body (the actual JSON payload) using the character `.`:

```python
message = ".".join((request_timestamp, request_body))
```

### Step 3: Construct the signature

Then create the signature, an HMAC created using the SHA256 hash function, by signing the message using the your webhook secret as the signing key.

```python
import hashlib
import hmac

key = "..."  # This is your webhook secret.

signature = hmac.new(
    key.encode("utf-8"),
    message.encode("utf-8"),
    hashlib.sha256,
).hexdigest()
```

### Step 4: Compare the signatures

Compare the computed signature with the one we provide in the `Synthesia-Signature` header.

```python
assert signature == request.headers["Synthesia-Signature"]
```

### Step 5: Compare the timestamps

Optionally, protect yourself from replay attacks by checking that the `Synthesia-Timestamp` is within your tolerance. For example, you might choose to ignore events that were created more than 10 minutes ago.