superapi
Use the superapi operator to perform GET, POST, PUT, PATCH, and DELETE requests to internal ThreatStream API endpoints directly from the AQL Search interface and without additional authentication. The operator enables automation of data retrieval, updates, and bulk operations on ThreatStream. It supports flexible input specifications using fields from your pipeline, and allows you to explicitly define output fields and their types for correct parsing.
Before you begin
Before using the superapi operator, consider the following:
Fetching live data
To fetch data on the fly, always use the anomali_api_proxy placeholder table with the superapi operator.
anomali_api_proxy | superapi
Resource consumption
Running queries with a large number of response rows or extended time ranges can lead to excessive resource consumption on the API server. To avoid service disruption, use the superapi operator cautiously and limit both the scope and frequency of your requests.
Response size limit
The superapi operator tracks the cumulative size of all HTTP responses within a single query.
When the total exceeds 50 MB, the operator stops making additional API calls. Rows processed before the limit is reached return normally. Rows that would have been processed after the limit is reached receive a warning in their output instead of API results.
Consider the following example:
example_actors_list
| fields name as actor_name, id
| superapi endpoint='/api/v1/actor/<<id>>/tipreport/?limit=1000' input_fields='id'
| calc objects=json_extract(response_data, 'objects', ARRAY)
| mvexpand objects
| calc name=json_extract(objects_expanded, 'name')
| calc modified_ts=json_extract(objects_expanded, 'modified_ts')
| calc created_ts=json_extract(objects_expanded, 'created_ts')
| fields name, actor_name, id, modified_ts, created_ts
| where actor_name contains_ci ("APT27","APT28","APT34","APT41")
| sort modified_ts desc
In this query, the first line starts with a list of actors. Each row has an actor_name and an id. The superapi line then makes one HTTP API call per actor row, replacing <<id>> with the actor ID in that row.
For example, if the input table has the following rows:
| Row | actor_name | id | API call |
|---|---|---|---|
| 1 | APT27 | 101 | /api/v1/actor/101/tipreport/?limit=1000
|
| 2 | APT28 | 102 | /api/v1/actor/102/tipreport/?limit=1000
|
| 3 | APT34 | 103 | /api/v1/actor/103/tipreport/?limit=1000
|
Because the endpoint uses limit=1000, each call can return up to 1,000 threat bulletins for that actor. If those reports are large, each response can be several MB, and could therefore exceed the 50 MB limit.
Note: Because API calls are executed in parallel, the order in which rows are processed is non-deterministic. Once the limit is reached, the specific rows that are skipped may vary between runs.
When the limit is reached, Anomali Search displays the following warning:
API response size limit reached. Some results may be incomplete due to large API responses.
Skipped rows contain the following in their output:
{"warning": "API response size limit reached. Row skipped."}
Additionally, caching responses ensures completed requests are not reprocessed again for non-idempotent requests (POST/PATCH), preventing duplicate records.
Recommended Best Practice
If you see the limit warning, reduce the scope of your query using one or more of the following approaches:
-
Limit input rows. Add
| limit Nbefore| superapito cap the number of API calls made. For example:Copy| makeresults count=100
| streamstats count AS counter
| limit 20
| superapi endpoint='/api/v1/intelligence/?limit=1000&offset=<<counter>>' input_fields='counter' -
Use a smaller page size. Lower the
limit=parameter in your endpoint URL to reduce the size of each individual response. For example, uselimit=100instead oflimit=1000. -
Filter before the API call. Add
| whereconditions before| superapito reduce the number of rows that need API enrichment.
Syntax
superapi
endpoint = <string>
method = <string>
payload | body_content= <string>
output = <string>
output_types = <string>
endpoint
|
Specifies the endpoint used to search on ThreatStream. For a list of available ThreatStream API endpoints, refer to the ThreatStream API Reference Guide, which can be downloaded on the Downloads page.
|
method
|
Specifies the method to perform the request to ThreatStream. Default: |
payload | body_content
|
The When using the The For example, Copy
|
output
|
Specifies a comma-separated list of fields to extract from the response. These fields are included in the output of the operator. Key features:
You can extract every key in the hierarchy and get the count at the end of it in different output fields. The syntax for this is the following:
The final output to get the data in the hierarchy is as follows:
This output generates 4 fields:
|
output_types
|
Specifies a comma-separated list of field types corresponding to each output field defined in the output parameter. If the number of Supported TS API output types:
|
Examples
Example 1: Retrieve the first 20 threat intelligence entries with a confidence greater than 80 and a severity of “low".
anomali_api_proxy | superapi
endpoint = "/api/v2/intelligence?limit=20&&confidence__gt=80&severity=low"
method = get
output = "objects.{}.id as id, objects.{}.uuid as uuid, objects.{}.value as value, objects.{}.confidence as confidence, objects.{}.severity as severity, objects.{}.created_ts as created_ts"
output_types = "number,string,string,number,string,timestamp"
Example 2: Retrieve observables with private tags.
anomali_api_proxy | superapi
endpoint = "/api/v1/intelligence/?limit=1000&is_public=false&tags.tlp__isnull=false"
method = get
output = "objects.{}.id as id, objects.{}.value as value, objects.{}.itype as itype, objects.{}.confidence as confidence, objects.{}.severity as severity, objects.{}.tags.{}.name as tag_name, objects.{}.tags.{}.tlp as tag_tlp, objects.{}.created_ts as created_ts"
output_types = "number,string,string,number,string,string,string,timestamp"
Example 3: Combine lookup table results from multiple API endpoints.
ocsf | superapi endpoint = '/api/v1/xdr/event/lookup/test_table_iris' output='result.modified_ts as modified_ts, result.modified_by_user as modified_by' | calc source='test_table_iris' | appendtable [| superapi endpoint = '/api/v1/xdr/event/lookup/test_table_iris_passthrough' output='result.modified_ts as modified_ts, result.modified_by_user as modified_by' | calc source='test_table_iris_passthrough']
Example 4: Calls the XDR IOC exclusion list API endpoint and maps the response fields into the result set for each OCSF event.
ocsf | superapi endpoint='/api/v1/xdr/excludelist/ioc' output='{}.created_by as created_by,{}.created_ts as created_ts,{}.modified_by as modified_by,{}.modified_ts as modified_ts,{}.username as username,{}.value as value'