Webhooks
Signed events pushed to your endpoints.
Add an endpoint under Webhooks and choose events. Gasket POSTs each event as JSON, signed with the endpoint's secret (shown once).
json
{
"id": "evt_1042",
"object": "event",
"type": "run.completed",
"created_at": "2026-10-15T12:41:11.000Z",
"request_id": "req_...",
"data": { "agent_id": "agt_...", "action_id": null, "run_id": "run_...", "status": "completed", "cost_micros": 20255 }
}| Events you can subscribe to |
|---|
| run.completed, run.failed, run.requires_approval |
| approval.requested, approval.approved, approval.rejected, approval.expired |
| action.authorized, action.denied, action.succeeded, action.failed |
Delivery
- Headers: Gasket-Signature, Gasket-Delivery (id), Gasket-Event (type).
- Respond 2xx within 10 seconds. Anything else is retried after 1m, 5m, 30m, 2h and 6h, then marked failed.
- Every attempt is listed on the endpoint's page with your response; redeliver any delivery from there.
- HTTPS only, public addresses only, no redirects.
verify.js
import crypto from "node:crypto";
// header: the Gasket-Signature header, "t=<unix seconds>,v1=<hex>"
// body: the raw request body, exactly as received
export function verifyGasket(header, body, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");
return expected.length === v1.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}Something wrong or missing? Tell us · Stuck? Help center