Engineering

Verify Computer Use API Webhooks with HMAC Signatures

Rachel Kim||6 min
Ctrl+A

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.

python
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.

Want to see this in action?

View Case Studies
Try Coasty Free