How to Export Cortex XDR Logs

How to Export Cortex XDR Logs

SOC Prime Team
SOC Prime Team linkedin icon Follow

Use the XQL query APIs. Start a query with /public_api/v1/xql/start_xql_query, which returns an execution ID. Fetch the results with /public_api/v1/xql/get_query_results in JSON. That call returns up to 1,000 results inline; anything bigger comes back as a stream ID you pass to /public_api/v1/xql/get_query_results_stream. Authentication uses two headers: your API key in Authorization and its ID in x-xdr-auth-id.

Cortex XDR collects detailed endpoint telemetry, plus network and identity data in many deployments. Prime Core has more than 24,000 unique detection rules, mapped to 676 MITRE ATT&CK techniques. Below is how to get data out, sanitize it, and investigate it for free in LogTotal.

Get Started For Free

Before you start

An API key. Create one in the Cortex XDR settings (the standard key type is simplest) with a role that can run XQL queries. Note the key and its ID.

Your API URL. It’s shown when you create the key, in the form https://api-<tenant>.xdr.<region>.paloaltonetworks.com.

License and quota. The XQL APIs need a Cortex XDR Pro license. Queries draw on your XQL quota, and you can run up to four API queries in parallel.

The dataset. Endpoint telemetry is in xdr_data, with fields such as agent_hostname, event_type, action_process_image_command_line and actor_process_image_name. Build the query in the Query Builder first.

Export with the XQL APIs

XDR="https://api-<tenant>.xdr.<region>.paloaltonetworks.com"
H1="Authorization: $XDR_API_KEY"
H2="x-xdr-auth-id: $XDR_API_KEY_ID"

# 1. start the query (timeframe in epoch milliseconds)
QID=$(curl -sS -X POST "$XDR/public_api/v1/xql/start_xql_query" -H "$H1" -H "$H2" -H 'Content-Type: application/json' \
  -d '{"request_data": {"query": "dataset = xdr_data | filter agent_hostname = \"WS-042\" | fields _time, agent_hostname, event_type, action_process_image_name, action_process_image_command_line, actor_process_image_name", "timeframe": {"from": 1792368000000, "to": 1792454400000}}}' \
  | jq -r '.reply')

# 2. wait for the results
while :; do
  RESP=$(curl -sS -X POST "$XDR/public_api/v1/xql/get_query_results" -H "$H1" -H "$H2" -H 'Content-Type: application/json' \
    -d "{\"request_data\": {\"query_id\": \"$QID\", \"pending_flag\": true, \"format\": \"json\"}}")
  [ "$(echo "$RESP" | jq -r '.reply.status')" != "PENDING" ] && break
  sleep 5
done

# 3. up to 1,000 results inline; more through the stream
STREAM=$(echo "$RESP" | jq -r '.reply.results.stream_id // empty')
if [ -n "$STREAM" ]; then
  curl -sS -X POST "$XDR/public_api/v1/xql/get_query_results_stream" -H "$H1" -H "$H2" -H 'Content-Type: application/json' \
    -d "{\"request_data\": {\"stream_id\": \"$STREAM\", \"is_gzip_compressed\": false}}" > xdr_ws042_1019.jsonl
else
  echo "$RESP" | jq -c '.reply.results.data[]' > xdr_ws042_1019.jsonl
fi

The timeframe above is 2026-10-19 00:00 UTC to 2026-10-20 00:00 UTC. 

Upload, sanitize and review in LogTotal

  1. Upload. Open logtotal.com and drop in the file.
  2. Sanitize. 
  3. Review. 

When it goes wrong

SymptomLikely causeFix
401Key and key ID swapped, or the key expiredKey in Authorization, ID in x-xdr-auth-id
License errorNo XDR Pro licenseXQL APIs need XDR Pro
Quota errorsXQL quota used up, or more than four parallel queriesWait; narrow the query
Exactly 1,000 resultsStream not usedFetch the rest with the stream ID
Query errorsXQL syntaxTest in the Query Builder first

FAQ

Can I export incidents and alerts?

Yes, through separate incident and alert APIs. For LogTotal, export the telemetry behind them.

What about raw third-party logs?

If you ingest them into Cortex, they live in their own datasets and come out the same way.

Join SOC Prime's Detection as Code platform to improve visibility into threats most relevant to your business. To help you get started and drive immediate value, book a meeting now with SOC Prime experts.