Skip to content
Try the API

Build custom reports with EQL

Use EQL reporting to build custom reports beyond the fixed templates: describe what you want in plain language, get a validated EQL query back, preview the results, then save the report (as JSON or PDF) or run it on a schedule.

  • EQL needs the tenant’s eql-reporting feature and a dedicated EQL reader on the deployment. When it’s off, calls return 403.
  • The caller must be a tenant admin with universal API scope: issue the token with "all_scopes": true. See Automate personal access tokens.
  • Queries are validated and run with bounded limits. Requests are rate limited (the spec gives one active EQL request per tenant and ten attempts per tenant per minute), and a 429 means a budget was exceeded. Nothing is retried automatically.

The spec doesn’t publish an EQL grammar. The query language is documented in the Elastio console; over the API, a query is a string of up to 8,192 bytes sent in a query field. The practical way to get a valid query is the draft endpoint below, which turns a plain-language request into EQL and explains it. The examples on this page pass the drafted query through rather than hand-writing one.

The catalog lists the datasets you can query (with their columns), which optional features are available (aiAvailable for drafting, pdfAvailable, schedulesAvailable) and the limits that apply.

GET
/gateway/reporting/v1/eql/datasetsDiscover EQL datasets and capabilities
Try it
Terminal window
curl "https://acme.app.elastio.com/gateway/reporting/v1/eql/datasets" \
-H "Authorization: Bearer $ELASTIO_TOKEN"
{
"version": "…",
"aiAvailable": true,
"pdfAvailable": true,
"schedulesAvailable": true,
"datasets": [
{ "name": "…", "title": "…", "columns": ["…", "…"], "shape": "array", "platform": "…" }
],
"limits": { "maxRows": …, "maxQueryBytes": …, "maxResponseBytes": …, "maxPeriodDays": … }
}

Send a prompt (up to 4,000 bytes) and a past UTC period of at most 90 days. The service sends your request and the public catalog definitions to Azure OpenAI (not customer rows) and returns either compiled EQL (status: "ready") or a question to answer first (status: "clarification"). Drafting never runs, saves or schedules anything.

POST
/gateway/reporting/v1/eql/draftDraft EQL from a natural-language report request
Try it
Terminal window
curl -X POST "https://acme.app.elastio.com/gateway/reporting/v1/eql/draft" \
-H "Authorization: Bearer $ELASTIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Assets with active ransomware findings, grouped by AWS account",
"periodStart": "2026-09-12T00:00:00Z",
"periodEnd": "2026-10-12T00:00:00Z"
}'
{
"status": "ready",
"query": "…",
"explanation": "…",
"clarification": ""
}

Other responses to handle: 422 (the generated EQL didn’t pass validation; rephrase), 502 (the AI provider was unavailable or returned invalid output) and 503 (AI isn’t configured; aiAvailable is false).

Preview runs the query for a period and returns the rows inline without saving anything. Check truncated: if it’s true, the result hit the row or size limit.

POST
/gateway/reporting/v1/eql/queryPreview a bounded EQL report
Try it
Terminal window
# $QUERY holds the "query" string from the draft response
jq -n --arg q "$QUERY" '{query:$q, periodStart:"2026-09-12T00:00:00Z", periodEnd:"2026-10-12T00:00:00Z"}' |
curl -X POST "https://acme.app.elastio.com/gateway/reporting/v1/eql/query" \
-H "Authorization: Bearer $ELASTIO_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @-
{
"version": "…",
"columns": ["…", "…"],
"data": [ … ],
"rowCount": 42,
"truncated": false
}

When the preview looks right, save it. Saving takes the same body plus optional format (json or pdf) and description (up to 500 characters), and returns 202 while the report is generated. Poll GET /gateway/reporting/v1/eql/reports/{id} until status is ready or failed, then download the PDF if you asked for one.

POST
/gateway/reporting/v1/eql/reportsGenerate and save an EQL report
Try it
GET
/gateway/reporting/v1/eql/reports/{id}/pdfDownload a completed EQL PDF
Try it
Terminal window
ID=$(jq -n --arg q "$QUERY" '{query:$q, periodStart:"2026-09-12T00:00:00Z", periodEnd:"2026-10-12T00:00:00Z", format:"pdf", description:"Ransomware exposure by account"}' |
curl -s -X POST "https://acme.app.elastio.com/gateway/reporting/v1/eql/reports" \
-H "Authorization: Bearer $ELASTIO_TOKEN" -H "Content-Type: application/json" --data-binary @- | jq -r .id)
until [ "$(curl -s "https://acme.app.elastio.com/gateway/reporting/v1/eql/reports/$ID" \
-H "Authorization: Bearer $ELASTIO_TOKEN" | jq -r .status)" != "processing" ]; do sleep 10; done
curl "https://acme.app.elastio.com/gateway/reporting/v1/eql/reports/$ID/pdf" \
-H "Authorization: Bearer $ELASTIO_TOKEN" -o ransomware-exposure.pdf

The saved report includes the query it ran:

{
"id": "f0e1d2c3-b4a5-4968-8776-655443322110",
"title": "…",
"status": "ready",
"query": "…",
"format": "pdf",
"periodStart": "2026-09-12T00:00:00Z",
"periodEnd": "2026-10-12T00:00:00Z",
"createdAt": "2026-10-12T09:20:00Z",
"columns": ["…", "…"],
"shape": "array",
"rowCount": 42,
"data": [ … ]
}

Downloading the PDF before the report is ready returns 409. GET /gateway/reporting/v1/eql/reports?page=N lists saved reports with items, total, page and pageSize.

When schedulesAvailable is true, you can run a query on a cadence. name, template (always eql) and query are required. period, cadence and cadence_config work as for report schedules: period is last_24_hours, last_7_days, last_30_days or last_90_days; cadence is hourly, daily, weekly or monthly, with cadence_config shaped to match. format is json or pdf. The query is stored and revalidated each time the schedule fires. Results are saved as EQL reports only; email and webhook delivery aren’t supported.

POST
/gateway/reporting/v1/eql/schedulesSchedule an EQL report
Try it
Terminal window
jq -n --arg q "$QUERY" '{
name: "Monthly ransomware exposure",
template: "eql",
query: $q,
period: "last_30_days",
cadence: "monthly",
cadence_config: { day_of_month: 1, time_utc: "06:00" },
format: "pdf"
}' | curl -X POST "https://acme.app.elastio.com/gateway/reporting/v1/eql/schedules" \
-H "Authorization: Bearer $ELASTIO_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @-
{
"id": "a9b8c7d6-e5f4-4321-8a0b-1c2d3e4f5a6b",
"name": "Monthly ransomware exposure",
"template": "eql",
"period": "last_30_days",
"cadence": "monthly",
"cadence_config": { "day_of_month": 1, "time_utc": "06:00" },
"format": "pdf",
"enabled": true,
"created_at": "2026-10-12T09:30:00Z",
"created_by": "jane.doe@example.com",
"last_run_at": null,
"next_run_at": "2026-11-01T06:00:00Z",
"sync_status": "pending",
"query": "…"
}

To pause a schedule, send PATCH /gateway/reporting/v1/eql/schedules/{id} with {"enabled": false}. The same call can change the query or cadence.