Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/v2-alert-silence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperdx/api': minor
---

feat: Silence and unsilence alerts through the external API with POST and DELETE /api/v2/alerts/{id}/silenced
157 changes: 157 additions & 0 deletions packages/api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -6600,6 +6600,163 @@
}
}
},
"/api/v2/alerts/{id}/silenced": {
"post": {
"summary": "Silence Alert",
"description": "Silences an alert until the given time. Notifications are suppressed while the alert is silenced.",
"operationId": "silenceAlert",
"tags": [
"Alerts"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Alert ID",
"example": "65f5e4a3b9e77c001a123456"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"mutedUntil"
],
"properties": {
"mutedUntil": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 timestamp, in the future, until which the alert is silenced.",
"example": "2026-01-01T00:00:00.000Z"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Successfully silenced alert",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AlertResponseEnvelope"
}
}
}
},
"400": {
"description": "Invalid request, such as a mutedUntil in the past",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Alert not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"delete": {
"summary": "Unsilence Alert",
"description": "Clears the silence on an alert so notifications resume",
"operationId": "unsilenceAlert",
"tags": [
"Alerts"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Alert ID",
"example": "65f5e4a3b9e77c001a123456"
}
],
"responses": {
"200": {
"description": "Successfully unsilenced alert",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AlertResponseEnvelope"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Alert not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/api/v2/charts/series": {
"post": {
"summary": "Query Chart Series Data",
Expand Down
28 changes: 28 additions & 0 deletions packages/api/src/controllers/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,34 @@ export const getAlertById = async (
});
};

export const silenceAlert = async (
alertId: ObjectId | string,
teamId: ObjectId | string,
userId: ObjectId,
until: Date,
) => {
const alert = await getAlertById(alertId, teamId);
if (!alert) {
return null;
}
alert.silenced = { by: userId, at: new Date(), until };
await alert.save();
return alert;
};

export const unsilenceAlert = async (
alertId: ObjectId | string,
teamId: ObjectId | string,
) => {
const alert = await getAlertById(alertId, teamId);
if (!alert) {
return null;
}
alert.silenced = undefined;
await alert.save();
return alert;
};

export const getTeamDashboardAlertsByDashboardAndTile = async (
teamId: ObjectId,
) => {
Expand Down
19 changes: 9 additions & 10 deletions packages/api/src/routers/api/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
deleteAlert,
getAlertById,
getAlertEnhanced,
silenceAlert,
unsilenceAlert,
updateAlert,
validateAlertInput,
} from '@/controllers/alerts';
Expand Down Expand Up @@ -416,16 +418,15 @@ router.post(
return res.sendStatus(403);
}

const alert = await getAlertById(req.params.id, teamId);
const alert = await silenceAlert(
req.params.id,
teamId,
req.user._id,
new Date(req.body.mutedUntil),
);
if (!alert) {
return res.status(404).json({ error: 'Alert not found' });
}
alert.silenced = {
by: req.user._id,
at: new Date(),
until: new Date(req.body.mutedUntil),
};
await alert.save();

res.sendStatus(200);
} catch (e) {
Expand All @@ -448,12 +449,10 @@ router.delete(
return res.sendStatus(403);
}

const alert = await getAlertById(req.params.id, teamId);
const alert = await unsilenceAlert(req.params.id, teamId);
if (!alert) {
return res.status(404).json({ error: 'Alert not found' });
}
alert.silenced = undefined;
await alert.save();

res.sendStatus(200);
} catch (e) {
Expand Down
Loading
Loading