Panther offers a public GraphQL-over-HTTP API, meaning you can write GraphQL queries and invoke the API using a typical HTTP request. For more information on GraphQL, see .
Currently, you can interact with the following entities through the GraphQL API:
Additional operations are available in the .
Understanding a GraphQL query
Click to expand GraphQL query example
The example query below is named ListAlerts. This query will return a list of alerts including every alert's id, title, severity and status based on the time range provided.
The input variable of type AlertsInput is used to filter the alerts based on certain conditions, such as createdAtAfter and createdAtBefore. Those conditions will provide a time range for the query.
The alerts field returns an object with edges and pageInfo. Each edge has a node field that contains the actual alert data, such as id, title, severity and status.
The pageInfo field contains information on pagination, such as hasNextPage and endCursor, which allows the user to loop through all the pages of alerts once hasNextPage becomes false.
query ListAlerts($input: AlertsInput!) {
alerts(input: $input) {
edges {
node {
id
title
severity
status
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
Discover the Panther GraphQL schema
There are three ways to discover the GraphQL schema:
Option 1 (quickest): Download the publicly available GraphQL schema file
Option 1: Download the publicly available GraphQL schema file
Option 2: Use the GraphQL Playground
Option 3: Performing an introspection query
An introspection query yields all the GraphQL API's entities in a format that most third-party libraries can parse. This discoverability option is useful if you want to make another library or service aware of the supported operations and types that the Panther API has. These libraries typically issue their own version of an introspection query, so they only need to be pointed to an API URL.
The actual shape of the introspection query is customizable. You can ask for a limited set of entities or for all possible information about the schema. For example, a query such as the following would yield every single piece of schema information:
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type { ...TypeRef }
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
How to use the Panther GraphQL API
Step 1: Identify your Panther GraphQL API URL
To locate your GraphQL API URL:
In the upper-right corner of your Panther Console, click the gear icon, then API Tokens.
At the top of the page, see the API URL.
The GraphQL API URL structure differs depending on your Panther deployment model:
Step 2: Generate an API token
Step 3: Invoke the Panther GraphQL API
Option 1 (recommended): Install and use a GraphQL Client to abstract the transport-related complexities
Option 2: Manually construct an HTTP call
Option 1: Installing and Using GraphQL Clients (Recommended)
While all GraphQL operations are essentially simple HTTP calls, the advantage of using a GraphQL client is that it is more user-friendly.
We recommend using:
Below are some examples of how you would construct a GraphQL query to fetch the first page of alerts in your system:
// npm install graphql graphql-request
import { GraphQLClient, gql } from 'graphql-request';
const client = new GraphQLClient(
'YOUR_PANTHER_API_URL',
{ headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
// `PaginateAlerts` is a nickname for the operation
const query = gql`
query PaginateAlerts {
alerts(
input: {
createdAtAfter: "2023-06-14T21:00:00Z",
createdAtBefore: "2023-06-21T21:59:59Z"
}) {
edges {
node {
id
title
severity
status
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`;
client.request(query).then((data) => console.log(data));
# pip install gql aiohttp
from gql import gql, Client
from gql.transport.aiohttp import AIOHTTPTransport
transport = AIOHTTPTransport(
url="YOUR_PANTHER_API_URL",
headers={"X-API-Key": "YOUR_API_KEY"}
)
client = Client(transport=transport, fetch_schema_from_transport=True)
# `PaginateAlerts` is a nickname for the operation
query = gql(
"""
query PaginateAlerts {
alerts(
input: {
createdAtAfter: "2023-06-14T21:00:00Z",
createdAtBefore: "2023-06-21T21:59:59Z"
}) {
edges {
node {
id
title
severity
status
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
"""
)
result = client.execute(query)
print(result)
// go get -u github.com/hasura/go-graphql-client
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/hasura/go-graphql-client"
)
// Strongly-typed languages don't pair well with GraphQL
var query struct {
Alerts struct {
Edges []struct {
Node struct {
Id graphql.String
Title graphql.String
Severity graphql.String
Status graphql.String
}
}
PageInfo struct {
HasNextPage graphql.Boolean
EndCursor graphql.String
}
} `graphql:"alerts(input: { createdAtAfter: \"2023-06-14T21:00:00Z\", createdAtBefore: \"2023-06-21T21:59:59Z\" })"`
}
func main() {
client := graphql.
NewClient("YOUR_PANTHER_API_URL", nil).
WithRequestModifier(func(req *http.Request) {
req.Header.Set("X-API-KEY", "YOUR_API_KEY")
})
if err := client.Query(context.Background(), &query, nil); err != nil {
panic(err)
}
formattedResult, _ := json.MarshalIndent(query.Alerts, "", "\t")
fmt.Println(string(formattedResult))
fmt.Println(query.Alerts.PageInfo.HasNextPage)
}
The query above returns the first page of all of your Panther alerts. If it's the first time you're using GraphQL, please note the following:
There's only one endpoint.
The HTTP operation is always a POST.
The API operations are defined in POST's body.
The body of the POST operation always contains the following keys:
query - a GraphQL string defining the GraphQL operation that should be executed
variables - an optional set of variables that will be passed along to the query
operationName - an optional "nickname" for this operation
You must always select a set of fields to return (if the operation returns data.)
Note: The only thing that would change from one GraphQL operation to another is the body of the HTTP POST.
Option 2 (most user-friendly): Use
Option 3 (best for tools and services): Perform an against the GraphQL endpoint
You can download the latest version of the GraphQL schema file .
Panther's API Playground is a user-friendly way of browsing and discovering what's supported in our API. Please refer to our for information on how to use this as a discoverability mechanism.
For security purposes, the introspection query is an authorized operation. This means that you'll need to add an X-API-Key header to your HTTP call with the value of an in order for the introspection to work.