For the complete documentation index, see llms.txt. This page is also available as Markdown.

Investigate API user guide

Using the RUX Investigate (Metadata) API Manually (e.g., with Postman)

Please Note:

This only applies to the new Vectra AI experience (RUX).

Investigate API is currently in PREVIEW. Please provide feedback to your respective account teams.

Overview

The Vectra AI Investigations API (also called the Metadata API) enables you to run SQL-like queries directly against network metadata and cloud logs captured by your Vectra sensors. This is the same data that powers Vectra's built-in detections, giving you full access to underlying evidence for threat hunting, incident response, and ad-hoc investigation.

Key capabilities:

  • Query up to 14 days of raw network session data (connections, DNS, HTTP, TLS, SMB, Kerberos, LDAP, RDP, SSH, beacons, and more)

  • Query cloud audit logs: AWS CloudTrail, Azure ARM, Microsoft 365 (Entra ID, SharePoint, Exchange, Teams), and Entra ID sign-ins

  • Filter by host entity IDs, IP addresses, timestamps, protocol fields, MITRE technique indicators, and any field documented in the schema reference

  • Retrieve up to 10,000 rows per query with full pagination support

  • Use aggregation functions (COUNT, SUM, AVG, etc.) and grouping for statistical analysis

The API is asynchronous: you submit a query, receive a request_id, then poll for completion and retrieve paginated results.

Prerequisites & Authentication

What You Need

Item
Details

Vectra Brain URL

Your Vectra deployment URL, e.g., https://your-brain.vectra.ai

API Client Credentials

OAuth 2.0 Client ID and Client Secret (created in Vectra Admin → API Clients)

Access Token

Bearer token obtained via the OAuth token endpoint

Postman (optional)

Version 9+ recommended; import the collection or build requests manually

Obtaining an Access Token

The Investigations API uses OAuth 2.0 Bearer Token authentication. Obtain a token before making API calls.

Token endpoint:

Postman setup:

  1. Create a new request → set method to POST

  2. URL: https://{your-brain}/oauth2/token

  3. Body → select x-www-form-urlencoded and add:

Key
Value

grant_type

client_credentials

client_id

{your_client_id}

client_secret

{your_client_secret}

  1. Send the request. Copy the access_token value from the response.

Token response example:

json

Using the token in subsequent requests:

In Postman, go to the Authorization tab → select Bearer Token → paste the access token. Alternatively, add a header manually:

Tip: In Postman, store the token as a collection variable ({{access_token}}) and reference it with Bearer {{access_token}}. You can automate token refresh using a pre-request script.

How It Works — Submit, Poll, Retrieve

The Investigations API uses an asynchronous pattern. Queries may take several seconds or longer depending on data volume and time range.

Status values:

meta.query_status

Meaning

RUNNING

Query is actively executing — keep polling

SUCCESS

Query finished — data array contains your results

FAILED

Query failed — check the response body for error details (exact structure unconfirmed)

Recommended polling interval: 1–3 seconds. Most queries complete within 5–15 seconds.

Postman Automation Tip: Add this snippet to the Tests tab of your POST request to automatically capture the request_id into a collection variable:

javascript

Your GET request can then reference {{request_id}} in the URL path automatically — no manual copy/paste needed. See Appendix B for the full script.

API Reference

POST /api/v3.4/investigations/ — Submit a Query

Full URL: https://{your-brain}/api/v3.4/investigations/

Method: POST

Headers:

Header
Value

Authorization

Bearer {access_token}

Content-Type

application/json

Request body (JSON):

Field
Type
Required
Description

query

string

Yes

SQL-like query string. See Query Language Reference.

version

string

No

Query language version. Use "1.0" (default).

Example request body:

json

Success response — 200 OK:

json

Error responses:

HTTP Status
Cause

400 Bad Request

Invalid query syntax, unsupported clause, or missing ._all suffix on table name

401 Unauthorized

Missing or expired Bearer token

403 Forbidden

Token does not have Investigations API permission

429 Too Many Requests

