> ## Documentation Index
> Fetch the complete documentation index at: https://developers.bloobank.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Filtering (SFS-1)

> Full normative reference for the SFS-1 filter syntax used by every list endpoint.

Every list endpoint in the BlooBank API supports filtering via the `filter` query parameter. The syntax is **SFS-1 (Soluts Filter Syntax v1)** — a lightweight, predictable expression language designed for both API integrators and ad-hoc tooling.

This page is the **complete normative reference**. For an overview of when and how to use filters, see [Filtering concepts](/get-started/concepts/filtering).

## Restrictions in v1

SFS-1 intentionally supports **only `AND` logic**. The following are explicitly rejected with `INVALID_FILTER` (HTTP 400):

* `OR` operator
* `NOT` operator and negation with `-`
* Parentheses for grouping
* Functions `(call(arg...))`
* Wildcards `*` with special semantics
* Loose literals without a field (e.g., `Victor Hugo`)
* Collection-specific operators (`has`, `contains`, `any`)

Future versions of SFS may add `OR`, `NOT`, and parentheses without breaking v1 semantics.

## Request parameter

APIs adopting SFS expose exactly one filter field:

| Query parameter | Type     | Encoding               |
| --------------- | -------- | ---------------------- |
| `filter`        | `string` | URL-encoded (RFC 3986) |

```
GET /wallets/production-main/paymentOrders?filter=status%3DSUCCESS%20AND%20createdAt%3E%3D2026-01-01
```

Decoded:

```
status=SUCCESS AND createdAt>=2026-01-01
```

## Syntax

A filter is a list of comparisons joined by `AND`, `and`, or `;`.

**Comparison format:**

```
<field> <operator> <literal>
```

**Examples:**

* `status=ACTIVE;name=production-main`
* `status = SUCCESS AND createdAt >= 2026-01-01`
* `createdAt >= "2026-01-15T00:00:00Z" and direction = OUT`

### Field names

Field names are **explicitly allowlisted per endpoint**. Referencing a field not in the allowlist returns `INVALID_FILTER`. The allowlist is documented in each endpoint's reference page.

**Supported field types:**

| Type        | Notes                                 |
| ----------- | ------------------------------------- |
| `string`    | Unquoted (identifier-like) or quoted. |
| `number`    | Integer or floating-point.            |
| `boolean`   | `true`, `false`, `TRUE`, `FALSE`.     |
| `timestamp` | RFC 3339.                             |
| `enum`      | Allowlisted values; case-sensitive.   |

### Literals

| Form                  | Examples                                                |
| --------------------- | ------------------------------------------------------- |
| Unquoted strings      | `ACTIVE`, `SUCCESS`, `br.gov.bcb.pix`                   |
| Double-quoted strings | `"John Doe"`, `"ACME \"Corp\""`                         |
| Single-quoted strings | `'John Doe'`, `'a\'b'`                                  |
| Numbers               | `42`, `3.14`, `2.997e9`                                 |
| Booleans              | `true`, `false`, `TRUE`, `FALSE`                        |
| Null                  | `null`, `NULL`                                          |
| Timestamps (RFC 3339) | `"2026-01-15T10:30:00Z"`, `"2026-01-15T07:30:00-03:00"` |

**String escaping.** Inside a quoted string, `\` escapes the next character:

* `"a\"b"` resolves to `a"b`
* `'a\'b'` resolves to `a'b`

**Timestamp validation.** A `timestamp` literal must parse as RFC 3339. Failures return `INVALID_FILTER`.

### Operators

| Operator | Allowed on                 |
| -------: | -------------------------- |
|      `=` | All types                  |
|     `!=` | All types                  |
|      `<` | `number`, `timestamp` only |
|     `<=` | `number`, `timestamp` only |
|      `>` | `number`, `timestamp` only |
|     `>=` | `number`, `timestamp` only |

`string`, `boolean`, and `enum` types accept only `=` and `!=`. Using `<` / `<=` / `>` / `>=` on these types returns `UNSUPPORTED_FILTER_OPERATION`.

