Outbound webhooks
Notify your systems when workflow runs succeed or fail.
Add endpoints in Workspace → Webhooks. For each one, choose the events and either every workflow or specific ones. Kovca POSTs a signed JSON event when a matching run finishes. That covers runs from the API and from webhook triggers, not Studio tests. Webhooks are free and don't count as evaluations. A workspace can have up to 10 endpoints.
Events
run.succeeded: the run finished and returned its output.run.failed: a step failed, the run timed out, or it wasinterrupted.ping: sent by “Send test event”.
{
"id": "evt_5c1f0a6e9b2d4c7a8e3f1b0d2c4a6e8f",
"type": "run.failed",
"created_at": "2026-10-30T14:02:11.000Z",
"data": {
"run_id": "run_...",
"request_id": "req_...",
"workflow": { "id": "wf_...", "version": 4 },
"source": "webhook",
"trigger_id": "trg_...",
"status": "failed",
"error": { "code": "ACTION_FAILED" },
"failed_step": "create_incident",
"evaluations": 1,
"duration_ms": 812,
"started_at": "2026-10-30T14:02:10.188Z",
"finished_at": "2026-10-30T14:02:11.000Z"
}
}Events carry run metadata only: the same facts as GET /v1/runs/{id}, never the workflow's input, output, or what its steps sent and received. Kovca doesn't store those, so retries can always rebuild the event. To send workflow data to another system, add an HTTP request step to the workflow.
Verifying signatures
Deliveries follow the Standard Webhooks format. Each request has webhook-id (the event ID), webhook-timestamp (Unix seconds), and webhook-signature: v1, plus the base64 HMAC-SHA256 of {id}.{timestamp}.{body}, keyed with the base64-decoded part of your whsec_ secret. The secret is shown once, when you add the endpoint or rotate it. Verify the raw body, reject old timestamps, and de-duplicate on webhook-id, which is the same on every retry.
import { Webhook } from "standardwebhooks"; // npm install standardwebhooks
const wh = new Webhook(process.env.KOVCA_WEBHOOK_SECRET); // "whsec_..."
export async function POST(request) {
const body = await request.text(); // the raw body, before JSON parsing
let event;
try {
event = wh.verify(body, Object.fromEntries(request.headers));
} catch {
return new Response("invalid signature", { status: 400 });
}
if (event.type === "run.failed") {
// e.g. page on-call with event.data.workflow.id, event.data.error.code, event.data.run_id
}
return new Response(null, { status: 204 });
}Rotating a secret keeps the old one valid for 24 hours: during that window each delivery carries two signatures, separated by a space, so either secret verifies it.
Delivery and retries
- A 2xx response within 10 seconds counts as delivered. Redirects aren't followed.
- Otherwise Kovca retries after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours, and 24 hours, then marks the delivery failed.
- Endpoints must be public https URLs on port 443 or 8443. The URL is stored encrypted and shown shortened, so it can safely include a token.
- The Webhooks page lists every delivery from the last 30 days with its status, attempts, and last HTTP status. You can resend any finished delivery. A run's page shows the deliveries for that run.
- Turning an endpoint off or deleting it cancels its pending deliveries.