Guide

Verifying Computer Use API Webhooks with HMAC Signatures

Emily Watson||5 min
Ctrl+P

When you create a webhook_url in a POST /v1/runs request, Coasty posts updates to your endpoint. To prove the request really comes from Coasty, the payload includes an HMAC signature. You must verify it before trusting task state, machine logs, or workflow outcomes.

How it works

Coasty signs all POST bodies sent to webhook_url with HMAC-SHA256. The signature appears in the header Coasty-Signature. This header has a format t=unix_timestamp,v1=hex_signature. You reconstruct the original JSON body, compute the HMAC, and compare against the value in v1. If they match, the request is authentic.

python
import base64
import hashlib
import hmac
import os
import json
import time
import requests
from datetime import datetime

# Read the key from the environment
api_key = os.getenv('COASTY_API_KEY')
# If you are at the webhook endpoint, you receive the body as text
def verify_webhook_signature(body_bytes, signature_header, secret_key):
    # Parse the signature header: t=unix,v1=hex
    parts = signature_header.split(',')
    timestamp = int(parts[0].split('=')[1])
    provided_hmac = parts[1].split('=')[1]
    
    # Reconstruct the signing string: timestamp + '.' + body
    signing_string = f"{timestamp}.{body_bytes.decode('utf-8')}"
    signing_bytes = signing_string.encode('utf-8')
    
    # Compute HMAC-SHA256
    computed_hmac = hmac.new(
        secret_key.encode('utf-8'),
        signing_bytes,
        hashlib.sha256
    ).hexdigest()
    
    # Compare in constant time
    return hmac.compare_digest(computed_hmac, provided_hmac)

# Example webhook handler
@app.route('/webhook', methods=['POST'])
def handle_webhook():
    body_bytes = request.get_data()
    signature_header = request.headers.get('Coasty-Signature', '')
    
    if not verify_webhook_signature(body_bytes, signature_header, api_key):
        return 'Invalid signature', 401
    
    body = json.loads(body_bytes)
    event_type = body.get('event_type')
    data = body.get('data')
    
    # Handle different event types (e.g., task completion, workflow step)
    if event_type == 'task_completed':
        run_id = data.get('run_id')
        status = data.get('status')
        # Store result, notify your users, etc.
    
    return 'OK', 200

What Coasty sends

  • webhook_url in POST /v1/runs is HTTPS only
  • Each POST includes Coasty-Signature header with t=unix,v1=hex
  • Body is the full JSON payload describing the event
  • Events: task_started, task_step, task_completed, task_failed, workflow_step, workflow_completed
  • HMAC uses your API key as the secret

Use hmac.compare_digest to safely compare HMACs and avoid timing attacks.

Where this beats brittle automation

API-only agents rely on brittle selectors and fixed endpoints. Computer use agents see the screen and act like humans, handling UI changes, popups, and dynamic layouts. Webhook signatures let you trust remote events without exposing your API key. This makes it safe to orchestrate agents across machines, workflows, and teams.

Secure your computer use agent pipelines with webhook verification. Build reliable monitoring, automated reports, and multi-step workflows. Get your API key at https://coasty.ai/developers and start building.

Want to see this in action?

View Case Studies
Try Coasty Free