Skip to content

Document kuery (KQL) filtering and improve Fleet API page structure#7067

Open
charlotte-hoblik wants to merge 5 commits into
mainfrom
charlotte-Kuery-3401
Open

Document kuery (KQL) filtering and improve Fleet API page structure#7067
charlotte-hoblik wants to merge 5 commits into
mainfrom
charlotte-Kuery-3401

Conversation

@charlotte-hoblik

Copy link
Copy Markdown
Contributor

Summary

Adds KQL filtering guidance to the Fleet API page and brings the page in line with the how-to content type. Closes #3401.

Connected issue: #3401

kuery / KQL filtering (the issue)

  • New Filter results with KQL section: which list endpoints accept kuery, the saved-object field-prefix rule, a verified package_policies example, and links to the KQL reference. The API reference names kuery but never explains it or links out, this is the missing on-ramp.

Structure and navigation (applied the Elastic docs skills)

  • Rewrote the page opening to state purpose and scope, and added a description to the frontmatter (no longer duplicated by the intro).
  • Added a Before you begin prerequisites section, plus Next steps and Related pages sections.
  • Folded the standalone Authentication section into the prerequisites.

Copy edits throughout

  • Active voice, concision, and punctuation; removed the relative-time word "currently"; replaced a directional "previous example" reference with a direct link; fixed an unclosed quote in a curl example.
  1. Did you use a generative AI (GenAI) tool to assist in creating this contribution?
  • Yes
  • No
  1. If you answered "Yes" to the previous question, please specify the tool(s) and model(s) used (e.g., Google Gemini, OpenAI ChatGPT-4, etc.).

Tool(s) and model(s) used:
Claude Opus 4.8
Elastic docs review skills

@charlotte-hoblik charlotte-hoblik self-assigned this Jun 22, 2026
@charlotte-hoblik charlotte-hoblik added the documentation Improvements or additions to documentation label Jun 22, 2026
@charlotte-hoblik charlotte-hoblik requested a review from a team as a code owner June 22, 2026 17:33
@github-actions

Copy link
Copy Markdown
Contributor

Elastic Docs AI PR menu

Check the box to run an AI review for this pull request.

  • Review docs changes (docs-review). Status: not started.

Powered by GitHub Agentic Workflows and docs-actions. For more information, reach out to the docs team.

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

🔍 Preview links for changed docs

@github-actions

Copy link
Copy Markdown
Contributor

✅ Elastic Docs Style Checker (Vale)

No issues found on modified lines!


The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale.

