Webhooks
Signed run.* and dataset.updated events — Standard Webhooks verification in 10 lines
Register an endpoint and DeepSieve POSTs you events instead of making you poll:
curl -s -X POST $BASE_URL/v1/webhooks \
-H "Authorization: Bearer $DEEPSIEVE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-app.example.com/hooks/deepsieve",
"events": ["run.completed", "run.failed", "dataset.updated"]}'The response includes "secret": "whsec_..." — shown once; use it to verify
signatures. Endpoints must be public HTTPS; up to 10 active endpoints per workspace.
Events
| Event | When |
|---|---|
run.completed / run.failed / run.cancelled | a research run reaches a terminal state |
dataset.updated | a monitored value was re-verified and changed (payload: table, record_id, column, new + superseded evidence ids) |
Verify signatures (Standard Webhooks)
Headers on every delivery: webhook-id, webhook-timestamp (unix seconds),
webhook-signature (v1,<base64 HMAC-SHA256> over "{id}.{timestamp}.{body}").
Any Standard Webhooks library works, or by hand:
import base64, hashlib, hmac, time
def verify(secret: str, headers: dict, body: bytes) -> bool:
ts = headers["webhook-timestamp"]
if abs(time.time() - int(ts)) > 300: # ±5 min tolerance
return False
msg = f"{headers['webhook-id']}.{ts}.".encode() + body
mac = hmac.new(secret.encode(), msg, hashlib.sha256)
expected = "v1," + base64.b64encode(mac.digest()).decode()
return hmac.compare_digest(expected, headers["webhook-signature"])import crypto from "node:crypto";
function verify(secret: string, headers: Record<string, string>, body: string): boolean {
const ts = headers["webhook-timestamp"];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const mac = crypto.createHmac("sha256", secret)
.update(`${headers["webhook-id"]}.${ts}.${body}`).digest("base64");
return crypto.timingSafeEqual(Buffer.from(`v1,${mac}`),
Buffer.from(headers["webhook-signature"]));
}Delivery & retries
2xx acknowledges. Anything else retries with backoff: 1m, 5m, 30m, 2h, 12h,
then the delivery is dropped. webhook-id is stable across retries — use it to
deduplicate. Test with POST /v1/webhooks/{id}/ping. Manage with
GET/PATCH/DELETE /v1/webhooks/{id} (PATCH keeps the secret; DELETE
disables). Rotate a leaked secret with POST /v1/webhooks/{id}/rotate — it
returns a new whsec_ once and the old secret stops signing immediately, so
re-point your verifier first. Bring a disabled endpoint back with
POST /v1/webhooks/{id}/enable (the secret is unchanged).