Back to Blog
Engineering

Sarah Chen6 min
Del

You receive a webhook payload when a Task Run reaches a terminal state, when a Workflow step completes, or when a machine event streams. The header Coasty-Signature: t=unix,v1=hex proves the request originated from Coasty and has not been tampered with. Without verification, you risk processing forged events, replayed state, or malicious payloads that could break your automation logic.

How it works

Coasty signs the raw request body using HMAC-SHA256 and sends it in the header Coasty-Signature. The format is t=<timestamp>,v1=<hex>. You compute the HMAC on your server using the same secret and compare the hex string. If they match and the timestamp is recent, the payload is authentic. The signature covers the entire body, including nested JSON for task runs, workflows, and events.

bash
#!/bin/bash
# Example: Verify a webhook payload (Unix shell)

API_KEY=$(cat "$HOME/.coasty_key")
# Replace with your actual webhook URL
WEBHOOK_URL="https://your-server.com/webhook"

# Simulate an incoming POST (replace with real curl)
curl -X POST "$WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -H "Coasty-Signature: t=1704067200,v1=YOUR_HEX_SIGNATURE" \
  -d '{"event_type":"run.completed","run_id":"abc123","status":"succeeded"}'

# Server-side verification (Python example below)

Server-side verification in Python

  • Read X-API-Key from COASTY_API_KEY environment variable.
  • Compute HMAC-SHA256 of the raw request body.
  • Compare the computed signature to Coasty-Signature header.
  • Check the timestamp to guard against replay attacks.
python
import os
import hmac
import hashlib
import base64
from datetime import datetime, timedelta
from flask import Flask, request, jsonify

app = Flask(__name__)

# Expect the key in the environment
COASTY_API_KEY = os.getenv("COASTY_API_KEY")

# In production, fetch a secret per webhook (e.g., from Coasty dashboard)
WEBHOOK_SECRET = os.getenv("COASTY_WEBHOOK_SECRET")

ALLOWED_TIME_SECONDS = 300  # 5 minutes

@app.route('/webhook', methods=['POST'])
def webhook():
    raw_body = request.get_data(as_text=True)
    signature_header = request.headers.get('Coasty-Signature', '')
    
    # Ensure the header exists and has the expected format
    if not signature_header:
        return jsonify({"error": "missing signature"}), 401
    
    try:
        timestamp_str, hex_sig = signature_header.split(',', 1)
        timestamp = int(timestamp_str.split('=', 1)[1])
    except Exception:
        return jsonify({"error": "malformed signature header"}), 401
    
    # Reject stale payloads
    now = int(datetime.now().timestamp())
    if abs(now - timestamp) > ALLOWED_TIME_SECONDS:
        return jsonify({"error": "stale payload"}), 401
    
    # Compute HMAC
    mac = hmac.new(
        WEBHOOK_SECRET.encode(),
        raw_body.encode(),
        hashlib.sha256
    ).hexdigest()
    
    if not hmac.compare_digest(mac, hex_sig):
        return jsonify({"error": "invalid signature"}), 401
    
    # At this point, the payload is verified
    payload = request.get_json()
    
    # Example: handle a run.completed event
    if payload.get("event_type") == "run.completed":
        run_id = payload.get("run_id")
        status = payload.get("status")
        # Continue with your integration logic
        print(f"Run {run_id} completed with status {status}")
    
    return jsonify({"status": "accepted"})

if __name__ == '__main__':
    app.run(port=8080)

Always compare digests with hmac.compare_digest to avoid timing leaks.

Where this beats brittle automation

Computer use agents interact with real desktops, browsers, and terminals. Webhooks give you a definitive, tamper-evident signal that something changed on the machine. You can trust a run succeeded, a workflow step passed, or a machine event fired, without listening for brittle selectors or polling APIs. This is especially important for workflows with conditional branches, retries, and human approval steps. HMAC verification guarantees that each event you process is exactly what Coasty sent.

Add webhook verification to your server to protect your automation pipeline. With Coasty, you get task runs, workflows, and machine events all signed for integrity. Get a key and start building secure, reliable computer use agents at https://coasty.ai/developers.

© 2026 Coasty

Backed byYCombinator