Comment thread reference/fleet/fleet-api-docs.md Outdated
Comment thread reference/fleet/fleet-api-docs.md Outdated
Comment on lines +472 to +474
The {{fleet}} list endpoints for agents, agent policies, package policies, and enrollment tokens accept a `kuery` query parameter that takes a [{{kib}} Query Language (KQL)](elasticsearch://reference/query-languages/kql.md) string to filter results. To check whether another endpoint accepts `kuery`, refer to its parameters in the [Kibana API docs]({{kib-apis}}).

Reference each field by the saved object type that stores it. {{fleet}} stores package policies as `ingest-package-policies` objects, so to filter package policies by integration name, query the `ingest-package-policies.package.name` field.

@bmorelli25 bmorelli25 Jun 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure this isn't true. Agents and enrollment tokens are not saved objects. They are stored in .fleet-* system indices so they must be referenced directly with no saved object prefix.

Your example for package policies works in [redacted] test cluster (I'll share w/you on Slack).

GET kbn:/api/fleet/package_policies?kuery=ingest-package-policies.package.name:activemq

{
  "items": [
    {
      "id": "9xxxxa3-b6b2-4xxx-8f20-bb9822xxxxxe",
      "version": "WxxxxxxxxxQ==",
      "name": "activemq-1",
...

However, appending the saved object type to an agent call does not work:

GET kbn:/api/fleet/agents?kuery=ingest-agents.status:online
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "[request query.kuery]: KQLSyntaxError: This key 'ingest-agents.status' does NOT exist in fleet-agents saved object index patterns"
}

Excluding the saved object type from an agent call does work:

GET kbn:/api/fleet/agents?kuery=status:online

{
  "items": [
    {
      "id": "3xxxx1-4a0a-4b00-bxxxx20xxxxx9d4",
      "type": "PERMANENT",
      "active": true,
...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vishaangelova keep me honest here

@vishaangelova vishaangelova Jun 25, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so actually only these two Fleet endpoints are backed by saved objects:

  • Agent policies (GET /api/fleet/agent_policies): stored as a fleet-agent-policies saved object, or, on deployments where space awareness is off, as the legacy ingest-agent-policies saved object (#1 and #2).
    • Use fleet-agent-policies.<field> in the KQL prefix; the legacy ingest-agent-policies.<field> also works because Fleet normalizes either prefix at runtime (#3)
  • Package policies (GET /api/fleet/package_policies): stored as a fleet-package-policies saved object, or, on deployments where space awareness is off, as the legacy ingest-package-policies saved object (#1, and #2).
    • Use fleet-package-policies.<field>, but the legacy ingest-package-policies.<field> also works for the same reason as above (#3).

Agents (GET /api/fleet/agents) are stored in the .fleet-agents ES system index (#1). So these should be referenced without a prefix (e.g., status:online). However, here fleet-agents.status:online also works because Fleet strips it from the kuery (#2), but ingest-agents. does not exist, and that returns an error.

Enrollment API keys (GET /api/fleet/enrollment_api_keys) are stored in the .fleet-enrollment-api-keys ES system index (#1), but here no prefix should be used as the kuery is passed straight through to the index search (e.g., policy_id:"<policy-id>").

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much, both of you, this was really helpful. I tested it all on a 9.4.2 cluster and your breakdown held up, with one surprise.

fleet-agent-policies. doesn't actually work on 9.4.2. It 400s, and only ingest-agent-policies. or a bare name:"..." work, even though the data is stored under the fleet-* types (confirmed with a type agg on .kibana*).

In the doc I went with bare fields where possible, prefixed only nested fields like package.name, and added a tip that the KQLSyntaxError names the exact pattern to use.

@vishaangelova does fleet-agent-policies. work for you on main? Thanks again.

@bmorelli25 bmorelli25 Jun 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can confirm that fleet-agent-policies.name 400s and the following actually work:

GET kbn:/api/fleet/agent_policies?kuery=ingest-agent-policies.name:"Elastic Cloud agent policy"
GET kbn:/api/fleet/agent_policies?kuery=name:"Elastic Cloud agent policy"

Tested on 9.4.3 (unreleased)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @paul-tavares, pulling you in this thread to confirm if the way this works is by design:

On GET /api/fleet/agent_policies, the kuery validator rejects the fleet-agent-policies.<field> prefix (returns a 400 KQLSyntaxError), so only ingest-agent-policies.<field> or bare fields work. On GET /api/fleet/package_policies the validator was widened to accept both prefixes as part of elastic/kibana#227862, but the equivalent change doesn't seem to have been made for agent policies. Wondering if this was intentional, so we can document the right prefix?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, after checking with Paul, it seems maybe @criamico could help instead?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On GET /api/fleet/agent_policies, the kuery validator rejects the fleet-agent-policies. prefix (returns a 400 KQLSyntaxError), so only ingest-agent-policies. or bare fields work.

I just checked the code and verified that the KQL validator rejects any kuery prefixed with fleet-agent-policies. This was probably missed when doing the work for space awareness. It is actually a bug, so I'll open a ticket to track it.

Comment thread reference/fleet/fleet-api-docs.md Outdated
```

::::{tip}
The accepted saved object type prefix can differ across deployments and endpoints. If a query returns a `KQLSyntaxError` stating that a key does not exist in a saved object index pattern, use the index pattern named in the error as your prefix. For example, if the error names `ingest-agent-policies`, query `ingest-agent-policies.name`.

@bmorelli25 bmorelli25 Jun 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this tip but the current wording only handles the KQLSyntaxError that names the index pattern (for example, ingest-agents.status on the agents endpoint). Forgetting the prefix on a nested field produces a different error that does not have this pattern:

GET kbn:/api/fleet/package_policies?kuery=package.name:nginx
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "This type package is not allowed: Bad Request"
}

Here the parser reads package as a saved object type and rejects it, so there's no index pattern in the error to copy. Could we broaden the tip to cover both errors? Something like:

Suggested change
The accepted saved object type prefix can differ across deployments and endpoints. If a query returns a `KQLSyntaxError` stating that a key does not exist in a saved object index pattern, use the index pattern named in the error as your prefix. For example, if the error names `ingest-agent-policies`, query `ingest-agent-policies.name`.
If a query returns an error like `This type <x> is not allowed` or a `KQLSyntaxError` about a missing key, the field needs the saved object type as a prefix. If the error names an index pattern, use that; otherwise prefix with the endpoint's saved object type (for example, `ingest-package-policies` for package policies).

@bmorelli25 bmorelli25 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty! 🚢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feedback]: Kuery is nowhere described or explictily mapped or matched.

4 participants