Back to Blog
Engineering

Priya Patel6 min
⌘+W

When your Task Runs emit events via webhooks, you need to be sure the payload actually came from Coasty. A malicious actor could craft a request that claims a run succeeded or failed when it did not. The Coasty computer use API signs every webhook request with an HMAC. You must verify this signature before processing the event. This guide shows you how to validate incoming webhooks using the Coasty-Signature header and your API key.

How webhook signatures work

Coasty sends webhooks from POST /v1/runs/{id}/events. The response is a stream of server-sent events. Each event is an HTTP request with a header named Coasty-Signature. This header contains a timestamp and an HMAC value. The header format is Coasty-Signature: t=unix,v1=hex. The timestamp is seconds since the Unix epoch. The hex string is an HMAC-SHA256 computed over the raw request body using your Coasty API key. To verify, you decode the header, recompute the HMAC on the received body, and compare the hex values. If they match, the request is authentic.

python
import os
import hmac
import hashlib
import json
import time
from flask import Flask, request, Response

app = Flask(__name__)
API_KEY = os.getenv("COASTY_API_KEY")

@app.route("/webhook", methods=["POST"])
def handle_webhook():
    # 1. Get raw body (Flask reads into request.data)
    body = request.data
    
    # 2. Extract signature header
    sig_header = request.headers.get("Coasty-Signature")
    if not sig_header:
        return "Missing signature", 401
    
    # 3. Parse header (t=unix,v1=hex)
    parts = sig_header.split(",")
    timestamp = None
    hex_signature = None
    for part in parts:
        if part.startswith("t="):
            timestamp = int(part[2:])
        elif part.startswith("v1="):
            hex_signature = part[3:]
    
    if timestamp is None or hex_signature is None:
        return "Invalid signature format", 401
    
    # 4. Reject replayed or old requests (e.g., >5 minutes old)
    if abs(time.time() - timestamp) > 300:
        return "Timestamp too old", 401
    
    # 5. Compute HMAC-SHA256 of the body using your API key
    computed = hmac.new(
        API_KEY.encode("utf-8"),
        body,
        hashlib.sha256
    ).hexdigest()
    
    # 6. Compare hex strings in constant-time to avoid timing attacks
    if not hmac.compare_digest(computed, hex_signature):
        return "Signature mismatch", 401
    
    # 7. Payload is verified; parse and handle the event
    try:
        event = json.loads(body)
        run_id = event.get("run_id")
        status = event.get("status")
        print(f"Verified event: run_id={run_id}, status={status}")
        # Process your business logic here, for example:
        # - Update your database record for the run
        # - Trigger downstream workflows
        # - Notify your team
        return "OK", 200
    except json.JSONDecodeError:
        return "Invalid JSON body", 400

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

Key webhook fields and states

  • POST /v1/runs/{id}/events streams Server-Sent Events. Each event is a separate HTTP request with Coasty-Signature header.
  • Each event payload is JSON. It contains run_id, status, and optional fields like error_code, message, and timestamp.
  • Status values include queued, running, awaiting_human, succeeded, failed, cancelled, and timed_out.
  • The Coasty-Signature header format is Coasty-Signature: t=unix,v1=hex. Extract both parts for validation.
  • Use hmac.compare_digest to safely compare computed and received signatures and avoid timing side channels.

Always verify the Coasty-Signature header before processing any webhook payload.

Where this beats brittle automation

Traditional automation often relies on fragile selectors or fixed endpoints. If a UI element moves or an API contract changes, your scripts break. The Coasty computer use API lets you drive real desktops, browsers, and terminals through Task Runs. You configure a task and a webhook URL for events. The agent executes the task in a browser or desktop environment. When the run reaches a final state, Coasty sends a webhook with the status. By verifying the HMAC, you know the run state is authentic and not tampered with. This pattern works for any workflow you orchestrate with POST /v1/runs or POST /v1/workflows.

You now have a production-ready webhook verification flow for the Coasty computer use API. Use the HMAC signature to ensure that every event you receive is genuine and untampered. From here, you can build robust monitoring dashboards, trigger downstream automation, or notify your team when a Task Run succeeds or fails. Get your API key at https://coasty.ai/developers and start building resilient computer use agents today.

© 2026 Coasty

Backed byYCombinator