Rate limit exceeded (5 POST requests/minute)

The API surfaces two distinct error patterns depending on when the error is detected.

Syntax errors — returned directly in the POST response (query fails to parse before execution):

json

Error field
Description

error.errorCode

SYNTAX_ERROR for parse failures

error.errorId

Unique ID for this error — include when reporting issues

error.extra[].line

Line number in the query where the error occurred

error.extra[].column

Character position of the error

error.extra[].offending_symbol

The token that triggered the parse failure

error.extra[].message

Human-readable description of the parse error

Common cause: Missing ._all suffix on a table name produces a SYNTAX_ERROR because the parser expects a . after the table name and encounters WHERE instead.

Runtime errors — returned in the GET response (query parses successfully but fails during execution):

json

Error field
Description

error.errorCode

DATABASE_ERROR for runtime failures

error.errorId

Unique ID for this error — include when reporting issues

error.extra[].column

The field name that caused the error

error.extra[].error_name

Specific error type (e.g. COLUMN_NOT_FOUND)

error.extra[].error_type

USER_ERROR indicates the query itself is the problem

Common error_name values for runtime errors:

error_name

column present

Meaning

COLUMN_NOT_FOUND

Yes — names the offending field

A field name in SELECT or WHERE does not exist in the table — check the schema reference for correct field names

TYPE_MISMATCH

No

A value, cast, or function argument has an incompatible type — check comparisons (e.g. string field vs. numeric literal), CAST expressions, and aggregate function inputs

GET /api/v3.4/investigations/{request_id}/ — Get Results

Full URL: https://{your-brain}/api/v3.4/investigations/{request_id}/

Method: GET

Headers:

Header
Value

Authorization

Bearer {access_token}

Query parameters:

Parameter
Type
Default
Description

page

integer

1

Page number (1-indexed)

page_size

integer

50

Rows per page (max 10,000)

Success response — 200 OK (completed):

json

Response fields:

Field
Location
Description

request_id

top level

Unique ID for this query job

data

top level

Array of result rows — your query results are here

meta.query_status

meta

"RUNNING" while executing, "SUCCESS" when complete

meta.num_rows_available

meta

Total rows returned by the query

meta.page

meta

Current page number

meta.page_size

meta

Rows returned on this page

meta.estimated_file_size_bytes

meta

Estimated size of the full result set in bytes

meta.columns

meta

Array of [column_name, [{type}, hint]] tuples describing the result schema

Checking for more pages: Compare meta.num_rows_available against meta.page_size. If num_rows_available > page_size, there are additional pages to retrieve. Increment the page parameter until you have collected all rows.

Still running — 202 OK:

json

Polling tip: The response structure is identical whether the query is running or complete — data and columns are simply empty arrays while the query is in progress. Poll until meta.query_status equals "SUCCESS" before reading data.

Failed query response (expected structure):

json

Query Language Reference

Table Naming Convention

All table names must end with the ._all suffix:

sql

Supported Clauses

Clause
Supported
Notes

SELECT

Use * or specific fields

FROM

One table per query (no JOIN)

WHERE

Standard filters + functions

ORDER BY

ASC or DESC

LIMIT

Recommended; maximum 10,000

GROUP BY

For aggregation queries

HAVING

Filter on aggregate results

UNION ALL

Combine results from multiple queries

Subqueries

Supported

JOIN

Not supported — use UNION ALL instead

Plain UNION

Use UNION ALL

INSERT / UPDATE / DELETE

Read-only API

Field Notation Rules

Struct fields must use dot-notation in WHERE and ORDER BY clauses. Using a flat field name in a filter position returns 400 Bad Request.

sql

Note: In SELECT, either form works — SELECT id.orig_h returns the column as orig_h in results.

Supported Functions

Aggregate functions: COUNT, MAX, MIN, SUM, AVG, STDDEV, STDDEV_SAMP, STDDEV_POP

String functions: LOWER, UPPER, LENGTH, ABS, CONCAT, CONTAINS, COALESCE

