Alerts & Errors
The Panther API supports the following alerting operations:
  • Listing your alerts and errors with optional filters
  • Fetching the details of a particular alert
  • Updating the status of one or more alerts
See the sections below for GraphQL queries and mutations around certain common operations, as well as end-to-end examples on typical workflows.

Common Operations

Below are some of the most common GraphQL operations in Panther. These examples demonstrate how you can use a GraphQL client (or curl) to make a call to Panther's GraphQL API.
For more information on what fields and operations exist in the API, please see the Discovering the Schema documentation.

Listing your Alerts

First page of all alerts
Subsequent page of alerts
Filtered page of alerts
1
# `FirstPageOfAllAlerts` is a nickname for the operation
2
query FirstPageOfAllAlerts {
3
alerts {
4
edges {
5
node { # you can ask for more alert-related fields here
6
id
7
title
8
severity
9
status
10
}
11
}
12
pageInfo {
13
hasNextPage
14
endCursor
15
}
16
}
17
}
Copied!
1
# `AnotherPageOfAllAlerts` is a nickname for the operation
2
query AnotherPageOfAllAlerts {
3
alerts(input: { cursor: "value_of_`pageInfo.endCursor`" }) {
4
edges {
5
node { # you can ask for more alert-related fields here
6
id
7
title
8
severity
9
status
10
}
11
}
12
pageInfo {
13
hasNextPage
14
endCursor
15
}
16
}
17
}
Copied!
1
# `FilteredPageOfAlerts` is a nickname for the operation
2
query FilteredPageOfAlerts {
3
alerts(input: { severities: [LOW], statuses: [OPEN] }) {
4
edges {
5
node { # you can ask for more alert-related fields here
6
id
7
title
8
severity
9
status
10
}
11
}
12
pageInfo {
13
hasNextPage
14
endCursor
15
}
16
}
17
}
Copied!

Describing an Alert

1
query AlertDetails {
2
alert(id: "FAKE_ALERT_ID") {
3
id
4
title
5
severity
6
status
7
}
8
}
Copied!

Updating the status of one or more Alerts

1
mutation UpdateAlertStatus {
2
updateAlertStatusById(
3
input: {
4
ids: ["FAKE_ALERT_ID_1","FAKE_ALERT_ID_2"],
5
status: CLOSED # notice how this isn't a string when hardcoded (it's an `enum`)
6
}
7
) {
8
alerts {
9
id
10
status
11
}
12
}
13
}
Copied!

End-to-end Examples

Below, we will build on the Common Operations examples to showcase an end-to-end flow.

Find a particular set of alerts and mark them as Resolved:

NodeJS
Python
1
// npm install graphql graphql-request
2
3
import { GraphQLClient, gql } from 'graphql-request';
4
5
const client = new GraphQLClient(
6
'YOUR_PANTHER_API_URL',
7
{ headers: { 'X-API-Key': 'YOUR_API_KEY' }
8
});
9
10
// `FindAlerts` is a nickname for the query. You can fully omit it.
11
const findAlerts = gql`
12
query FindAlerts($input: AlertsInput!) {
13
alerts(input: $input) {
14
edges {
15
node {
16
id
17
}
18
}
19
pageInfo {
20
hasNextPage
21
endCursor
22
}
23
}
24
}
25
`;
26
27
// `UpdateAlerts` is a nickname for the query. You can fully omit it.
28
const updateAlerts = gql`
29
mutation UpdateAlerts($input: UpdateAlertStatusByIdInput!) {
30
updateAlertStatusById(input: $input) {
31
alerts {
32
id
33
}
34
}
35
}
36
`;
37
38
(async () => {
39
try {
40
41
// an accumulator that holds all alerts that we fetch all pages
42
let allAlerts = [];
43
// a helper to know when to exit the loop
44
let hasMore = true;
45
// the pagination cursor
46
let cursor = null;
47
48
// Keep fetching pages until there are no more left
49
do {
50
const queryData = await client.request(findAlerts, {
51
input: {
52
severities: ["LOW"],
53
createdAtBefore: "2022-03-01T00:00:00.000Z",
54
createdAtAfter: "2022-02-01T00:00:00.000Z",
55
cursor
56
}
57
});
58
59
allAlerts = [
60
...allAlerts,
61
...queryData.alerts.edges.map((edge) => edge.node)
62
];
63
64
hasMore = queryData.alerts.pageInfo.hasNextPage;
65
cursor = queryData.alerts.pageInfo.endCursor;
66
} while (hasMore);
67
68
69
const mutationData = await client.request(updateAlerts, {
70
input: {
71
ids: allAlerts.map((alert) => alert.id),
72
status: "RESOLVED"
73
}
74
});
75
76
console.log(
77
`Resolved ${mutationData.updateAlertStatusById.alerts.length} alert(s)!`
78
);
79
} catch (err) {
80
console.error(err.response);
81
}
82
})();
83
Copied!
1
# pip install gql aiohttp
2
3
from gql import gql, Client
4
from gql.transport.aiohttp import AIOHTTPTransport
5
6
transport = AIOHTTPTransport(
7
url="YOUR_PANTHER_API_URL",
8
headers={"X-API-Key": "YOUR_API_KEY"}
9
)
10
11
client = Client(transport=transport, fetch_schema_from_transport=True)
12
13
# `FindAlerts` is a nickname for the query. You can fully omit it.
14
find_alerts = gql(
15
"""
16
query FindAlerts($input: AlertsInput!) {
17
alerts(input: $input) {
18
edges {
19
node {
20
id
21
}
22
}
23
pageInfo {
24
hasNextPage
25
endCursor
26
}
27
}
28
}
29
"""
30
)
31
32
# `UpdateAlerts` is a nickname for the query. You can fully omit it.
33
update_alerts = gql(
34
"""
35
mutation UpdateAlerts($input: UpdateAlertStatusByIdInput!) {
36
updateAlertStatusById(input: $input) {
37
alerts {
38
id
39
}
40
}
41
}
42
"""
43
)
44
45
# an accumulator that holds all alerts that we fetch all pages
46
all_alerts = []
47
# a helper to know when to exit the loop
48
has_more = True
49
# the pagination cursor
50
cursor = None
51
52
# Keep fetching pages until there are no more left
53
while has_more:
54
query_data = client.execute(
55
find_alerts,
56
variable_values={
57
"input": {
58
"severities": ["LOW"],
59
"createdAtBefore": "2022-03-01T00:00:00.000Z",
60
"createdAtAfter": "2022-02-01T00:00:00.000Z",
61
"cursor": cursor
62
}
63
}
64
)
65
66
all_alerts.extend([edge["node"] for edge in query_data["alerts"]["edges"]])
67
has_more = query_data["alerts"]["pageInfo"]["hasNextPage"]
68
cursor = query_data["alerts"]["pageInfo"]["endCursor"]
69
70
mutation_data = client.execute(
71
update_alerts,
72
variable_values={
73
"input": {
74
"ids": [alert["id"] for alert in all_alerts],
75
"status": "RESOLVED"
76
}
77
}
78
)
79
80
print(f'Resolved {len(mutation_data["updateAlertStatusById"]["alerts"])} alert(s)!')
Copied!