GraphQL API
Use the Panther GraphQL API to interact with your Panther entities
Overview
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 GraphQL's documentation.
Currently, you can interact with the following entities through the GraphQL API:
Additional operations are available in the REST API.
Understanding a GraphQL query
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 2 (most user-friendly): Use Panther's API Playground
Option 3 (best for tools and services): Perform an introspection query against the GraphQL endpoint
Option 1: Download the publicly available GraphQL schema file
You can download the latest version of the GraphQL schema file here.
Option 2: Use the GraphQL Playground
Panther's API Playground is a user-friendly way of browsing and discovering what's supported in our API. Please refer to our API Playground docs for information on how to use this as a discoverability mechanism.
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.
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 API Token in order for the introspection to work.
$ curl -H "X-API-Key: <API_KEY>" -d <INTROSPECTION_QUERY> <YOUR_PANTHER_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:
SaaS deployments:
https://api.{YOUR_PANTHER_DOMAIN}.runpanther.net/public/graphqlCloud Connected and self-hosted deployments:
https://{YOUR_PANTHER_DOMAIN}/v1/public/graphql

Step 2: Generate an API token
Step 3: Invoke the Panther GraphQL API
In addition to testing with the API Playground, there are two ways to invoke a GraphQL-over-HTTP 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:
graphql-requestfor your NodeJS projectsgqlfor your Python projectsgo-graphql-clientfor your Go projects
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)
}Option 2: Manually Constructing HTTP Calls
An example request:
curl 'YOUR_PANTHER_GRAPHQL_API_URL' \
-H 'Content-Type: application/json' \
-H 'X-API-Key: {YOUR_API_KEY}' \
-d '{"query":"\n query Foo {\n alerts {\n edges {\n node {\n id\n }\n }\n }\n }","variables":{}}' 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
POSToperation always contains the following keys:query- a GraphQL string defining the GraphQL operation that should be executedvariables- an optional set of variables that will be passed along to the queryoperationName- 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.
Last updated
Was this helpful?

