Webhooks
Overview
Webhook Verification
import hmac
import hashlib
import time
from flask import Flask, request, abort
app = Flask(__name__)
SIGNING_SECRET = "your_signing_secret_here"
TIMESTAMP_TOLERANCE = 300000 # 5 minutes in milliseconds
def verify_webhook(request):
# 1. Get signature header
signature_header = request.headers.get('X-Terra-Signature')
if not signature_header:
return False, "Missing signature header"
# 2. Parse signature header
parts = dict(item.split('=') for item in signature_header.split(','))
try:
timestamp = int(parts.get('t', 0))
received_signature = parts.get('v1', '')
except (ValueError, AttributeError):
return False, "Invalid signature format"
# 3. Verify timestamp
current_time = int(time.time() * 1000)
age = current_time - timestamp
if abs(age) > TIMESTAMP_TOLERANCE:
return False, "Timestamp too old or in future"
# 4. Get raw body
body = request.get_data(as_text=True)
# 5. Construct signed string
signed_string = f"{timestamp}.{body}"
# 6. Calculate expected signature
expected_signature = hmac.new(
SIGNING_SECRET.encode('utf-8'),
signed_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
# 7. Compare signatures (constant-time)
if not hmac.compare_digest(expected_signature, received_signature):
return False, "Signature mismatch"
return True, None
@app.route('/webhooks/terra', methods=['POST'])
def webhook_handler():
valid, error = verify_webhook(request)
if not valid:
abort(401, description=error)
# Process webhook
data = request.get_json()
print(f"Received webhook: {data}")
return '', 200
if __name__ == '__main__':
app.run(port=3000)
Headers
Header
Description
Example
Signature Format
Body
Event Type
Description
Webhook Payload
Last updated
Was this helpful?