From 0638aba6f7f26ec87ec94ecff42f3ee621b3e44d Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Wed, 12 Nov 2025 18:39:45 -0800 Subject: [PATCH 01/44] First pass Early Access doc --- api/early-access_API-Filtering.md | 161 ++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 api/early-access_API-Filtering.md diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md new file mode 100644 index 0000000000..c35e086e56 --- /dev/null +++ b/api/early-access_API-Filtering.md @@ -0,0 +1,161 @@ +# Advanced API Filtering (Preview) + +> **Status: In Progress** — This feature is under active development. Behavior, supported fields, and limits may change before General Availability (GA). This guide is provided as forward-looking context for evaluation and feedback. + +## Overview + +Advanced API filtering helps you quickly surface the resources that matter, using a server-side subset of the Common Expression Language (CEL) to evaluate expressions against each resource instance before results are returned. Using Advanced API Filtering helps avoid downloading large collections and filtering client-side, and helps make operational tooling faster and more precise. + +**Request shape** + +```http +GET /{resource}?filter='{CEL_EXPRESSION}' +``` + +Example: + +```http +GET /endpoints?filter='obj.type == "cloud" || obj.type == "agent"' +``` + +--- + +## Supported CEL (subset) + +The following core operators and helpers are supported for the initial release: +- Logical operators: `!`, `&&`, `||` +- Comparative operators: `<`, `<=`, `==`, `!=`, `>=`, `>` +- Parentheses for grouping +- List membership using the `in` keyword +- String substring checks: `startsWith()`, `contains()`, `endsWith()` +- Length / emptiness checks: `size()`, `== ""`, `== null` +- Date parsing: `datetime.parse()` + +### Instance Inspection (vs. List Comprehension) + +Expressions are evaluated against a single **resource instance** exposed as `obj`. Compare fields **on the instance** rather than attempting list-wise checks on fields. + +✅ Valid +```http +GET /endpoints?filter='obj.type == "cloud" || obj.type == "agent"' +GET /endpoints?filter='obj.type in ["agent", "cloud"]' +``` + +❌ Not valid +```http +GET /endpoints?filter='["agent","cloud"] in obj.types' +``` + +--- + +## Dates and time helpers + +- **Treat timestamps as numerics** by using `<`, `<=`, `==`, `>=`, `>` directly on timestamp fields. +- **Parsing:** `datetime.parse("")` to compare against string literals. +- **Convenience helpers:** `now()` and `daysAgo(n)` support concise relative filters, e.g.: + ```http + GET /endpoints?filter='obj.created_at >= daysAgo(7)' + ``` + +--- + +## Query restrictions and limitations + +### Unsupported CEL features (initial release) + +- **No index access** (e.g., `a[0]`) +- **No arithmetic** (e.g., `a + b`) +- **No ternary** (e.g., `cond ? x : y`) +- **No type checks** (e.g., `type(a) == string`) +- **No regexes** +- **No fuzzy matching** + +These exclusions intentionally keep evaluation small and predictable. + +### High-entropy fields and substring checks + +Substring functions (`startsWith()`, `contains()`, `endsWith()`) are **disallowed** on fields considered **high entropy** (values that are effectively random, where substring predicates add cost without meaningful benefit). **Identifiers are the canonical example** of high-entropy fields. Prefer equality on these fields (e.g., `obj.id == "ep_123"`). + +### Query complexity (budgeting/limits) + +Very large expressions can stress the query engine. The service may enforce **limits on the number of conditions per query** or similar throttles in the future. + +--- + +## Filterable resources and fields + +The initial release prioritizes the resource types and fields below. Field coverage is evolving and may change before GA. + +| Resource Type | Filterable Fields | +|---------------|-------------------| +| **Endpoints** | - `id`
- `created_at`
- `description`
- `metadata`
- `principal.id`
- `type`
- `binding`
- `url`
- `pooling_enabled`
- `scheme`
- `region` | +| **Reserved Addresses** | - `id`
- `created_at`
- `description`
- `metadata`
- `addr`
- `region` | +| **Reserved Domains** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain`
- `region`
- `cname_target`
- `certificate.id`
- `acme_challenge_cname_target` | +| **TLS Certificates** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_after`
- `not_before`
- `serial_number` | +| **Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_before`
- `not_after` | +| **IP Policies** | - `id`
- `created_at`
- `description`
- `metadata` | +| **IP Policy Rules** | - `id`
- `created_at`
- `description`
- `metadata`
- `ip_policy`
- `cidr`
- `action` | +| **Agent Ingress** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain` | +| **Tunnel Sessions** | - `id`
- `metadata`
- `agent_version`
- `ip`
- `os`
- `region`
- `started_at`
- `credential` | +| **Event Destinations** | - `id`
- `created_at`
- `description`
- `metadata` | +| **Event Subscriptions** | - `id`
- `created_at`
- `description`
- `metadata` | +| **IP Restrictions** | - `id`
- `created_at`
- `description`
- `metadata` | +| **API Keys** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id` | +| **SSH Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | +| **Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | +| **Service Users** | - `id`
- `created_at` | +| **SSH Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata` | +| **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | +| **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | + +--- + +## Usage examples + +**Filter endpoints by type and creation time** +```http +GET /endpoints?filter='obj.type == "cloud" && obj.created_at < "2025-10-31T09:23:45-07:00"' +# or using helpers +GET /endpoints?filter='obj.type == "cloud" && obj.created_at >= daysAgo(6)' +``` + +**Reserved domains by prefix** +```http +GET /reserved_domains?filter='obj.domain.startsWith("myapi.ngrok")' +``` + +**IP policy rules by CIDR and action** +```http +GET /ip_policy_rules?filter='obj.cidr.contains("1.1.0.0/16") && obj.action == "deny"' +``` + +**Credentials by owner with optional empty ACL** +```http +GET /credentials?filter='obj.owner_id == "usr_2tEpN0yrxDI4j8jVnhVRoTNN2Tx" && (obj.acl == null || obj.acl == "")' +``` + +**Complex nesting** +```http +GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (obj.created_at < "2025-05-10Z" && obj.description.contains("cowbell"))' +``` + +--- + +## Error handling + +Invalid filters return **HTTP 400** with a structured error body (category, status code, message, details). Example: + +```http +HTTP/1.1 400 Bad Request +Content-Type: application/json; charset=utf-8 +Cache-Control: no-store + +{ + "error_code": "invalid_cel_expression", + "status_code": 400, + "msg": "Invalid CEL query: unsupported field: endpoint.idk (must be endpoint.url, endpoint.id, endpoint.type, or endpoint.bindings).", + "details": { + "operation_id": "op_k23j45n134jkasdfk34jkjnlkjuhasdf" + } +} +``` From e9f71918f8b1c9305073839d3186a34265681c12 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 09:41:00 -0800 Subject: [PATCH 02/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index c35e086e56..d400825d45 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -1,4 +1,9 @@ -# Advanced API Filtering (Preview) +--- +title: Advanced API Filtering (Preview) +sidebarTitle: Advanced API Filtering +description: Learn how to use Advanced API to make operational tooling faster and more precise. +tag: Preview +--- > **Status: In Progress** — This feature is under active development. Behavior, supported fields, and limits may change before General Availability (GA). This guide is provided as forward-looking context for evaluation and feedback. From ab0643d4d6c11645003f7689c2583bf3151504c6 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 09:41:08 -0800 Subject: [PATCH 03/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index d400825d45..89a4470ba0 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -5,7 +5,9 @@ description: Learn how to use Advanced API to make operational tooling faster an tag: Preview --- -> **Status: In Progress** — This feature is under active development. Behavior, supported fields, and limits may change before General Availability (GA). This guide is provided as forward-looking context for evaluation and feedback. + +This feature is under active development. Behavior, supported fields, and limits may change before General Availability (GA). This guide is provided as forward-looking context for evaluation and feedback. + ## Overview From cdd5b83626b0829883ec398f384b2bb658e04dca Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 09:41:25 -0800 Subject: [PATCH 04/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 89a4470ba0..e277efadc8 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -9,7 +9,6 @@ tag: Preview This feature is under active development. Behavior, supported fields, and limits may change before General Availability (GA). This guide is provided as forward-looking context for evaluation and feedback. -## Overview Advanced API filtering helps you quickly surface the resources that matter, using a server-side subset of the Common Expression Language (CEL) to evaluate expressions against each resource instance before results are returned. Using Advanced API Filtering helps avoid downloading large collections and filtering client-side, and helps make operational tooling faster and more precise. From b0d65e61f9168e53ea901318c4984fdd2b5232e0 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:23:44 -0800 Subject: [PATCH 05/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index e277efadc8..e11a40d112 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -52,7 +52,6 @@ GET /endpoints?filter='obj.type in ["agent", "cloud"]' GET /endpoints?filter='["agent","cloud"] in obj.types' ``` ---- ## Dates and time helpers From 683ef3cb0c0789c73e0a3919064512e72787f5b1 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:24:12 -0800 Subject: [PATCH 06/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index e11a40d112..0b5929c117 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -12,18 +12,19 @@ This feature is under active development. Behavior, supported fields, and limits Advanced API filtering helps you quickly surface the resources that matter, using a server-side subset of the Common Expression Language (CEL) to evaluate expressions against each resource instance before results are returned. Using Advanced API Filtering helps avoid downloading large collections and filtering client-side, and helps make operational tooling faster and more precise. -**Request shape** +The following example request fetches a list of all your Cloud and Agent endpoints. ```http -GET /{resource}?filter='{CEL_EXPRESSION}' +GET /endpoints?filter='obj.type == "cloud" || obj.type == "agent"' ``` -Example: +## Request shape ```http -GET /endpoints?filter='obj.type == "cloud" || obj.type == "agent"' +GET /{resource}?filter='{CEL_EXPRESSION}' ``` + --- ## Supported CEL (subset) From ff3b077f1b15e95ce0ef8ed1f52c59840d40340c Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:24:29 -0800 Subject: [PATCH 07/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 0b5929c117..03357c2486 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -63,7 +63,6 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' GET /endpoints?filter='obj.created_at >= daysAgo(7)' ``` ---- ## Query restrictions and limitations From 980f6699498294893e4fb06f64e2bc92a5ed09e1 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:24:47 -0800 Subject: [PATCH 08/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 03357c2486..ceab852634 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -68,6 +68,8 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' ### Unsupported CEL features (initial release) +To keep filter evaluation small and predictable, the following CEL features will be excluded in the initial release of Advanced API Filtering. + - **No index access** (e.g., `a[0]`) - **No arithmetic** (e.g., `a + b`) - **No ternary** (e.g., `cond ? x : y`) From fb099300e0ffeef1b33e37b46543908dad145b80 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:24:55 -0800 Subject: [PATCH 09/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index ceab852634..823bcb774d 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -136,6 +136,9 @@ GET /reserved_domains?filter='obj.domain.startsWith("myapi.ngrok")' GET /ip_policy_rules?filter='obj.cidr.contains("1.1.0.0/16") && obj.action == "deny"' ``` +Reference: +- [`LIST /ip_policy_rules`](/api-reference/ippolicyrules/list) + **Credentials by owner with optional empty ACL** ```http GET /credentials?filter='obj.owner_id == "usr_2tEpN0yrxDI4j8jVnhVRoTNN2Tx" && (obj.acl == null || obj.acl == "")' From e9b669f1de261cef7f643af8d647ea984deb3f8e Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:25:38 -0800 Subject: [PATCH 10/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 823bcb774d..dbaffe0de6 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -81,7 +81,9 @@ These exclusions intentionally keep evaluation small and predictable. ### High-entropy fields and substring checks -Substring functions (`startsWith()`, `contains()`, `endsWith()`) are **disallowed** on fields considered **high entropy** (values that are effectively random, where substring predicates add cost without meaningful benefit). **Identifiers are the canonical example** of high-entropy fields. Prefer equality on these fields (e.g., `obj.id == "ep_123"`). +**High entropy** fields are fields with values that are effectively random, usually because they're generated. The `id` field on a response object, such as `obj.id`, is a common example. + +[Substring functions](https://github.com/google/cel-spec/blob/master/doc/langdef.md#string-functions), such as `startsWith()`, `contains()`, `endsWith()`, are **disallowed** on high entropy fields. Check for equality on these fields instead. For example, `obj.id == "ep_123"`. ### Query complexity (budgeting/limits) From d302e1b181c362a0e47f58d99a274901f56ca43b Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:25:44 -0800 Subject: [PATCH 11/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index dbaffe0de6..9305fefa55 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -146,6 +146,9 @@ Reference: GET /credentials?filter='obj.owner_id == "usr_2tEpN0yrxDI4j8jVnhVRoTNN2Tx" && (obj.acl == null || obj.acl == "")' ``` +Reference: +- [`LIST /credentials`](/api-reference/credentials/list) + **Complex nesting** ```http GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (obj.created_at < "2025-05-10Z" && obj.description.contains("cowbell"))' From c220aee2d19f2ba7c27d90a1a5e96935d3ee11c9 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:25:50 -0800 Subject: [PATCH 12/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 9305fefa55..bd2a48f603 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -154,6 +154,9 @@ Reference: GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (obj.created_at < "2025-05-10Z" && obj.description.contains("cowbell"))' ``` +Reference: +- [`LIST /agent_ingresses`](/api-reference/agentingresses/list) + --- ## Error handling From 4c28a9510bf4d2905a7defd332c6e56362f91799 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:26:02 -0800 Subject: [PATCH 13/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index bd2a48f603..fbf2f975dc 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -161,7 +161,7 @@ Reference: ## Error handling -Invalid filters return **HTTP 400** with a structured error body (category, status code, message, details). Example: +Invalid filters return **HTTP 400** with a structured error body (`category`, `status_code`, `message`, `details`). Example: ```http HTTP/1.1 400 Bad Request From 38a91a2b90e03770b680957fc6c6ff766af97c49 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 10:26:11 -0800 Subject: [PATCH 14/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index fbf2f975dc..baa61e662e 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -157,7 +157,6 @@ GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (o Reference: - [`LIST /agent_ingresses`](/api-reference/agentingresses/list) ---- ## Error handling From 0b44b5a5ea4c9c22c2112317c9c9415ebe607678 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 11:56:00 -0800 Subject: [PATCH 15/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index baa61e662e..9da5ceaf09 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -10,7 +10,9 @@ This feature is under active development. Behavior, supported fields, and limits -Advanced API filtering helps you quickly surface the resources that matter, using a server-side subset of the Common Expression Language (CEL) to evaluate expressions against each resource instance before results are returned. Using Advanced API Filtering helps avoid downloading large collections and filtering client-side, and helps make operational tooling faster and more precise. +When using ngrok's API, you can add the `filter` query parameter to your `GET` requests to ensure you receive a smaller payload tailored to your needs. This is called Advanced API Filtering, and it helps make operational tooling faster and more precise while eliminating the need to download large collections and filter client-side. + +To use Advanced API Filtering, you can pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. The following example request fetches a list of all your Cloud and Agent endpoints. From eeded62ff89f5368b3b82402d17ce28d7213983c Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 11:56:29 -0800 Subject: [PATCH 16/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 9da5ceaf09..23db858937 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -91,7 +91,6 @@ These exclusions intentionally keep evaluation small and predictable. Very large expressions can stress the query engine. The service may enforce **limits on the number of conditions per query** or similar throttles in the future. ---- ## Filterable resources and fields From 77637846632f676570ce463bec5093f4199f94d5 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 11:58:44 -0800 Subject: [PATCH 17/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 23db858937..faccc772f4 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -128,6 +128,8 @@ GET /endpoints?filter='obj.type == "cloud" && obj.created_at < "2025-10-31T09:23 # or using helpers GET /endpoints?filter='obj.type == "cloud" && obj.created_at >= daysAgo(6)' ``` +Reference: +- [`LIST /endpoints`](/api-reference/endpoints/list) **Reserved domains by prefix** ```http From efffffa1db0e31dad1ba78978a911c33bf936f96 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 11:59:09 -0800 Subject: [PATCH 18/44] Update api/early-access_API-Filtering.md Co-authored-by: Shaquil Hansford --- api/early-access_API-Filtering.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index faccc772f4..3a0d41ae62 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -136,6 +136,9 @@ Reference: GET /reserved_domains?filter='obj.domain.startsWith("myapi.ngrok")' ``` +Reference: +- [`LIST /reserved_domains`](/api-reference/reserveddomains/list) + **IP policy rules by CIDR and action** ```http GET /ip_policy_rules?filter='obj.cidr.contains("1.1.0.0/16") && obj.action == "deny"' From c3211c80558b6af526756dda93a74a456715b876 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:01:31 -0800 Subject: [PATCH 19/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 3a0d41ae62..42ef67815c 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -122,7 +122,7 @@ The initial release prioritizes the resource types and fields below. Field cover ## Usage examples -**Filter endpoints by type and creation time** +### **Filter endpoints by type and creation time** ```http GET /endpoints?filter='obj.type == "cloud" && obj.created_at < "2025-10-31T09:23:45-07:00"' # or using helpers From a4810885811473a92d8764d0dea5a29ad7eb32b5 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:01:38 -0800 Subject: [PATCH 20/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 42ef67815c..de598b892c 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -131,7 +131,7 @@ GET /endpoints?filter='obj.type == "cloud" && obj.created_at >= daysAgo(6)' Reference: - [`LIST /endpoints`](/api-reference/endpoints/list) -**Reserved domains by prefix** +### **Reserved domains by prefix** ```http GET /reserved_domains?filter='obj.domain.startsWith("myapi.ngrok")' ``` From e1c88dfcc0e031ee742cc0b4a0b7c1703f887085 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:01:45 -0800 Subject: [PATCH 21/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index de598b892c..7dc14bc80f 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -139,7 +139,7 @@ GET /reserved_domains?filter='obj.domain.startsWith("myapi.ngrok")' Reference: - [`LIST /reserved_domains`](/api-reference/reserveddomains/list) -**IP policy rules by CIDR and action** +### **IP policy rules by CIDR and action** ```http GET /ip_policy_rules?filter='obj.cidr.contains("1.1.0.0/16") && obj.action == "deny"' ``` From 38cb23bffe940037642c2ac3e326d1a997e84d4f Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:01:58 -0800 Subject: [PATCH 22/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 7dc14bc80f..de68cbaa01 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -147,7 +147,7 @@ GET /ip_policy_rules?filter='obj.cidr.contains("1.1.0.0/16") && obj.action == "d Reference: - [`LIST /ip_policy_rules`](/api-reference/ippolicyrules/list) -**Credentials by owner with optional empty ACL** +### **Credentials by owner with optional empty ACL** ```http GET /credentials?filter='obj.owner_id == "usr_2tEpN0yrxDI4j8jVnhVRoTNN2Tx" && (obj.acl == null || obj.acl == "")' ``` From 3efb28727f7d1cf39b61c9cfc3ec1ad88e3c7cac Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:02:04 -0800 Subject: [PATCH 23/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index de68cbaa01..36ef9fb978 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -155,7 +155,7 @@ GET /credentials?filter='obj.owner_id == "usr_2tEpN0yrxDI4j8jVnhVRoTNN2Tx" && (o Reference: - [`LIST /credentials`](/api-reference/credentials/list) -**Complex nesting** +### **Complex nesting** ```http GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (obj.created_at < "2025-05-10Z" && obj.description.contains("cowbell"))' ``` From 53c24f77e11f00a74dc89f419a54347e4d3f7c79 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:03:41 -0800 Subject: [PATCH 24/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 36ef9fb978..a2609b941c 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -27,7 +27,6 @@ GET /{resource}?filter='{CEL_EXPRESSION}' ``` ---- ## Supported CEL (subset) From 635b733315df040f3fe3567f6206048fd286b46f Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:03:58 -0800 Subject: [PATCH 25/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index a2609b941c..c537a484c2 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -27,7 +27,6 @@ GET /{resource}?filter='{CEL_EXPRESSION}' ``` - ## Supported CEL (subset) The following core operators and helpers are supported for the initial release: From 87190403dc011a9cbd43922ce88117cfd833b477 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:04:17 -0800 Subject: [PATCH 26/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index c537a484c2..8f341b634c 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -26,7 +26,6 @@ GET /endpoints?filter='obj.type == "cloud" || obj.type == "agent"' GET /{resource}?filter='{CEL_EXPRESSION}' ``` - ## Supported CEL (subset) The following core operators and helpers are supported for the initial release: From 5b5cab52de5a29b2b66825704bb6fa8030038c61 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:04:38 -0800 Subject: [PATCH 27/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 8f341b634c..c726c20005 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -52,7 +52,6 @@ GET /endpoints?filter='obj.type in ["agent", "cloud"]' GET /endpoints?filter='["agent","cloud"] in obj.types' ``` - ## Dates and time helpers - **Treat timestamps as numerics** by using `<`, `<=`, `==`, `>=`, `>` directly on timestamp fields. From 1affd10389f4b1b20d6bcc62dd1eab9f558cf0cf Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:04:52 -0800 Subject: [PATCH 28/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index c726c20005..56d216cdfc 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -61,7 +61,6 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' GET /endpoints?filter='obj.created_at >= daysAgo(7)' ``` - ## Query restrictions and limitations ### Unsupported CEL features (initial release) From 5f605ec700f75e732e0006d7966d11b938f646c2 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:05:42 -0800 Subject: [PATCH 29/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 1 - 1 file changed, 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 56d216cdfc..eecf03ebb3 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -113,7 +113,6 @@ The initial release prioritizes the resource types and fields below. Field cover | **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | | **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | ---- ## Usage examples From 17db8d0ccc6a8f5fdb06f9b8e89f9f390d8a11a3 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:10:37 -0800 Subject: [PATCH 30/44] Newline formatting --- api/early-access_API-Filtering.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index eecf03ebb3..99f9777c7e 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -9,7 +9,6 @@ tag: Preview This feature is under active development. Behavior, supported fields, and limits may change before General Availability (GA). This guide is provided as forward-looking context for evaluation and feedback. - When using ngrok's API, you can add the `filter` query parameter to your `GET` requests to ensure you receive a smaller payload tailored to your needs. This is called Advanced API Filtering, and it helps make operational tooling faster and more precise while eliminating the need to download large collections and filter client-side. To use Advanced API Filtering, you can pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. @@ -86,7 +85,6 @@ These exclusions intentionally keep evaluation small and predictable. Very large expressions can stress the query engine. The service may enforce **limits on the number of conditions per query** or similar throttles in the future. - ## Filterable resources and fields The initial release prioritizes the resource types and fields below. Field coverage is evolving and may change before GA. @@ -113,7 +111,6 @@ The initial release prioritizes the resource types and fields below. Field cover | **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | | **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | - ## Usage examples ### **Filter endpoints by type and creation time** @@ -157,7 +154,6 @@ GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (o Reference: - [`LIST /agent_ingresses`](/api-reference/agentingresses/list) - ## Error handling Invalid filters return **HTTP 400** with a structured error body (`category`, `status_code`, `message`, `details`). Example: From ed362269189787103d91ed32563d085bb8fb8f6e Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 12:13:32 -0800 Subject: [PATCH 31/44] Add date comparison example --- api/early-access_API-Filtering.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 99f9777c7e..4a60be6c6c 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -53,8 +53,11 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' ## Dates and time helpers -- **Treat timestamps as numerics** by using `<`, `<=`, `==`, `>=`, `>` directly on timestamp fields. -- **Parsing:** `datetime.parse("")` to compare against string literals. +- **Treat timestamps as numerics** by using `<`, `<=`, `==`, `>=`, `>` directly on timestamp fields, e.g.: + ```http + GET /vaults?filter=’obj.created_at < “2025-10-31T09:23:45-07:00”’ + ``` +- **Parsing:** `datetime.parse("")` to compare against string literals. - **Convenience helpers:** `now()` and `daysAgo(n)` support concise relative filters, e.g.: ```http GET /endpoints?filter='obj.created_at >= daysAgo(7)' From 17af48b2d03892db4fbc7c118ac5a61552a1dd83 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 17:44:12 -0800 Subject: [PATCH 32/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 4a60be6c6c..49d55b9fc0 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -34,7 +34,7 @@ The following core operators and helpers are supported for the initial release: - List membership using the `in` keyword - String substring checks: `startsWith()`, `contains()`, `endsWith()` - Length / emptiness checks: `size()`, `== ""`, `== null` -- Date parsing: `datetime.parse()` +- Date parsing: `timestamp(RFC-3339)` ### Instance Inspection (vs. List Comprehension) From 5ef721958d91b1e5742db381c53067c6c50e51ef Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 17:46:14 -0800 Subject: [PATCH 33/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 49d55b9fc0..18479e97f1 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -55,7 +55,7 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' - **Treat timestamps as numerics** by using `<`, `<=`, `==`, `>=`, `>` directly on timestamp fields, e.g.: ```http - GET /vaults?filter=’obj.created_at < “2025-10-31T09:23:45-07:00”’ + GET /vaults?filter=’obj.created_at < timestamp(“2025-10-31T09:23:45-07:00”)’ ``` - **Parsing:** `datetime.parse("")` to compare against string literals. - **Convenience helpers:** `now()` and `daysAgo(n)` support concise relative filters, e.g.: From 4cb4faa63855b0b78d49856f2149d1f346f9369f Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 17:46:24 -0800 Subject: [PATCH 34/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 18479e97f1..ddacfe8e95 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -151,7 +151,7 @@ Reference: ### **Complex nesting** ```http -GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (obj.created_at < "2025-05-10Z" && obj.description.contains("cowbell"))' +GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (obj.created_at < timestamp("2025-05-10Z") && obj.description.contains("cowbell"))' ``` Reference: From 37445af026276fd1498d434736569221ae35ff51 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 17:46:31 -0800 Subject: [PATCH 35/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index ddacfe8e95..4f010dae29 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -118,7 +118,7 @@ The initial release prioritizes the resource types and fields below. Field cover ### **Filter endpoints by type and creation time** ```http -GET /endpoints?filter='obj.type == "cloud" && obj.created_at < "2025-10-31T09:23:45-07:00"' +GET /endpoints?filter='obj.type == "cloud" && obj.created_at < timestamp("2025-10-31T09:23:45-07:00")' # or using helpers GET /endpoints?filter='obj.type == "cloud" && obj.created_at >= daysAgo(6)' ``` From c675f8f77bc85e1dbb70c822e63d1a2305c7d76f Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 17:46:38 -0800 Subject: [PATCH 36/44] Update api/early-access_API-Filtering.md --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 4f010dae29..f20be94dac 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -57,7 +57,7 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' ```http GET /vaults?filter=’obj.created_at < timestamp(“2025-10-31T09:23:45-07:00”)’ ``` -- **Parsing:** `datetime.parse("")` to compare against string literals. +- **Parsing:** `timestamp("RFC-3339")` to compare against string literals. - **Convenience helpers:** `now()` and `daysAgo(n)` support concise relative filters, e.g.: ```http GET /endpoints?filter='obj.created_at >= daysAgo(7)' From 89c411463b176630777ba1e8b6bee552174a9d65 Mon Sep 17 00:00:00 2001 From: "b.meltongrace" Date: Fri, 14 Nov 2025 01:57:58 +0000 Subject: [PATCH 37/44] fmt --- api/early-access_API-Filtering.md | 58 +++++++++++++++++++------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index f20be94dac..d2cf6b315d 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -11,7 +11,7 @@ This feature is under active development. Behavior, supported fields, and limits When using ngrok's API, you can add the `filter` query parameter to your `GET` requests to ensure you receive a smaller payload tailored to your needs. This is called Advanced API Filtering, and it helps make operational tooling faster and more precise while eliminating the need to download large collections and filter client-side. -To use Advanced API Filtering, you can pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. +To use Advanced API Filtering, you can pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. The following example request fetches a list of all your Cloud and Agent endpoints. @@ -28,6 +28,7 @@ GET /{resource}?filter='{CEL_EXPRESSION}' ## Supported CEL (subset) The following core operators and helpers are supported for the initial release: + - Logical operators: `!`, `&&`, `||` - Comparative operators: `<`, `<=`, `==`, `!=`, `>=`, `>` - Parentheses for grouping @@ -41,12 +42,14 @@ The following core operators and helpers are supported for the initial release: Expressions are evaluated against a single **resource instance** exposed as `obj`. Compare fields **on the instance** rather than attempting list-wise checks on fields. ✅ Valid + ```http GET /endpoints?filter='obj.type == "cloud" || obj.type == "agent"' GET /endpoints?filter='obj.type in ["agent", "cloud"]' ``` ❌ Not valid + ```http GET /endpoints?filter='["agent","cloud"] in obj.types' ``` @@ -92,69 +95,80 @@ Very large expressions can stress the query engine. The service may enforce **li The initial release prioritizes the resource types and fields below. Field coverage is evolving and may change before GA. -| Resource Type | Filterable Fields | -|---------------|-------------------| -| **Endpoints** | - `id`
- `created_at`
- `description`
- `metadata`
- `principal.id`
- `type`
- `binding`
- `url`
- `pooling_enabled`
- `scheme`
- `region` | -| **Reserved Addresses** | - `id`
- `created_at`
- `description`
- `metadata`
- `addr`
- `region` | -| **Reserved Domains** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain`
- `region`
- `cname_target`
- `certificate.id`
- `acme_challenge_cname_target` | -| **TLS Certificates** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_after`
- `not_before`
- `serial_number` | -| **Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_before`
- `not_after` | -| **IP Policies** | - `id`
- `created_at`
- `description`
- `metadata` | -| **IP Policy Rules** | - `id`
- `created_at`
- `description`
- `metadata`
- `ip_policy`
- `cidr`
- `action` | -| **Agent Ingress** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain` | -| **Tunnel Sessions** | - `id`
- `metadata`
- `agent_version`
- `ip`
- `os`
- `region`
- `started_at`
- `credential` | -| **Event Destinations** | - `id`
- `created_at`
- `description`
- `metadata` | -| **Event Subscriptions** | - `id`
- `created_at`
- `description`
- `metadata` | -| **IP Restrictions** | - `id`
- `created_at`
- `description`
- `metadata` | -| **API Keys** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id` | -| **SSH Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | -| **Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | -| **Service Users** | - `id`
- `created_at` | -| **SSH Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata` | -| **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | -| **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | +| Resource Type | Filterable Fields | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Endpoints** | - `id`
- `created_at`
- `description`
- `metadata`
- `principal.id`
- `type`
- `binding`
- `url`
- `pooling_enabled`
- `scheme`
- `region` | +| **Reserved Addresses** | - `id`
- `created_at`
- `description`
- `metadata`
- `addr`
- `region` | +| **Reserved Domains** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain`
- `region`
- `cname_target`
- `certificate.id`
- `acme_challenge_cname_target` | +| **TLS Certificates** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_after`
- `not_before`
- `serial_number` | +| **Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_before`
- `not_after` | +| **IP Policies** | - `id`
- `created_at`
- `description`
- `metadata` | +| **IP Policy Rules** | - `id`
- `created_at`
- `description`
- `metadata`
- `ip_policy`
- `cidr`
- `action` | +| **Agent Ingress** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain` | +| **Tunnel Sessions** | - `id`
- `metadata`
- `agent_version`
- `ip`
- `os`
- `region`
- `started_at`
- `credential` | +| **Event Destinations** | - `id`
- `created_at`
- `description`
- `metadata` | +| **Event Subscriptions** | - `id`
- `created_at`
- `description`
- `metadata` | +| **IP Restrictions** | - `id`
- `created_at`
- `description`
- `metadata` | +| **API Keys** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id` | +| **SSH Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | +| **Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | +| **Service Users** | - `id`
- `created_at` | +| **SSH Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata` | +| **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | +| **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | ## Usage examples ### **Filter endpoints by type and creation time** + ```http GET /endpoints?filter='obj.type == "cloud" && obj.created_at < timestamp("2025-10-31T09:23:45-07:00")' # or using helpers GET /endpoints?filter='obj.type == "cloud" && obj.created_at >= daysAgo(6)' ``` + Reference: + - [`LIST /endpoints`](/api-reference/endpoints/list) ### **Reserved domains by prefix** + ```http GET /reserved_domains?filter='obj.domain.startsWith("myapi.ngrok")' ``` Reference: + - [`LIST /reserved_domains`](/api-reference/reserveddomains/list) ### **IP policy rules by CIDR and action** + ```http GET /ip_policy_rules?filter='obj.cidr.contains("1.1.0.0/16") && obj.action == "deny"' ``` Reference: + - [`LIST /ip_policy_rules`](/api-reference/ippolicyrules/list) ### **Credentials by owner with optional empty ACL** + ```http GET /credentials?filter='obj.owner_id == "usr_2tEpN0yrxDI4j8jVnhVRoTNN2Tx" && (obj.acl == null || obj.acl == "")' ``` Reference: + - [`LIST /credentials`](/api-reference/credentials/list) ### **Complex nesting** + ```http GET /agent_ingresses?filter='obj.domain in ["foo.com","bar.com","baz.com"] || (obj.created_at < timestamp("2025-05-10Z") && obj.description.contains("cowbell"))' ``` Reference: + - [`LIST /agent_ingresses`](/api-reference/agentingresses/list) ## Error handling From 190c5568f064bfd88953876abbdc08a95ab0f024 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 18:04:48 -0800 Subject: [PATCH 38/44] Clean up linebreak tags --- api/early-access_API-Filtering.md | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index d2cf6b315d..fff3d0575c 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -97,25 +97,25 @@ The initial release prioritizes the resource types and fields below. Field cover | Resource Type | Filterable Fields | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **Endpoints** | - `id`
- `created_at`
- `description`
- `metadata`
- `principal.id`
- `type`
- `binding`
- `url`
- `pooling_enabled`
- `scheme`
- `region` | -| **Reserved Addresses** | - `id`
- `created_at`
- `description`
- `metadata`
- `addr`
- `region` | -| **Reserved Domains** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain`
- `region`
- `cname_target`
- `certificate.id`
- `acme_challenge_cname_target` | -| **TLS Certificates** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_after`
- `not_before`
- `serial_number` | -| **Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_before`
- `not_after` | -| **IP Policies** | - `id`
- `created_at`
- `description`
- `metadata` | -| **IP Policy Rules** | - `id`
- `created_at`
- `description`
- `metadata`
- `ip_policy`
- `cidr`
- `action` | -| **Agent Ingress** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain` | -| **Tunnel Sessions** | - `id`
- `metadata`
- `agent_version`
- `ip`
- `os`
- `region`
- `started_at`
- `credential` | -| **Event Destinations** | - `id`
- `created_at`
- `description`
- `metadata` | -| **Event Subscriptions** | - `id`
- `created_at`
- `description`
- `metadata` | -| **IP Restrictions** | - `id`
- `created_at`
- `description`
- `metadata` | -| **API Keys** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id` | -| **SSH Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | -| **Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | -| **Service Users** | - `id`
- `created_at` | -| **SSH Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata` | -| **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | -| **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | +| **Endpoints** | - `id`
- `created_at`
- `description`
- `metadata`
- `principal.id`
- `type`
- `binding`
- `url`
- `pooling_enabled`
- `scheme`
- `region` | +| **Reserved Addresses** | - `id`
- `created_at`
- `description`
- `metadata`
- `addr`
- `region` | +| **Reserved Domains** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain`
- `region`
- `cname_target`
- `certificate.id`
- `acme_challenge_cname_target` | +| **TLS Certificates** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_after`
- `not_before`
- `serial_number` | +| **Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_before`
- `not_after` | +| **IP Policies** | - `id`
- `created_at`
- `description`
- `metadata` | +| **IP Policy Rules** | - `id`
- `created_at`
- `description`
- `metadata`
- `ip_policy`
- `cidr`
- `action` | +| **Agent Ingress** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain` | +| **Tunnel Sessions** | - `id`
- `metadata`
- `agent_version`
- `ip`
- `os`
- `region`
- `started_at`
- `credential` | +| **Event Destinations** | - `id`
- `created_at`
- `description`
- `metadata` | +| **Event Subscriptions** | - `id`
- `created_at`
- `description`
- `metadata` | +| **IP Restrictions** | - `id`
- `created_at`
- `description`
- `metadata` | +| **API Keys** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id` | +| **SSH Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | +| **Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | +| **Service Users** | - `id`
- `created_at` | +| **SSH Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata` | +| **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | +| **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | ## Usage examples From fca367806e02f52b4e1a93d911e9673188858669 Mon Sep 17 00:00:00 2001 From: "b.meltongrace" Date: Fri, 14 Nov 2025 02:06:25 +0000 Subject: [PATCH 39/44] fmt --- api/early-access_API-Filtering.md | 40 +++++++++++++++---------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index fff3d0575c..f45e312ba5 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -95,27 +95,27 @@ Very large expressions can stress the query engine. The service may enforce **li The initial release prioritizes the resource types and fields below. Field coverage is evolving and may change before GA. -| Resource Type | Filterable Fields | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Resource Type | Filterable Fields | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Endpoints** | - `id`
- `created_at`
- `description`
- `metadata`
- `principal.id`
- `type`
- `binding`
- `url`
- `pooling_enabled`
- `scheme`
- `region` | -| **Reserved Addresses** | - `id`
- `created_at`
- `description`
- `metadata`
- `addr`
- `region` | -| **Reserved Domains** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain`
- `region`
- `cname_target`
- `certificate.id`
- `acme_challenge_cname_target` | -| **TLS Certificates** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_after`
- `not_before`
- `serial_number` | -| **Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_before`
- `not_after` | -| **IP Policies** | - `id`
- `created_at`
- `description`
- `metadata` | -| **IP Policy Rules** | - `id`
- `created_at`
- `description`
- `metadata`
- `ip_policy`
- `cidr`
- `action` | -| **Agent Ingress** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain` | -| **Tunnel Sessions** | - `id`
- `metadata`
- `agent_version`
- `ip`
- `os`
- `region`
- `started_at`
- `credential` | -| **Event Destinations** | - `id`
- `created_at`
- `description`
- `metadata` | -| **Event Subscriptions** | - `id`
- `created_at`
- `description`
- `metadata` | -| **IP Restrictions** | - `id`
- `created_at`
- `description`
- `metadata` | -| **API Keys** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id` | -| **SSH Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | -| **Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | -| **Service Users** | - `id`
- `created_at` | -| **SSH Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata` | -| **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | -| **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | +| **Reserved Addresses** | - `id`
- `created_at`
- `description`
- `metadata`
- `addr`
- `region` | +| **Reserved Domains** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain`
- `region`
- `cname_target`
- `certificate.id`
- `acme_challenge_cname_target` | +| **TLS Certificates** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_after`
- `not_before`
- `serial_number` | +| **Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata`
- `subject_common_name`
- `not_before`
- `not_after` | +| **IP Policies** | - `id`
- `created_at`
- `description`
- `metadata` | +| **IP Policy Rules** | - `id`
- `created_at`
- `description`
- `metadata`
- `ip_policy`
- `cidr`
- `action` | +| **Agent Ingress** | - `id`
- `created_at`
- `description`
- `metadata`
- `domain` | +| **Tunnel Sessions** | - `id`
- `metadata`
- `agent_version`
- `ip`
- `os`
- `region`
- `started_at`
- `credential` | +| **Event Destinations** | - `id`
- `created_at`
- `description`
- `metadata` | +| **Event Subscriptions** | - `id`
- `created_at`
- `description`
- `metadata` | +| **IP Restrictions** | - `id`
- `created_at`
- `description`
- `metadata` | +| **API Keys** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id` | +| **SSH Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | +| **Credentials** | - `id`
- `created_at`
- `description`
- `metadata`
- `owner_id`
- `acl` | +| **Service Users** | - `id`
- `created_at` | +| **SSH Certificate Authorities** | - `id`
- `created_at`
- `description`
- `metadata` | +| **Vaults** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | +| **Secrets** | - `id`
- `created_at`
- `description`
- `metadata`
- `name` | ## Usage examples From 5de302a6d36df8e3db1810716ccc078e07aab0e5 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 18:38:10 -0800 Subject: [PATCH 40/44] Rebrand -> "API Filtering" --- api/early-access_API-Filtering.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index fff3d0575c..46668cb340 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -1,7 +1,7 @@ --- -title: Advanced API Filtering (Preview) -sidebarTitle: Advanced API Filtering -description: Learn how to use Advanced API to make operational tooling faster and more precise. +title: API Filtering (Preview) +sidebarTitle: API Filtering +description: Learn how to use API Filtering to make operational tooling faster and more precise. tag: Preview --- @@ -9,9 +9,9 @@ tag: Preview This feature is under active development. Behavior, supported fields, and limits may change before General Availability (GA). This guide is provided as forward-looking context for evaluation and feedback. -When using ngrok's API, you can add the `filter` query parameter to your `GET` requests to ensure you receive a smaller payload tailored to your needs. This is called Advanced API Filtering, and it helps make operational tooling faster and more precise while eliminating the need to download large collections and filter client-side. +When using ngrok's API, you can add the `filter` query parameter to your `GET` requests to ensure you receive a smaller payload tailored to your needs. This helps make operational tooling faster and more precise while eliminating the need to download large collections and filter client-side. -To use Advanced API Filtering, you can pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. +To use API Filtering, you can pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. The following example request fetches a list of all your Cloud and Agent endpoints. @@ -70,7 +70,7 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' ### Unsupported CEL features (initial release) -To keep filter evaluation small and predictable, the following CEL features will be excluded in the initial release of Advanced API Filtering. +To keep filter evaluation small and predictable, the following CEL features will be excluded in the initial release of API Filtering. - **No index access** (e.g., `a[0]`) - **No arithmetic** (e.g., `a + b`) From 8ac7beb2134e9f0caddf0e23469db0d6c6adeade Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 18:41:08 -0800 Subject: [PATCH 41/44] Remove mentions of 'initial release', as folks may overindex on this --- api/early-access_API-Filtering.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index f540fbd983..0af26c1926 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -27,7 +27,7 @@ GET /{resource}?filter='{CEL_EXPRESSION}' ## Supported CEL (subset) -The following core operators and helpers are supported for the initial release: +The following core operators and helpers are supported: - Logical operators: `!`, `&&`, `||` - Comparative operators: `<`, `<=`, `==`, `!=`, `>=`, `>` @@ -68,9 +68,9 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' ## Query restrictions and limitations -### Unsupported CEL features (initial release) +### Unsupported CEL features -To keep filter evaluation small and predictable, the following CEL features will be excluded in the initial release of API Filtering. +To keep filter evaluation small and predictable, the following CEL features are not supported. - **No index access** (e.g., `a[0]`) - **No arithmetic** (e.g., `a + b`) From f7b1a7a9b5d905dfddb6175c66dd0b8207c7f3f0 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 21:26:16 -0800 Subject: [PATCH 42/44] Conciseness, phrasing --- api/early-access_API-Filtering.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 0af26c1926..4c04663b05 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -9,11 +9,11 @@ tag: Preview This feature is under active development. Behavior, supported fields, and limits may change before General Availability (GA). This guide is provided as forward-looking context for evaluation and feedback. -When using ngrok's API, you can add the `filter` query parameter to your `GET` requests to ensure you receive a smaller payload tailored to your needs. This helps make operational tooling faster and more precise while eliminating the need to download large collections and filter client-side. +When using ngrok's API, you can add the `filter` query parameter to `GET` requests to return only those results which match a provided criteria. This makes automated management of resources easier while eliminating the need to download large collections and filter client-side. -To use API Filtering, you can pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. +To use API Filtering, you pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. -The following example request fetches a list of all your Cloud and Agent endpoints. +This example request fetches a list of all your Cloud and Agent endpoints. ```http GET /endpoints?filter='obj.type == "cloud" || obj.type == "agent"' @@ -27,7 +27,7 @@ GET /{resource}?filter='{CEL_EXPRESSION}' ## Supported CEL (subset) -The following core operators and helpers are supported: +These core operators and helpers are supported: - Logical operators: `!`, `&&`, `||` - Comparative operators: `<`, `<=`, `==`, `!=`, `>=`, `>` @@ -56,11 +56,10 @@ GET /endpoints?filter='["agent","cloud"] in obj.types' ## Dates and time helpers -- **Treat timestamps as numerics** by using `<`, `<=`, `==`, `>=`, `>` directly on timestamp fields, e.g.: +- **Treat timestamps as numerics** by using `<`, `<=`, `==`, `>=`, `>` directly on `timestamp()` fields, e.g.: ```http GET /vaults?filter=’obj.created_at < timestamp(“2025-10-31T09:23:45-07:00”)’ ``` -- **Parsing:** `timestamp("RFC-3339")` to compare against string literals. - **Convenience helpers:** `now()` and `daysAgo(n)` support concise relative filters, e.g.: ```http GET /endpoints?filter='obj.created_at >= daysAgo(7)' @@ -93,7 +92,7 @@ Very large expressions can stress the query engine. The service may enforce **li ## Filterable resources and fields -The initial release prioritizes the resource types and fields below. Field coverage is evolving and may change before GA. +The initial release prioritizes the resource types and fields below. CEL filtering is not supported on deprecated endpoints. Field coverage is evolving and may change before GA. | Resource Type | Filterable Fields | | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | From 4a39368f06402382e95f1392dafb8ec047580cd3 Mon Sep 17 00:00:00 2001 From: Brian Melton-Grace Date: Thu, 13 Nov 2025 21:27:33 -0800 Subject: [PATCH 43/44] clarity --- api/early-access_API-Filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/early-access_API-Filtering.md b/api/early-access_API-Filtering.md index 4c04663b05..e4628cdd18 100644 --- a/api/early-access_API-Filtering.md +++ b/api/early-access_API-Filtering.md @@ -11,7 +11,7 @@ This feature is under active development. Behavior, supported fields, and limits When using ngrok's API, you can add the `filter` query parameter to `GET` requests to return only those results which match a provided criteria. This makes automated management of resources easier while eliminating the need to download large collections and filter client-side. -To use API Filtering, you pass a server-side subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. +To use API Filtering, you pass a subset of CEL expressions to the `filter` query parameter, as demonstrated in the following example. This example request fetches a list of all your Cloud and Agent endpoints. From 81dec5ca2641f7fe9213c2b48861c0e44647980f Mon Sep 17 00:00:00 2001 From: Shaquil Hansford Date: Fri, 14 Nov 2025 10:29:16 -0500 Subject: [PATCH 44/44] Updating file name and navigation --- api/{early-access_API-Filtering.md => api-filtering.mdx} | 0 docs.json | 1 + 2 files changed, 1 insertion(+) rename api/{early-access_API-Filtering.md => api-filtering.mdx} (100%) diff --git a/api/early-access_API-Filtering.md b/api/api-filtering.mdx similarity index 100% rename from api/early-access_API-Filtering.md rename to api/api-filtering.mdx diff --git a/docs.json b/docs.json index 1d9128801a..3d0e5cf2a3 100644 --- a/docs.json +++ b/docs.json @@ -813,6 +813,7 @@ "openapi": "https://raw.githubusercontent.com/ngrok/ngrok-openapi/refs/heads/main/ngrok.yaml", "pages": [ "api/index", + "api/api-filtering", { "group": "Universal Gateway", "pages": [