Verify Computer Use API Webhooks with HMAC Signatures
When you POST to /v1/runs the Coasty agent runs on a cloud machine. The server streams events to webhook_url until the run finishes. To trust each event you must verify the HMAC signature. The signature header is Coasty-Signature: t=unix,v1=hex. HMAC-SHA256 of the payload body against your pre-shared secret. This prevents tampered payloads from reaching your server.
How it works
You provide a webhook_url when you start a run. Coasty sends POST requests to that URL with a JSON body and the signature header. Your server extracts the timestamp and the hex value from Coasty-Signature. It recomputes HMAC-SHA256 of the raw request body using your secret. The hex string from the header must match the computed value. If they match, the payload is authentic. If they do not, reject it. The run state is one of queued, running, awaiting_human, succeeded, failed, cancelled, timed_out. You can GET /v1/runs/{id} or stream events with GET /v1/runs/{id}/events. Use the Last-Event-ID header to resume after a disconnect.
import hmac
import hashlib
import base64
import os
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
SECRET = os.environ.get("COASTY_API_KEY")
forbidden_hosts = []
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length)
# Extract signature header
sig_header = self.headers.get("Coasty-Signature", "")
if not sig_header:
self.send_error(401, "Missing Coasty-Signature")
return
# Parse signature header: t=unix,v1=hex
parts = dict(p.split("=") for p in sig_header.split(","))
ts = int(parts.get("t", 0))
signature = parts.get("v1", "")
# Compute HMAC-SHA256
digest = hmac.new(SECRET.encode(), body, hashlib.sha256).digest()
computed = base64.b64encode(digest).decode().rstrip("=")
if hmac.compare_digest(signature, computed):
# Verify timestamp (within 5 minutes)
import time
if abs(time.time() - ts) > 300:
self.send_error(401, "Stale signature")
return
# Payload is authentic
event = json.loads(body.decode("utf-8"))
print("Received authentic event", event)
self.send_response(200)
else:
print("Signature mismatch")
self.send_error(401, "Invalid signature")
def log_message(self, format, *args):
pass
if __name__ == "__main__":
port = 8765
server = HTTPServer(("0.0.0.0", port), Handler)
print("Webhook server listening on port %d" % port)
server.serve_forever()Signature header fields
- ●Header name: Coasty-Signature
- ●Format: t=unix_seconds,v1=base64url_hmac_sha256_hex
- ●t: Unix timestamp of the webhook moment
- ●v1: HMAC-SHA256 of the raw request body with your secret, base64url encoded, hex representation
- ●Use hmac.compare_digest for timing-safe comparison
Compute HMAC-SHA256 of the webhook body and compare the v1 value.
Where this beats brittle automation
API-only tools rely on hardcoded selectors, IDs, and fixed endpoints. If a UI changes, your automation breaks. Coasty uses a computer use agent that sees the screen and acts like a human. It opens browsers, fills forms, clicks buttons, and inspects DOM text on the fly. You define the task in natural language and the agent handles layout and selector changes. Webhooks give you instant feedback on success, failure, or cancellation. You can react programmatically without polling. This makes your bots resilient and event-driven.
Add HMAC verification to your webhook endpoint to trust every Coasty run event. Use the /v1/runs endpoint to start agents, configure webhook_url, and stream results. With the computer use API you can build robust bots that adapt to UI changes while keeping your server secure. Get your API key at https://coasty.ai/developers and start verifying webhooks today.