Skip to content
Try the API

cURL & jq

curl and jq are all you need to explore the Elastio API, script one-off exports or debug what another client is sending.

Export your tenant and a personal access token once per session. Keep the token out of your shell history by reading it from a prompt or a secrets manager.

Terminal window
export ELASTIO_TENANT="acme"
read -rs ELASTIO_TOKEN && export ELASTIO_TOKEN # paste the token, then Enter
export ELASTIO_BASE="https://${ELASTIO_TENANT}.app.elastio.com"

A small helper keeps commands short. --fail-with-body (curl 7.76+) makes curl exit non-zero on HTTP errors while still printing the error envelope.

Terminal window
elastio() {
local path="$1"; shift
curl -sS --fail-with-body "${ELASTIO_BASE}${path}" \
-H "Authorization: Bearer ${ELASTIO_TOKEN}" \
-H "Accept: application/json" "$@"
}

Check that it works by listing open incidents:

GET
/gateway/api/v2/incidentsList retained incident episodes
Try it
Terminal window
elastio "/gateway/api/v2/incidents?status=open&limit=5" | jq .

Incidents come back as { "total": …, "data": [ … ] }. Pull out what you need:

Terminal window
elastio "/gateway/api/v2/incidents?status=open&limit=50" \
| jq -r '.data[] | [.handle, .finding.severity, .finding.asset_name, .opened_at] | @tsv'

.finding can be null when the finding is no longer available, so a // "-" fallback keeps the output tidy:

Terminal window
elastio "/gateway/api/v2/incidents?status=open" \
| jq -r '.data[] | "\(.handle)\t\(.finding.severity // "-")\t\(.finding.title // "-")"'
GET
/gateway/api/v2/threatsList findings (v2)
Try it
Terminal window
elastio "/gateway/api/v2/threats?page_size=100" \
| jq '.data | group_by(.threat_kind) | map({threat_kind: .[0].threat_kind, rows: length})'

Let curl encode parameters instead of pasting them into the URL. -G turns --data-urlencode pairs into a query string:

Terminal window
elastio "/gateway/api/v2/incidents" -G \
--data-urlencode "status=open" \
--data-urlencode "severity=critical,high" \
--data-urlencode "search=prod-db"

Build bodies with jq -n so quoting and escaping are always right. This posts a test message through a Slack integration:

POST
/gateway/integration/v1/slack/{slack_id}/testPost a test message with this integration
Try it
Terminal window
SLACK_ID="3f8d2a6c-1b4e-4c7a-9e2d-7a5b1c9f0e43"
body=$(jq -n --arg channel "C0ADDKEPP8V" '{channel_id: $channel}')
elastio "/gateway/integration/v1/slack/${SLACK_ID}/test" \
-X POST -H "Content-Type: application/json" -d "$body"

Most list operations return one page at a time. Operations that use page_size and next_page_token return the next token in pagination.next_page_token; keep requesting until it is empty. This loop exports every finding for one hunt result as JSON Lines:

GET
/gateway/api/v1/scanjobs/{scanJobId}/threatsList what a hunt found
Try it
Terminal window
SCAN_JOB_ID="9b2f4c1e-6d7a-4e8b-a1c3-5f0e2d4b6a71"
token=""
while :; do
args=(-G --data-urlencode "page_size=100")
[[ -n "$token" ]] && args+=(--data-urlencode "next_page_token=${token}")
page=$(elastio "/gateway/api/v1/scanjobs/${SCAN_JOB_ID}/threats" "${args[@]}") || exit 1
jq -c '.data[]?' <<<"$page"
token=$(jq -r '.pagination.next_page_token // empty' <<<"$page")
[[ -z "$token" ]] && break
done > findings.jsonl

Not every operation paginates the same way. Some use pageSize / pageToken, a few use page_token, and others use limit / offset with a total count. Check the parameters of the operation in the API reference and see Pagination.

  • Single quotes stop expansion. -H 'Authorization: Bearer $ELASTIO_TOKEN' sends the literal text $ELASTIO_TOKEN. Use double quotes.
  • Unquoted URLs. & in an unquoted URL backgrounds the command and drops the rest of the query. Always quote URLs, or use -G --data-urlencode.
  • Raw page tokens. Tokens are opaque and can contain =, + or /. Pass them with --data-urlencode, as in the loop above, rather than pasting them into the URL.
  • Silent failures. Without --fail or --fail-with-body, curl exits 0 on a 401 or 500 and your script carries on with an error body. The gateway’s error envelope looks like { "status": 404, "error": "Not Found", "message": "…" }. See Errors.
  • Wrong host. The API lives on your tenant host, https://<tenant>.app.elastio.com, not on a shared domain.
  • Tokens in logs. curl -v prints the Authorization header. Redact it before you share output.