Webhooks
Get an HTTP call when your runs complete or fail: events, payload, signature verification, delivery log and API.
What webhooks do
A webhook is a URL of yours that AutoData calls with a JSON POST when one of your runs finishes. Manage them on Listeners → Webhooks or at /api/v1/webhooks. To start a run from an incoming request instead, see Triggers.
Creating a webhook
- Click Add Webhook.
- Enter an optional name and the URL. It must be
httporhttps, resolve, and point to a public address. - Select events (the form pre-selects
error,job.completed,job.failed). - Optionally enter a secret to sign calls.
- Save, then use the test button.
Events
| Event | Sent when |
|---|---|
job.completed | One of your runs completes, from any surface. |
job.failed | One of your runs fails. |
error | Platform-wide error notices from the operators only; not sent for your runs. |
warning | Accepted, not currently sent. |
info | Accepted, not currently sent. |
success | Accepted, not currently sent. |
quality.breach | Accepted, not currently sent. |
A webhook created through the API without events subscribes to ["error"] only. Quality alert rules store webhook_ids, but those webhooks are not called when a rule fires. There is no job.cancelled event.
Choosing webhooks per run
A finished run calls every active webhook subscribed to the event, unless the run names webhook_ids; then only those are called. Set it as webhookIds on a dashboard upload, webhook_ids on a connector run, or pipeline_config.webhook_ids on listeners, the SFTP inbox and schedules (target_pipeline_config.webhook_ids on triggers).
Payload
{
"event": "job.completed",
"data": {
"session_id": "3971e9cc-...",
"status": "completed",
"original_filename": "orders.csv",
"timestamp": "2026-09-28T14:32:00.123456",
"files": ["dsm_output.csv", "dsg_output.csv"]
},
"timestamp": "2026-09-28T14:32:00.130001",
"webhook_id": "b6a4c1f0-..."
}
job.failed has "status": "failed" and error instead of files. The test call has "event": "test".
Verifying the signature
With a secret, each call carries X-Webhook-Signature: sha256=<hex>: HMAC-SHA256 with your secret over the payload serialised with sorted keys, exactly as Python's json.dumps(payload, sort_keys=True) produces it. The body on the wire is not sorted, so parse and re-serialise before hashing.
import hashlib, hmac, json
def verify(raw_body: bytes, header: str, secret: bytes) -> bool:
canonical = json.dumps(json.loads(raw_body), sort_keys=True).encode("utf-8")
expected = "sha256=" + hmac.new(secret, canonical, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header or "")
Delivery
- One attempt, 10-second timeout, no automatic retries.
- 2xx counts as delivered; redirects are not followed.
- The URL is re-checked at delivery; private addresses are blocked.
- The delivery log keeps the 50 most recent attempts with event, status code, duration, response excerpt and error.
API
| Method | Path | Notes |
|---|---|---|
| GET | /api/v1/webhooks | List. |
| POST | /api/v1/webhooks | url (required), name, events, secret. 201. |
| GET | /api/v1/webhooks/{id} | One webhook. |
| PUT | /api/v1/webhooks/{id} | Any of url, name, events, secret, active. |
| DELETE | /api/v1/webhooks/{id} | Also deletes its log. |
| POST | /api/v1/webhooks/{id}/test | Sends the test payload; reports your status code. |
| GET | /api/v1/webhooks/{id}/deliveries | Latest 50 attempts. |
Python SDK: list_webhooks(), create_webhook(url, events=None, name=None, secret=None), get_webhook(id), update_webhook(id, **fields) (use active=), delete_webhook(id), test_webhook(id), webhook_deliveries(id).