When alerts are triggered or resolved in your AgentMark platform, alert events are sent to your webhook endpoint. This allows you to integrate with monitoring systems, send notifications, and take automated actions.
Alert events are sent only to your production webhook endpoint. They are not handled by the local dev server (agentmark dev).
{
"event": {
"type": "alert",
"data": {
"alert": {
"id": "string",
"currentValue": 0,
"threshold": 0,
"status": "triggered | resolved",
"timeWindow": "string",
"type": "cost | latency | error_rate"
},
"message": "string",
"timestamp": "string"
}
}
}
Processing Alert Events
if (event.type === "alert") {
const alertData = event.data;
try {
if (alertData.alert.status === "triggered") {
await handleTriggeredAlert(alertData);
} else if (alertData.alert.status === "resolved") {
await handleResolvedAlert(alertData);
}
return NextResponse.json({
message: "Alert processed",
alertId: alertData.alert.id,
status: alertData.alert.status,
});
} catch (error) {
console.error("Alert processing error:", error);
return NextResponse.json(
{ message: "Error processing alert" },
{ status: 500 }
);
}
}
async function handleTriggeredAlert(alertData: any) {
const { alert, message, timestamp } = alertData;
switch (alert.type) {
case "cost":
console.log(`Cost alert: ${alert.currentValue} exceeded threshold ${alert.threshold}`);
break;
case "latency":
console.log(`Latency alert: ${alert.currentValue}ms exceeded threshold ${alert.threshold}ms`);
break;
case "error_rate":
console.log(`Error rate alert: ${alert.currentValue}% exceeded threshold ${alert.threshold}%`);
break;
}
}
async function handleResolvedAlert(alertData: any) {
const { alert, message, timestamp } = alertData;
console.log(`Alert ${alert.id} resolved at ${timestamp}`);
}
Alert Types
| Type | Monitors | Example Threshold |
|---|
cost | API usage costs | Spending > $50/day |
latency | Response times | P95 latency > 5000ms |
error_rate | Error frequency | Error rate > 5% |
Integration Examples
Slack Notifications
async function sendSlackNotification(alert: any, message: string) {
const slackWebhookUrl = process.env.SLACK_WEBHOOK_URL;
if (!slackWebhookUrl) return;
await fetch(slackWebhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `AgentMark Alert: ${alert.type.toUpperCase()}`,
blocks: [
{
type: "section",
text: { type: "mrkdwn", text: message },
},
{
type: "section",
fields: [
{ type: "mrkdwn", text: `*Status:*\n${alert.status}` },
{ type: "mrkdwn", text: `*Current:*\n${alert.currentValue}` },
{ type: "mrkdwn", text: `*Threshold:*\n${alert.threshold}` },
{ type: "mrkdwn", text: `*Window:*\n${alert.timeWindow}` },
],
},
],
}),
});
}
Email Notifications
async function sendEmailAlert(alert: any, message: string) {
// Use your preferred email service (Resend, SendGrid, AWS SES, etc.)
const emailConfig = {
from: process.env.ALERT_EMAIL_FROM,
to: process.env.ALERT_EMAIL_TO,
subject: `AgentMark Alert: ${alert.type} - ${alert.status}`,
html: `
<h2>AgentMark Alert</h2>
<p>${message}</p>
<table>
<tr><td><strong>Alert ID:</strong></td><td>${alert.id}</td></tr>
<tr><td><strong>Type:</strong></td><td>${alert.type}</td></tr>
<tr><td><strong>Status:</strong></td><td>${alert.status}</td></tr>
<tr><td><strong>Current Value:</strong></td><td>${alert.currentValue}</td></tr>
<tr><td><strong>Threshold:</strong></td><td>${alert.threshold}</td></tr>
</table>
`,
};
// await sendEmail(emailConfig);
}
Best Practices
- Respond quickly — return a
200 status promptly, then process the alert asynchronously if needed
- Route by type — send cost alerts to finance channels, latency alerts to engineering, etc.
- Log everything — store alert events for auditing and trend analysis
- Avoid fatigue — use deduplication or cooldown periods for repeated alerts
Have Questions?
We’re here to help! Choose the best way to reach us: