Qoc

Webhooks

Configure inbound HTTP webhooks that create inbox items or trigger workspace runs when an external event fires.


Webhooks give your workspace an inbound HTTP endpoint so external systems — price alerts, news feeds, portfolio risk monitors — can drop items into your inbox or kick off an agent run the moment something worth acting on happens.

How webhooks work

Each workspace can expose one or more named webhook endpoints through the qoc daemon. Incoming POST requests are authenticated with an HMAC-SHA256 signing secret and then dispatched to a handler you define in desk.toml.

A handler maps an incoming payload to one of two actions: `inbox` (write a formatted inbox item to inbox/) or `run` (queue an agent run for a named issue or task). Both actions are non-blocking from the caller's perspective — Qoc acknowledges the webhook with HTTP 202 and processes the action asynchronously.

Configuring a webhook in desk.toml

desk.toml — webhook block
toml
[[webhook]]
name   = "price-alert"
secret = "env:WEBHOOK_SECRET_PRICE_ALERT"   # reads from environment variable
action = "inbox"                             # write to inbox/

[[webhook]]
name   = "risk-breach"
secret = "env:WEBHOOK_SECRET_RISK"
action = "run"
task   = "risk-review"                      # triggers issues/risk-review.md

Endpoint URL

Once configured, each webhook endpoint is available at:

http://localhost:PORT/webhook/<workspace-name>/<webhook-name>

Replace PORT with the port your qoc daemon is listening on (default 7430) and <workspace-name> with the name field from your desk.toml header. The <webhook-name> matches the name field in the [[webhook]] block.

If you expose the daemon behind a reverse proxy or tunnel for external access, the same path applies on your public host.

Example webhook payload

POST /webhook/equity-desk/price-alert
json
{
  "event": "price_alert",
  "symbol": "MSFT",
  "trigger_price": 420.00,
  "current_price": 421.35,
  "direction": "above",
  "alert_name": "MSFT 420 break",
  "timestamp": "2026-07-05T13:45:00Z"
}

Signing requests

Computing the HMAC-SHA256 signature
bash
# The signature is sent in the X-Qoc-Signature header.
# Format: sha256=<hex-digest>
# Body is the raw request body bytes.

BODY='{"event":"price_alert","symbol":"MSFT",...}'
SECRET="your-signing-secret"

SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

curl -X POST "http://localhost:7430/webhook/equity-desk/price-alert"   -H "Content-Type: application/json"   -H "X-Qoc-Signature: sha256=$SIGNATURE"   -d "$BODY"

Handler action reference

action valueEffectRequired extra fields
inboxWrites a formatted inbox item to inbox/TIMESTAMP-WEBHOOK-NAME.mdNone
runQueues an agent run for the named tasktask — name of the issue or task to run

Always use a signing secret

Never expose a webhook endpoint without setting a signing secret. Qoc rejects any request whose X-Qoc-Signature header does not match the expected HMAC. Store the secret value in an environment variable and reference it with the env:VAR_NAME syntax in desk.toml — never hard-code it in the file.

Webhook-triggered runs are subject to the same limits

A webhook that triggers a run action follows the same context injection, scoped command surface, and human-approval flow as a scheduled or manual run. Draft orders still require your approval before execution.