Liberty91

Search.

Last updated 29 Jul 20263 min read

Search runs the same engine as the Event Search page in the platform, and returns the same thing it does: Threat Events, not individual reports. Ask for ransomware and you get the occurrences, each with its reporting attached, not four write-ups of the same breach.

Requires the search.read scope; running a search also requires threat-events.read, since the results are Threat Events. Listing and reading your saved searches needs search.read alone. These are POST because queries can be large, but they are reads, so a key with default (read-only) scopes can use them.

POST /api/v1/search/

curl -X POST "https://api.liberty91.com/api/v1/search/" \
  -H "X-API-Key: $LIBERTY91_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "free_text": "ransomware",
    "target_sectors": ["Healthcare"],
    "target_countries": ["DE", "NL"],
    "date_from": "2026-07-01T00:00:00Z"
  }'

Results use the Threat Event contract, cursor paginated, plus one extra key:

{
  "next": null,
  "previous": null,
  "results": [ /* Threat Events */ ],
  "unlinked_report_count": 2
}

unlinked_report_count is reports that matched but do not yet belong to a deduplicated occurrence. Without it, an empty results would be ambiguous between "nothing matched" and "things matched but are not yet grouped".

Criteria

FieldType
free_textstring
date_from, date_toISO 8601 datetime, inclusive
threat_actor_ids, malware_ids, vulnerability_ids, threat_cluster_idsUUID lists
asset_technology_ids, supplier_idsUUID lists
target_regions, target_countries, source_countries, target_states, target_sectorsstring lists
match_logicANY (default) or ALL
query_treeboolean condition groups, see below

Resolve names to ids first with the threat library (?name= or ?alias=).

Boolean queries

For questions the flat fields cannot express, send a query_tree. Conditions inside a group must all match; the query matches when any group matches.

Say you want healthcare occurrences in Germany, or anything involving a specific actor anywhere:

{
  "query_tree": {
    "op": "OR",
    "children": [
      {
        "op": "AND",
        "children": [
          {"field": "target_sector", "values": ["Healthcare"]},
          {"field": "target_country", "values": ["DE"]}
        ]
      },
      {
        "op": "AND",
        "children": [
          {"field": "threat_actor", "values": ["3e2d1c0b-..."]}
        ]
      }
    ]
  }
}

Several values inside one condition mean "any of these". A target_country condition listing DE and NL matches occurrences targeting either.

When query_tree is present it takes precedence over the flat fields, and they are not combined.

Note

Free text is capped at three leaves per query: each one triggers a broad scan. Exceeding the cap, the depth limit or the node limit returns a 400 naming the limit you hit.

Saved searches

Searches saved in the platform belong to the whole account, and you can read and run them over the API.

# what the team has saved
curl "https://api.liberty91.com/api/v1/searches/" -H "X-API-Key: $KEY"
 
# run one
curl -X POST "https://api.liberty91.com/api/v1/searches/$SEARCH_ID/run/" \
  -H "X-API-Key: $KEY"

Running a saved search executes its stored criteria and returns the same Threat-Event-shaped page as POST /search/. This is the clean way to schedule an analyst-authored query from your own tooling without duplicating the query in two places.

What search can reach

Search runs across the reporting you are entitled to. Sources you do not hold a licence or an upload for are not searchable by you, and an occurrence covered only by reporting you are not entitled to does not appear at all, the same boundary described on Threat Events.

Frequently asked questions

Does the search API return reports or occurrences?

Occurrences. Several reports about the same breach come back as one Threat Event, the same way the platform's own search behaves.

Can I run my saved searches over the API?

Yes. List them at /searches/ and run one with POST /searches/{id}/run/, which executes the stored criteria and returns Threat Events.

What does unlinked_report_count mean?

Reports that matched your query but do not yet belong to a deduplicated occurrence. It lets you tell "nothing matched" apart from "matches exist but are not yet grouped".

Was this page helpful?