## Validation

Filters are fully schema-validated before execution.

* Only fields listed in the endpoint's allowlist are accepted.
* Each literal must be coercible to the declared field type.
* Enum fields only accept values from their allowed set.
* Operators must be compatible with the field type.
* Servers enforce limits on filter length, comparison count, and token count.

Any violation returns `INVALID_FILTER` or `UNSUPPORTED_FILTER_OPERATION` with HTTP 400.

## Examples

### Basic equality

```http theme={"dark"}
GET /wallets?filter=status=ACTIVE
```

### Multiple clauses (AND)

```http theme={"dark"}
GET /wallets?filter=status%3DACTIVE%20AND%20createdAt%3E%3D2026-01-01
```

Decoded: `status=ACTIVE AND createdAt>=2026-01-01`

### Numeric range

```http theme={"dark"}
GET /wallets/production-main/paymentOrders?filter=amount%3E%3D10000%3Bamount%3C100000
```

Decoded: `amount>=10000;amount<100000`

### Timestamp range

```http theme={"dark"}
GET /wallets/production-main/paymentOrders?filter=createdAt%3E%3D%222026-01-01T00%3A00%3A00Z%22
```

Decoded: `createdAt>="2026-01-01T00:00:00Z"`

### Enum + direction

```http theme={"dark"}
GET /wallets/production-main/paymentOrders?filter=direction%3DIN%20AND%20status%3DSUCCESS
```

Decoded: `direction=IN AND status=SUCCESS`

## Formal grammar (EBNF)

```ebnf theme={"dark"}
filter        = ws? expr ws? ;

expr          = comparison ( ws? logical_sep ws? comparison )* ;

logical_sep   = "AND" | "and" | ";" ;

comparison    = field ws? op ws? literal ;

field         = ident ( "." ident )* ;
ident         = ( ALPHA | "_" ) ( ALPHA | DIGIT | "_" )* ;

op            = "=" | "!=" | "<" | ">" | "<=" | ">=" ;

literal       = string | number | boolean | null_lit | bare_string ;
null_lit      = "null" | "NULL" ;
bare_string   = ident ;

string        = sq_string | dq_string ;
sq_string     = "'" { sq_char | escape } "'" ;
dq_string     = '"' { dq_char | escape } '"' ;
escape        = "\" ANY_CHAR ;
sq_char       = ANY_CHAR - "'" - "\" ;
dq_char       = ANY_CHAR - '"' - "\" ;

number        = [ "-" ] int_part [ frac_part ] [ exp_part ] ;
int_part      = DIGIT { DIGIT } ;
frac_part     = "." DIGIT { DIGIT } ;
exp_part      = ( "e" | "E" ) [ "+" | "-" ] DIGIT { DIGIT } ;

boolean       = "true" | "false" | "TRUE" | "FALSE" ;

ws            = " " | "\t" | "\r" | "\n" ;
```

## Errors

| Reason                         | When                                                                 |
| ------------------------------ | -------------------------------------------------------------------- |
| `INVALID_FILTER`               | Malformed syntax; unknown field; invalid literal; uncoercible value. |
| `UNSUPPORTED_FILTER_OPERATION` | Operator not allowed on the field's type (e.g., `<` on a string).    |

Both return HTTP 400. See [Errors](/api-reference/conventions/errors) for the full envelope contract.

## Versioning

SFS-1 guarantees only `AND` semantics and the six comparison operators. Future versions may add `OR`, `NOT`, and parentheses — those will be released as SFS-2 (or higher), additively, without changing v1 behavior.

## Next

<CardGroup cols={2}>
  <Card title="Filtering concepts" icon="filter" href="/get-started/concepts/filtering">
    When to filter, how to choose fields, performance considerations.
  </Card>

  <Card title="Pagination" icon="arrow-down" href="/api-reference/conventions/pagination">
    `filter` combines with `order_by`, `page_size`, `page_token`.
  </Card>
</CardGroup>
