# GraphQL API

## 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](https://graphql.org/learn/).

Currently, you can interact with the following entities through the GraphQL API:

* [Alerts and errors](https://docs.panther.com/panther-developer-workflows/api/graphql/alerts-and-errors)
* [Cloud accounts](https://docs.panther.com/panther-developer-workflows/api/graphql/cloud-account)
* [Data lake queries](https://docs.panther.com/panther-developer-workflows/api/graphql/data-lake-queries)
* [Log sources](https://docs.panther.com/panther-developer-workflows/api/graphql/log-source)
* [Metrics](https://docs.panther.com/panther-developer-workflows/api/graphql/metrics)
* [Schemas](https://docs.panther.com/panther-developer-workflows/api/graphql/schemas)
* [API tokens](https://docs.panther.com/panther-developer-workflows/api/graphql/token-rotation)
* [Users and roles](https://docs.panther.com/panther-developer-workflows/api/graphql/user-management)

Additional operations are available in the [REST API](https://docs.panther.com/panther-developer-workflows/api/rest).

### Understanding a GraphQL query

<details>

<summary>Click to expand GraphQL query example</summary>

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`.

```graphql
query ListAlerts($input: AlertsInput!) {
    alerts(input: $input) {
      edges {
        node {
          id
          title
          severity
          status
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
```

</details>

### 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](https://docs.panther.com/panther-developer-workflows/api/api-playground)
* Option 3 (best for tools and services): Perform an [introspection query](https://graphql.org/learn/introspection/) against the GraphQL endpoint

{% tabs %}
{% tab title="Download GraphQL file" %}
**Option 1: Download the publicly available GraphQL schema file**

You can download the latest version of the GraphQL schema file [here](https://panther-community-us-east-1.s3.amazonaws.com/latest/graphql/schema.public.graphql).
{% endtab %}

{% tab title="Panther API Playground" %}
**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](https://docs.runpanther.io/api-beta/api-playground) for information on how to use this as a discoverability mechanism.
{% endtab %}

{% tab title="Introspection query" %}
**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](https://docs.runpanther.io/api-beta/generating-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:

```graphql
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
                }
              }
            }
          }
        }
      }
    }
  }
```

{% endtab %}
{% endtabs %}

## 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](https://docs.panther.com/system-configuration/panther-deployment-types) deployments: `https://api.{YOUR_PANTHER_DOMAIN}.runpanther.net/public/graphql`
    * [Cloud Connected](https://docs.panther.com/system-configuration/panther-deployment-types) and [self-hosted](https://docs.panther.com/system-configuration/panther-deployment-types) deployments: `https://{YOUR_PANTHER_DOMAIN}/v1/public/graphql`

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-20e1dd8a8366cc1aef4ed43a5aefa73883e04736%2FScreenshot%202023-12-13%20at%2011.35.41%20AM.png?alt=media" alt=""><figcaption></figcaption></figure>

### Step 2: Generate an API token

* See [these instructions on how to create an API token](https://docs.panther.com/panther-developer-workflows/api/..#how-to-create-a-panther-api-token).

### Step 3: Invoke the Panther GraphQL API

In addition to testing with the [API Playground](https://docs.panther.com/panther-developer-workflows/api/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

{% tabs %}
{% tab title="GraphQL Clients" %}
**Option 1: Installing and Using GraphQL Clients&#x20;*****(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-request`](https://github.com/prisma-labs/graphql-request) for your NodeJS projects
* [`gql`](https://github.com/graphql-python/gql) for your Python projects
* [`go-graphql-client`](https://github.com/hasura/go-graphql-client) for 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:

{% tabs %}
{% tab title="NodeJS" %}

```javascript
// 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));
```

{% endtab %}

{% tab title="Python" %}

```python
# 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)
```

{% endtab %}

{% tab title="Golang" %}

```go
// 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)
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="Construct HTTP Calls" %}
**Option 2: Manually Constructing HTTP Calls**

An example request:

```bash
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 `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`.
{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.panther.com/panther-developer-workflows/api/graphql.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
