Back to Blog
Engineering

Lisa Chen6 min
End

When you spin up a computer use agent with POST /v1/runs, the server streams events to your webhook_url. Those events include task steps, success, and failures. Malicious actors could forge payloads, so you must verify the source with HMAC signatures. Coasty signs each webhook with header Coasty-Signature: t=unix,v1=hex. This guide shows how to decode that header and validate the payload using the shared secret from your COASTY_API_KEY.

How it works

Coasty sends every webhook with a Coasty-Signature header that follows this format t=unix,v1=hex. The unix value is the timestamp in seconds since the epoch. The hex is an HMAC-SHA256 HMAC computed over the raw request body using the API key as the secret. Your server receives the header and the body, extracts the timestamp and signature, checks that the timestamp is recent, recomputes the HMAC, and compares it byte‑for‑byte. If they match, the payload is authentic.

python
import os
import hmac
import hashlib
import base64
from datetime import datetime, timezone

COASTY_API_KEY = os.environ.get("COASTY_API_KEY")

# Example webhook payload from Coasty
PAYLOAD = b'{"event_type":"task_step","run_id":"run_abc123","step":1,"status":"running"}'

# Signature header from Coasty
COASTY_SIGNATURE = "t=1729123456,v1=5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"

def verify_webhook_signature(payload: bytes, signature_header: str, secret: str) -> bool:
    try:
        # Parse signature header
        timestamp_str, hex_digest = signature_header.split(",v1=")
        timestamp = int(timestamp_str.split("t=")[1])
        
        # Reject stale webhooks (clock skew tolerance of 300 seconds)
        now = datetime.now(timezone.utc).timestamp()
        if abs(now - timestamp) > 300:
            return False
        
        # Recompute HMAC
        mac = hmac.new(secret.encode("utf-8"), payload, hashlib.sha256)
        expected_digest = mac.hexdigest()
        
        # Constant‑time comparison to avoid timing attacks
        return hmac.compare_digest(hex_digest, expected_digest)
    except Exception:
        return False

if __name__ == "__main__":
    is_valid = verify_webhook_signature(PAYLOAD, COASTY_SIGNATURE, COASTY_API_KEY)
    print("Webhook verified", is_valid)

Handling Server-Sent Events

  • The GET /v1/runs/{id}/events endpoint streams Server-Sent Events.
  • Each event includes fields like event_type, run_id, and optionally data.
  • For webhooks, Coasty sends a complete JSON payload for each event.
  • Include Last-Event-ID in subsequent requests to resume from the last known event.

Use hmac.compare_digest for constant‑time signature comparison to prevent timing attacks.

Where this beats brittle automation

Traditional automation relies on brittle selectors like CSS classes or XPaths that break when UI changes. Coasty’s computer use agent sees the actual screen and clicks the right element, so the event payload reflects real user actions. By verifying those events with HMAC, you can trust that the agent’s progress and results are genuine, not forged by a malicious system. This gives you a secure, observable pipeline for autonomous workflows.

Start securing your computer use API webhooks with HMAC signatures today. Create a Coasty API key at https://coasty.ai/developers and set COASTY_API_KEY in your environment. Use the code above to validate every incoming event and build reliable, trustworthy automation pipelines.

© 2026 Coasty

Backed byYCombinator