Search Query API Reference
Query raw events in Log Management programmatically using the Quickwit-compatible multi-search endpoint.
Radiant Security exposes a Quickwit-compatible multi-search endpoint that lets you query raw events in Log Management programmatically. Requests are sent as NDJSON payloads over HTTPS and support both search queries (returning individual event records) and aggregation queries (returning counts and bucketed summaries). This reference covers authentication, request structure, query building blocks, response formats, and error handling.
Use the links below to jump to a section:
Prerequisites
Before using this API, you need:
A Radiant Security tenant with Log Management enabled.
A Radiant API bearer token. The token is available in the Grafana Security Ops - Raw Events data connector in the Radiant application.
Working knowledge of REST APIs, cURL or Postman, and JSON.
Familiarity with Elasticsearch or Quickwit query DSL.
Important Note: Store your API token in an environment variable or secrets manager. Never commit tokens to source control.
Authentication
All requests require a Bearer token in the Authorization header. Tokens are scoped to your tenant and issued by Radiant Security.
Endpoint and headers
Method
POST
Base URL
https://plugin.radiantsecurity.ai
Path
/quickwit-api-proxy/_msearch
Full URL
https://plugin.radiantsecurity.ai/quickwit-api-proxy/_msearch
Request headers
Authorization
Yes
Bearer token. Include a space between Bearer and the token value: Bearer 1234567890abcdefgh...
Content-Type
Yes
Must be application/x-ndjson.
x-rs-is-byob
Conditional
Set to true only if your tenant uses a customer-owned S3 bucket (BYOB) for Log Management storage. Otherwise, omit this header.
Request body format
The request body consists of exactly two JSON objects, each on its own line, separated by a single \n, with a trailing newline:
When using cURL, pass the body with --data-binary and either a $'...' string or a file to preserve newlines exactly.
Header line
The header line is the same for every request. The index array is intentionally empty - Radiant routes queries by the connector type specified inside the query string.
Body line fields
query
Yes
Query DSL object. Typically a bool.filter combining a time range and a query string filter.
size
Yes
Maximum hits to return. Set to 0 for aggregation-only queries.
sort
Yes
Sort descriptors. Always include rs_timestamp with "format": "epoch_nanos_int" and "order": "desc".
aggs or aggregations
No
Aggregation definitions for counts, bucketing, or statistics.
Query building blocks
Time range filter
Every query should include a time range on rs_timestamp. Timestamps must be ISO 8601 UTC strings.
gte
Greater than or equal to (start time).
lte
Less than or equal to (end time).
Query string filter
Use query_string to filter by connector type, event class, or any indexed field. Phrase values must be double-quoted.
Common patterns:
rs_connectorType:valuescopes results to a specific connector.A bare keyword (for example,
username) performs a full-text search across all fields.field:value1 OR field:value2applies OR logic between clauses.
Bool query (combining filters)
Wrap multiple filters in bool.filter to require all conditions simultaneously:
Sort
The recommended sort returns events in reverse chronological order. The secondary _doc sort ensures stable pagination:
Search requests
Use a search request to retrieve individual event records. Set size to the maximum number of hits you want returned (0–1000).
Request body
cURL examples
Searches for the keyword username across all events and fields within a time window. The x-rs-is-byob header indicates that Log Management storage uses a customer-owned S3 bucket. Omit this header if your tenant uses Radiant-managed storage.
Note: The \n character inside $'...' produces a literal newline in bash. The trailing \n after the body line is required.
Searches two fields combined with an AND operator. The inner \" delimiters require an additional escape (\\") because cURL executes inside a shell. This example uses Radiant-managed storage, so the x-rs-is-byob header is omitted.
Aggregation requests
Use an aggregation request to obtain counts or bucketed summaries without retrieving raw events. Set size to 0 to suppress hits.
Request body
cURL example
Note: For complex queries, write the NDJSON payload to a file and pass it with --data-binary @file.ndjson. This avoids shell-escaping mistakes.
Response format
All responses return JSON with a top-level responses array. Each element corresponds to one body line in the request.
Search response
responses[0].hits.total
Total matched event count. May be an integer or an object of the form {"value": N} — handle both.
responses[0].hits.hits
Array of matched events. Each element contains a _source with the raw event payload.
_source.rs_timestamp
Event timestamp in epoch nanoseconds (integer).
_source.rs_connectorType
Connector that ingested the event (for example, cisco_ise, okta).
Aggregation response
responses[0].aggregations.<name>
Aggregation results keyed by the name specified in aggs.
buckets[].key
The field value for this bucket.
buckets[].doc_count
Number of events in this bucket within the query window.
Python example
This example assumes an environment variable RADIANT_API_TOKEN set to your bearer token. The x-rs-is-byob header is set to true; remove it if your tenant uses Radiant-managed storage.
Best practices
Always include a time range. Queries without an
rs_timestamprange scan the entire dataset, run slowly, consume excess capacity, and may time out without returning results.Scope by connector. Add
rs_connectorType:<name>to limit results to the data source you need.Use exact matches for event types. Phrase-quote values such as
msg_class:"Certificate"to avoid partial matches.Set
size: 0for aggregation-only queries. Returning hits when you only need counts adds latency and wastes bandwidth.Pass complex payloads from a file. Use
--data-binary @file.ndjsonto avoid shell-escaping errors.Validate timestamp format. Range filter timestamps must be ISO 8601 UTC strings (
YYYY-MM-DDTHH:MM:SSZ). Epoch integers are not accepted in the range filter.Secure your API token. Never commit tokens to source control. Use environment variables or a secrets manager.
Error handling
200 OK
Request succeeded. Inspect responses[0] for results or query-level errors.
400 Bad Request
Malformed NDJSON or invalid query DSL. Confirm that exactly two lines are present and all JSON is valid.
401 Unauthorized
Missing or invalid bearer token.
403 Forbidden
Token is valid but lacks permission for this resource.
429 Too Many Requests
Rate limit exceeded. Back off and retry with exponential delay.
500 Internal Server Error
Backend error. Retry with exponential backoff and contact support if the issue persists.
Important Note: Always check the HTTP status code before parsing the response body. A 200 response can still contain a query-level error object inside responses[0] if the query DSL was accepted but failed during execution.
Support
For questions, issues, or access requests, contact your Radiant Security account team or open a support ticket through the Radiant Security portal.
Last updated
Was this helpful?