Time functions: DATE, NOW, DATE_ADD, DATE_DIFF, FROM_ISO8601_TIMESTAMP, FROM_UNIXTIME, TO_UNIXTIME

Regex functions: REGEXP_COUNT, REGEXP_EXTRACT_ALL, REGEXP_EXTRACT, REGEXP_LIKE, REGEXP_POSITION, REGEXP_REPLACE, REGEXP_SPLIT

Type casting: TRY_CAST, CAST

Array / predicate functions: ANY_MATCH, ALL_MATCH, DISTINCT, ARRAY_AGG, CARDINALITY

Common Time Filter Pattern

sql

Common Fields (All Network Tables)

Field
Type
Description

timestamp

timestamp

Record timestamp — always use this (not ts)

id.orig_h

string

Source (originator) IP address

id.orig_p

integer

Source port

id.resp_h

string

Destination (responder) IP address

id.resp_p

integer

Destination port

local_orig

boolean

true if source IP is internal

local_resp

boolean

true if destination IP is internal

orig_hostname.id

integer

Vectra host entity ID for source host

orig_hostname.name

string

Display name of source host

uid

string

Unique session ID

For complete field listings by table, see the Table Schema Reference.

Sample Queries

All samples below are formatted as complete Postman request bodies (JSON). Submit each as the body of POST /api/v3.4/investigations/.

Basic Queries

1. Recent Outbound Connections (Last 24 Hours)

Returns outbound sessions from internal hosts to external destinations.

json

2. DNS Queries from a Specific Host

Returns all DNS lookups made by a host identified by its IP address.

json

Replace 1.2.3.4 with the actual Vectra host IP.

3. HTTP Activity to a Suspicious Domain

Finds all HTTP requests to a specific host header value.

json

4. Failed Kerberos Authentication Attempts

Returns failed Kerberos events which may indicate brute force or password spraying.

json

5. Large Outbound Data Transfers

Identifies sessions where an internal host sent more than 10 MB to an external destination.

json

Advanced Queries

6. Top External Destinations by Connection Count

Aggregates outbound connections grouped by destination IP, ordered by volume. Useful for identifying beaconing or bulk data transfer patterns.

json

7. DNS Tunneling Indicators

Flags suspiciously long DNS query names (potential data exfiltration via DNS tunneling) combined with TXT record lookups.

json

8. Lateral Movement — Internal RDP Sessions

Finds RDP connections between internal hosts, a primary lateral movement indicator.

json

9. AWS IAM Changes in the Last 7 Days

Identifies mutating IAM API calls (user/role/policy changes) in AWS CloudTrail — a key persistence and privilege escalation indicator.

json

10. Entra ID Sign-ins from High-Risk Countries (UNION ALL)

Combines sign-in events from multiple high-risk geographic locations using UNION ALL.

json

Pagination — Retrieving Large Result Sets

When a query matches more rows than your page_size, results are split across multiple pages. Use the next_page field in the response to retrieve subsequent pages.

Step-by-Step Pagination in Postman

Step 1 — Submit the query (POST):

json

Step 2 — Poll for completion (GET):

Step 3 — Retrieve page 1 (GET):

Step 4 — Continue if next_page is not null:

Stop when you've collected all rows — compare meta.num_rows_available (total rows) against meta.page * meta.page_size. When the rows you've collected equals meta.num_rows_available, you're done.

Performance tip: Use a page_size of 500–1,000 for large result sets to balance payload size and number of round trips. Your results will be in the data array of each response.

Troubleshooting

Symptom
Likely Cause
Resolution

SYNTAX_ERROR in POST response

Missing ._all suffix — parser expects . before WHERE

Change FROM network.isession to FROM network.isession._all

SYNTAX_ERROR in POST response

Malformed SQL — bad clause order, unmatched quotes, unsupported keyword

Check extra[].offending_symbol and extra[].message for the exact location

COLUMN_NOT_FOUND in GET response

Field name doesn't exist in the table

