Signature Verification

MyMX signs every webhook request so you can verify it came from us. This prevents attackers from sending fake webhooks to your endpoint.

The signature header

Every webhook includes a MyMX-Signature header with this format:

t=1734523200,v1=5257a869e7ecebeda32aff1deadbeef951cad7e77a0e56ff536d0ce8e108d8bd
  • t - Unix timestamp when the signature was generated
  • v1 - HMAC-SHA256 signature

Verifying with the SDK

The easiest way to verify signatures is with the official SDK:

import { verifyWebhookSignature, WebhookVerificationError } from 'mymx';
try {
verifyWebhookSignature({
rawBody, // The raw request body as a string
signatureHeader, // The MyMX-Signature header value
secret: process.env.WEBHOOK_SECRET,
});
// Signature is valid
} catch (err) {
if (err instanceof WebhookVerificationError) {
// Invalid signature
console.error('Verification failed:', err.code);
}
throw err;
}

Manual verification

If you're not using the SDK, here's how to verify manually:

  1. Parse the header - Extract t (timestamp) and v1 (signature)
  2. Check the timestamp - Reject if older than 5 minutes (prevents replay attacks)
  3. Compute expected signature - HMAC-SHA256 of {timestamp}.{rawBody} using your secret
  4. Compare signatures - Use constant-time comparison to prevent timing attacks
import hmac
import hashlib
import time
def verify_signature(raw_body, signature_header, secret):
# Parse header
parts = dict(p.split('=', 1) for p in signature_header.split(','))
timestamp = int(parts['t'])
signature = parts['v1']
# Check timestamp (5 min tolerance)
if abs(time.time() - timestamp) > 300:
return False
# Compute expected signature
signed_payload = f"{timestamp}.{raw_body}"
expected = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()
# Constant-time comparison
return hmac.compare_digest(signature, expected)

Finding your webhook secret

Your webhook secret is in the Webhooks section of your dashboard. Your webhook secret is global across all endpoints. Store it securely as an environment variable - never commit it to source control.

Rotating your secret

You can rotate your webhook secret from the dashboard at any time. When you rotate, the old secret is immediately invalidated. Make sure to update your webhook handlers before rotating to avoid verification failures.

Error codes

The SDK throws WebhookVerificationError with these codes:

CodeDescription
INVALID_SIGNATURE_HEADERMissing or malformed MyMX-Signature header
TIMESTAMP_OUT_OF_RANGETimestamp is too old (possible replay attack)
SIGNATURE_MISMATCHSignature doesn't match expected value
MISSING_SECRETNo webhook secret was provided