Webhook triggers

Start an agent or a workflow from another system with a signed HTTP request.

A webhook trigger gives an agent or a workflow its own URL. When your system calls that URL with a valid signature, AgentWorks starts a run and passes the request body to it as input. No API key is involved: the signature is the proof.

Use a webhook trigger when an event in another system should start work — a new order, a form that was submitted, a ticket that changed status. To drive work from your own code and read results back, use the API with a key instead.

Create the trigger

Create the trigger in the app (see Schedules and triggers). You get two values, shown once:

  • the Webhook URL, https://api.agent-works.ai/triggers/fire/webhook/{trigger_id}
  • the Signing secret

Store the secret as a secret in the calling system.

Sign the request

Every request carries two headers:

HeaderValue
X-Webhook-TimestampThe current time as Unix seconds.
X-Webhook-SignatureBase64 of HMAC-SHA256 over {timestamp}.{body}, keyed with the signing secret.

Sign the exact bytes you send as the body. A request whose timestamp is more than 5 minutes away from the current time is refused, so a captured request cannot be replayed later.

import base64, hashlib, hmac, json, time, urllib.request

url = "https://api.agent-works.ai/triggers/fire/webhook/TRIGGER_ID"
secret = "YOUR_SIGNING_SECRET"

body = json.dumps({"order_id": "SO-10432", "customer": "Berg Wholesale"}).encode()
timestamp = str(int(time.time()))
signature = base64.b64encode(
    hmac.new(secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256).digest()
).decode()

request = urllib.request.Request(
    url,
    data=body,
    method="POST",
    headers={
        "Content-Type": "application/json",
        "X-Webhook-Timestamp": timestamp,
        "X-Webhook-Signature": signature,
    },
)
print(urllib.request.urlopen(request).status)  # 202

What comes back

A valid request answers 202 Accepted straight away; the run starts in the background.

{ "status": "accepted", "trigger_id": "…" }

The JSON you sent is the input of the run. Follow what happened under View fire history on the trigger, or in the agent's or workflow's results.

StatusMeaning
202Accepted. The run is starting.
401The signature or the timestamp is missing, wrong or too old.
402The workspace balance or a spending limit does not allow the run.
404The trigger does not exist or is switched off.
429More than 30 requests in a minute for this endpoint.

Good to know

  • Send JSON. A body that is not JSON is passed on as raw text, cut to 1,000 characters.
  • The limit is 30 requests per minute. If your source can burst above that, queue on your side.
  • If an action in the run needs approval, a person decides it in the app. See Runs and approvals.
  • Rotate the secret by creating a new trigger and switching the caller over.