Check the schema reference for correct field names — e.g. orig_ip_bytes not orig_bytes

COLUMN_NOT_FOUND in GET response

Flat field name used in WHERE clause

Change WHERE resp_h = '...' to WHERE id.resp_h = '...'

TYPE_MISMATCH in GET response

Incompatible types in a comparison, cast, or function

Check that field types match their usage — e.g. wrap array fields with CAST(... AS VARCHAR) before using REGEXP_LIKE, avoid comparing string fields to numeric literals

400 Bad Request

Unsupported clause (e.g., JOIN)

Remove JOIN; use UNION ALL to combine results from multiple queries

401 Unauthorized

Missing or expired token

Re-authenticate via POST /oauth2/token and update the Bearer token

403 Forbidden

Insufficient API client permissions

Ensure the API client has Investigations API access in Vectra Admin → API Clients

429 Too Many Requests

Rate limit exceeded

Wait 60 seconds before retrying; the limit is 5 POST requests/minute

error object present in GET response

Runtime error (e.g. bad field name)

Check error.extra[].error_name and error.extra[].column for the specific cause

Query returns 0 results

Time range too narrow or wrong table

Widen the time range; verify the correct table name in the schema reference

Query times out

Query spans too much data

Add a more specific WHERE clause to narrow the result set; reduce time range

Struct field returns null

External IP has no Vectra host record

orig_hostname / resp_hostname fields are null for external IPs — this is expected

UNION ALL returns duplicate columns

Column alias mismatch between branches

Ensure both SELECT branches have identical column count and matching aliases

Rate Limits & Constraints

Constraint
Value

POST requests (submit query)

5 per minute

Maximum rows per query

10,000

Maximum lookback period

14 days

Minimum polling interval

1 second (recommended: 2–3 seconds)

Authentication token lifetime

3,600 seconds (1 hour) — refresh before expiry

Bulk data retrieval: If you need more than 10,000 rows, split your query into multiple time windows and submit them sequentially. For example, query 4-hour windows over a 24-hour period to retrieve up to 60,000 rows total.

Appendix A — Where to Find Table Schemas

This guide covers the query mechanics and provides sample queries, but does not document every available table and field. Full schema documentation — including all available tables, field names, types, and example values — is maintained separately.

📄 See the Vectra Investigate API Query Schema Reference for complete field listings:

Investigate API metadata schema reference

Appendix B — Quick Reference: Endpoint Summary

Action
Method
Endpoint

Obtain access token

POST

https://{brain}/oauth2/token

Submit a query

POST

https://{brain}/api/v3.4/investigations/

Poll for results

GET

https://{brain}/api/v3.4/investigations/{request_id}/

Get page 2+

GET

https://{brain}/api/v3.4/investigations/{request_id}/?page=2&page_size=500

Appendix C — Postman Tests Script (Auto-Capture Request ID)

Paste the following into the Tests tab of your POST request in Postman to automatically store the returned request_id as a collection variable. This eliminates the need to manually copy the ID between requests.

javascript

How to set this up in Postman:

  1. Open your POST /api/v3.4/investigations/ request

  2. Click the Tests tab (next to Headers, Body, etc.)

  3. Paste the script above

  4. In your GET request URL, use: https://{{VECTRA_BRAIN}}/api/v3.4/investigations/{{request_id}}/

  5. Every time you run the POST request, request_id is automatically updated — then just send the GET request to poll for results

Collection variables to configure:

Variable
Example Value
Description

VECTRA_BRAIN

your-brain.vectra.ai

Your Vectra Brain hostname

VECTRA_TOKEN

eyJhbGci...

OAuth Bearer token (refresh every hour)

request_id

(auto-populated by test script)

Captured from POST response automatically

Token auto-refresh tip: Add a pre-request script to your collection to check token expiry and re-authenticate automatically if needed. Store the token expiry timestamp in a TOKEN_EXPIRY collection variable and compare against Date.now() before each request.


Vectra AI — Investigations API User Guide | Version 1.0 | March 2026

Last updated

Was this helpful?