Skip to content

Getting started

What you will build

A GraphQL request that authenticates and searches your tenant's detections from endpoints, network sensors, and other data sources.

Prerequisites

Get credentials

Follow the audience guide above to create a service principal and exchange it for a bearer token, using the same client_credentials grant as every other Sophos API.

First authenticated call

Send a POST request to your configured GraphQL endpoint, with the token from the previous step in the Authorization header and your tenant ID in X-Tenant-ID.

detectionSearch searches detections using QL, the same language as the Advanced Search page.

Its in argument takes a cql_query string to filter by criteria such as status or severity. Set limit to cap the result set. This call asks for up to 10 detections, with no cql_query filter.

The schema doesn't guarantee an order when none is requested, so treat this as an arbitrary page, not "the 10 most recent."

curl -X POST "<graphql-endpoint>" \
  -H "Authorization: Bearer <jwt>" \
  -H "X-Tenant-ID: <tenant-id>" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query ListDetections($in: SearchRequestInput) { detectionSearch(in: $in) { alerts { list { id status metadata { title severity } } total_results } } }",
    "variables": { "in": { "limit": 10 } }
  }'

A successful response looks like this:

{
  "data": {
    "detectionSearch": {
      "alerts": {
        "list": [
          {
            "id": "6f1b1e0e-6b1a-4b3a-9c1a-1a2b3c4d5e6f",
            "status": "OPEN",
            "metadata": {
              "title": "Suspicious PowerShell activity",
              "severity": 0.8
            }
          }
        ],
        "total_results": 3
      }
    }
  }
}

Verify it worked

Check data.detectionSearch.alerts.total_results in the response. It's a number — the count of detections matching your request, not only the page you asked for. Each entry in data.detectionSearch.alerts.list has the id, status, and metadata fields you selected, in that order.

A request that fails at the GraphQL layer — for example, a cql_query string the schema can't parse — still returns HTTP 200, with an errors array alongside data instead of an HTTP error status. This differs from the status-coded error object described in Errors, which covers this API's transport layer instead. An expired token or a rate limit still fails that way, with a non-2xx status and that error object, before your query ever reaches the GraphQL layer.

What to do next

Selection-set cost

Only ask for the fields you need. Nesting one list-returning field inside another — for example, every detection's entities relationship graph on a large page of alerts — multiplies the amount of data the server has to assemble and return. Keep nested list selections as narrow as the fields you actually use.