GUIDES
Webhooks
Webhooks let your application receive real-time notifications when events occur in your agent infrastructure. Use them for monitoring, analytics, and event-driven workflows.
Setting Up a Webhook Endpoint
First, create an HTTP endpoint that can receive POST requests:
Express endpoint
import express from "express";
import crypto from "crypto";
const app = express();
app.use(express.raw({ type: "application/json" }));
const WEBHOOK_SECRET = process.env.YA_WEBHOOK_SECRET!;
app.post("/webhooks/ya-events", (req, res) => {
// 1. Verify signature
const signature = req.headers["x-ya-webhook-signature"] as string;
const timestamp = req.headers["x-ya-webhook-timestamp"] as string;
const body = req.body.toString();
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(`${timestamp}.${body}`)
.digest("hex");
if (!crypto.timingSafeEqual(
Buffer.from(signature.replace("sha256=", "")),
Buffer.from(expected)
)) {
return res.status(401).json({ error: "Invalid signature" });
}
// 2. Process the event
const event = JSON.parse(body);
switch (event.type) {
case "execution.completed":
console.log("Execution completed:", event.data.executionId);
break;
case "execution.failed":
console.error("Execution failed:", event.data.error);
break;
case "tool.error":
console.error("Tool error:", event.data.toolName, event.data.error);
break;
}
// 3. Respond with 200 to acknowledge receipt
res.status(200).json({ received: true });
});
app.listen(3000);
Register the Webhook
Register via SDK
const webhook = await client.webhooks.create({
url: "https://api.example.com/webhooks/ya-events",
events: [
"execution.completed",
"execution.failed",
"tool.error",
],
agentId: "agt_abc123", // optional: filter by agent
});
// Save the secret for signature verification
console.log("Webhook secret:", webhook.secret);
// Store this securely (env variable)
Event Payload Examples
execution.completed
{
"id": "evt_abc123",
"type": "execution.completed",
"data": {
"executionId": "exec_def456",
"agentId": "agt_ghi789",
"conversationId": "conv_jkl012",
"status": "completed",
"output": "I've processed your return request...",
"toolCalls": [
{ "name": "initiate_return", "duration": 234 }
],
"usage": { "totalTokens": 231 },
"timing": { "totalMs": 1234 }
},
"createdAt": "2026-03-15T10:30:00Z"
}
execution.failed
{
"id": "evt_def456",
"type": "execution.failed",
"data": {
"executionId": "exec_ghi789",
"agentId": "agt_jkl012",
"error": {
"type": "upstream_error",
"code": "model_unavailable",
"message": "The model is temporarily unavailable"
}
},
"createdAt": "2026-03-15T10:30:00Z"
}
tool.error
{
"id": "evt_ghi789",
"type": "tool.error",
"data": {
"executionId": "exec_jkl012",
"agentId": "agt_mno345",
"toolName": "lookup_order",
"error": {
"code": "TIMEOUT",
"message": "Tool handler did not respond within 10000ms"
}
},
"createdAt": "2026-03-15T10:30:00Z"
}
Monitoring Dashboard
Use webhooks to build a monitoring pipeline:
Monitoring pipeline
// Send metrics to your analytics platform
app.post("/webhooks/ya-events", (req, res) => {
const event = JSON.parse(req.body.toString());
if (event.type === "execution.completed") {
// Track in your analytics
analytics.track("agent_execution", {
agentId: event.data.agentId,
duration: event.data.timing.totalMs,
tokens: event.data.usage.totalTokens,
toolCalls: event.data.toolCalls.length,
});
}
if (event.type === "execution.failed") {
// Alert on failures
alerting.send({
channel: "#agent-alerts",
message: `Agent ${event.data.agentId} failed: ${event.data.error.message}`,
severity: "high",
});
}
res.status(200).json({ received: true });
});
Note
Always respond to webhook deliveries within 5 seconds with a 2xx status code. If your processing takes longer, acknowledge receipt immediately and process asynchronously.
Testing Webhooks Locally
Use a tunnel service during development to receive webhooks on localhost:
Local testing
# Using ngrok
ngrok http 3000
# Register the ngrok URL as your webhook
await client.webhooks.create({
url: "https://abc123.ngrok.io/webhooks/ya-events",
events: ["execution.completed"],
});