---
id: filter-context
slug: /reference/query-grammar/filter-context
title: 'Filter Context'
description: 'The with parameter: assigning variables that filter expressions reference, and how its lexing rules differ from the filter language.'
sidebar_label: 'Filter Context'
sidebar_position: 4
tags: ['reference', 'query-grammar', 'filtering', 'variables', 'with']
---

The `with` parameter assigns values to the variables a
[filter expression](/reference/query-grammar/filter-expressions#variables)
references with `$NAME`. Agility calls this the **filter context**.

```text
filter_context_token  = [ assignment , { "|" , assignment } ] ;
assignment            = "$" , NAME , "=" , value , { "," , value } ;
value                 = ? any run of characters other than "," and "|" ? ;
```


## Assignment

Assignments are separated by `|`; the values within one assignment are separated
by `,`:

```text
&with=$Scope=Scope:0,Scope:1,Scope:2
&with=$Story=Story:3|$Scope=Scope:0,Scope:1,Scope:2
```


A variable holding several values behaves as a value list wherever it is used,
so `Scope=$Scope` against the assignment above means "Scope is any of
`Scope:0`, `Scope:1`, `Scope:2`".

## Worked Example

```text
GET /rest-1.v1/Data/Epic
    ?where=AssetState!='Closed';Scope=$Scope;-SuperAndUp[Scope=$Scope]
    &with=$Scope=Scope:0,Scope:1,Scope:2
```


`$Scope` is referenced twice — once at the top level and once inside a nested
inline filter — from a single assignment. The query reads "open Epics in any of
these three projects that are not contained by another Epic in those same
projects", i.e. the top-level Epics of that project set.

That reuse is the point of the feature. Without it you would repeat the OID list
in both places, and the two copies would drift.

:::warning Values in `with` are not quoted — unlike values in `where`
This is the difference that catches people. In `where`, every value is a quoted
string: `where=ToDo='0'`. In `with`, values are bare: `with=$Scope=Scope:0`.

The reason is in the grammar's own preamble: "The actual implementation of this
grammar is done with simple token splitting." `V1FilterContext.g` has to model
that with a lexer mode — `CONTEXT_VALUE` is defined as `~(',' | '|')*`, any run
of characters that is not a comma or a pipe. Quote marks are not delimiters
there; they are just more characters in the value.

So `with=$Scope='Scope:0'` assigns the eight-character string `'Scope:0'`,
apostrophes included, and the filter that compares against it silently matches
nothing.
:::

Two consequences of the same token-splitting rule:

- A value may contain spaces, colons, quotes and equals signs. Only `,` and `|`
  terminate it. (URL-encoding rules still apply on top of this — encode the
  parameter value as usual.)
- A value **cannot** contain a comma or a pipe, and there is no escape
  mechanism. If a value you need contains either character, `with` cannot carry
  it; inline the value in the filter expression instead, where quoting exists.

## What Can Be Assigned

The shipped examples all assign OIDs (`Scope:0`, `Story:3`). The grammar itself
places no constraint on the value beyond the delimiter rule, so plain scalars
also parse. Whether a given variable is meaningful in a given comparison depends
on the attribute it is compared against; that is not something the grammar
constrains, and no shipped example demonstrates a non-OID assignment. Treat
non-OID values as unverified.

`$` on its own — the context asset — is **not** assignable through `with`. It is
supplied by the query itself. `V1FilterContext.g` only produces
`VARIABLE_NAME`, which requires a name after the `$`.

## Where It Applies

Unlike `where`, filter context is applied to every query shape, including
single-asset requests: `AddQueryFilterContext` is called from `DoAssetQuery`,
`DoAssetTypeQuery` and `DoHistoricalAssetQuery` alike. That matters because a single-asset request can still
carry a `sel` containing inline filters that reference variables.

## Reserved Variables

Two variable names are supplied by the server rather than by your `with`
parameter:

- **`$` on its own is the asset itself.** In a filter that is evaluated
  against a concrete asset — a bracket filter on an
  [attribute path](/reference/query-grammar/attribute-paths), or the
  valid-values filters the schema defines — `$` resolves to that asset:

  ```text
  GET /rest-1.v1/Data/Scope/1067?sel=Members[Scopes=$].Name
  ```

  returns the members whose `Scopes` contain `Scope:1067`. A top-level
  `where` has no asset to refer to, and sending `$` there is a server
  error.

- **`$Search` is the current text search's result set.** When a request
  carries `find`, the matched asset IDs are bound to `$Search`, and a
  filter may reference them:

  ```text
  GET /rest-1.v1/Data/Story?find=login&findin=Name&where=ID=$Search&sel=Name&page=50,0
  ```

  The name is only defined while a `find` is present. Its value is the
  matched set itself, so the practical use is referencing search results
  from a *relation's* filter rather than the root asset's.

Assigning either name yourself in `with` is not supported — treat both as
reserved. A third server-supplied name, `#ContextOid`, belongs to the Bulk
API's create commands rather than to filters — see
[aliases and projection](/apis/asset-bulk/aliases-and-projection).

## Errors

A `with` value that fails to parse produces `400 Bad Request` with the message
`Invalid WITH parameter`. Note that because almost anything lexes as a
`CONTEXT_VALUE`, a malformed assignment is far more likely to produce a
successful query that matches nothing than an error. If a filter using a
variable returns an empty set, check the `with` value for stray quotes first.

## The `query.v1` Equivalent

`query.v1` carries the same concept as a mapping rather than a token, which
removes the quoting trap entirely:

```json
{
  "from": "Epic",
  "select": ["Number", "Name"],
  "filter": ["AssetState!='Closed';Scope=$Scope;-SuperAndUp[Scope=$Scope]"],
  "with": {
    "Scope": ["Scope:0", "Scope:1", "Scope:2"]
  }
}
```

The parser reads the mapping keys verbatim, so whether the key needs the
leading `$` is decided downstream — and is **not verifiable from the parser
alone**. The
example above omits it, matching how the reference in the filter expression
supplies the `$`. If a `query.v1` filter using a variable returns nothing, try
the key both ways.

## Related Topics

- [Filter expressions](/reference/query-grammar/filter-expressions)
- [Attribute paths](/reference/query-grammar/attribute-paths)
- [Grammar reference](/reference/query-grammar/ebnf)
