# Filtern und Paginieren (https://developer.bimetrics.de/filtering)

Suchanfragen für Belege, Kontakte, Bankkonten, Umsätze und Buchungen.

Listen fragst du mit `POST` an eine Filterroute ab, zum Beispiel [`POST /api/document/filter`](https://developer.bimetrics.de/reference/documents/filter-documents.md). Der Body ist JSON und enthält einen Filterausdruck, die Sortierung und die Seite.

Beispiel für `POST /api/document/filter`:

```json
{
  "kind": "and",
  "children": [
    {
      "kind": "range",
      "attribute": "invoiceDate",
      "lower": "2026-01-01",
      "upper": "2026-12-31"
    }
  ],
  "limit": 50,
  "offset": 0,
  "sort": [
    "invoiceDate"
  ],
  "direction": [
    "desc"
  ]
}
```

Welche Attribute es je Route gibt, steht [weiter unten](#attribute-je-route), jeweils mit einem Beispiel.

## Filterausdruck

Ein Ausdruck hat eine Art (`kind`). Ausdrücke mit `and`, `or` und `not` enthalten weitere Ausdrücke in `children` und lassen sich verschachteln.

| Art (`kind`) | Bedeutung |
| --- | --- |
| `and` | Alle Teilausdrücke in `children` treffen zu. Ein leeres `children` liefert alle Einträge. |
| `or` | Mindestens ein Teilausdruck in `children` trifft zu. |
| `eq` | `attribute` hat genau den Wert `value`. |
| `not` | Verneint den Teilausdruck in `children`. Verwende genau einen Teilausdruck. |
| `in` | `attribute` enthält den Text `value`. Groß- und Kleinschreibung spielen keine Rolle. |
| `range` | `attribute` liegt zwischen `lower` und `upper`, beide Grenzen inklusive. Eine Grenze genügt. |
| `oneof` | `attribute` hat einen der Werte im Array `value`. |

* Werte sind Strings, Zahlen oder Wahrheitswerte. Kalenderdaten (Typ `date`) schreibst du als String `JJJJ-MM-TT`, Zeitpunkte (Typ `date-time`) als String nach RFC 3339 mit Zeitzone. Einzelheiten stehen unter [Datentypen](/data-types).
* `{ "kind": "and", "children": [] }` liefert alle Einträge.
* `not` braucht mindestens einen Ausdruck in `children`. Mehrere verneint es gemeinsam, wie ein `not` um ein `and`.
* Eine unbekannte Art (`kind`) oder ein unbekanntes Attribut ergibt `400`.
* Ein Wert, der nicht zum Typ des Attributs passt, ergibt ebenfalls `400`, zum Beispiel Text für eine Ganzzahl oder eine UUID, eine Zahl mit Nachkommastellen für eine Ganzzahl oder ein Zeitpunkt in einer Schreibweise außerhalb von ISO 8601, etwa `01.09.2026`. Kalenderdaten in anderer Schreibweise lehnt die API nicht ab, sie liefern aber falsche Treffer.

## Sortieren

`sort` enthält ein oder mehrere Attribute, `direction` die Richtung je Attribut: `asc` (Standard) oder `desc`. Beide Felder nehmen auch einen einzelnen String an.

Für `sort` sind nur die Attribute dokumentiert, die [weiter unten](#attribute-je-route) als sortierbar markiert sind. Ein Attribut, das dort als nicht sortierbar markiert ist, etwa `uploadDocument.ocrStatus` bei Belegen, ergibt in `sort` den Status `400`.

Ohne `sort` ist die Reihenfolge nicht festgelegt. Sortiere immer, wenn du mehrere Seiten abrufst.

## Seitenweise abrufen

| Feld     | Bedeutung                                                                                                           |
| -------- | ------------------------------------------------------------------------------------------------------------------- |
| `limit`  | Treffer je Seite, höchstens 1.000. Größere Werte werden auf den Höchstwert gesetzt. Ohne `limit` gilt der Höchstwert. |
| `offset` | Anzahl der Treffer, die übersprungen werden, höchstens 1.000.000. Größere oder negative Werte ergeben `400`.              |

Die Antwort nennt die Gesamtzahl und die gelieferte Seite:

```json
{
  "total": 1234,
  "limit": 100,
  "offset": 0,
  "items": []
}
```

Für die nächste Seite erhöhst du `offset` um `limit`, bis `offset` die Zahl `total` erreicht. Wenn sich die Daten zwischen zwei Abrufen ändern, können sich Seiten verschieben. Für einen vollständigen Abgleich grenzt du deshalb am besten über ein Datumsattribut ein, sortierst danach und rufst die Seiten zügig nacheinander ab.

## Attribute je Route

Dokumentiert sind nur die hier aufgeführten Attribute, in `sort` nur die als sortierbar markierten. Andere Attribute können funktionieren, gehören aber nicht zum dokumentierten Umfang (siehe [Stabilität und Änderungen](/stability)) und können sich ohne Ankündigung ändern.

### Buchungen suchen

`POST /api/accounting/booking/filter` (Referenz: https://developer.bimetrics.de/reference/accounting/filter-bookings)

| Attribut | Typ | Sortierbar | Beschreibung |
| --- | --- | --- | --- |
| `id` | uuid | ja | ID der Buchung. |
| `bookingDate` | date | ja | Buchungsdatum. |
| `account` | integer | ja | Konto. |
| `accountContra` | integer | ja | Gegenkonto. |
| `amount` | decimal | ja | Betrag. |
| `refDocumentId` | uuid | ja | ID des gebuchten Belegs. |
| `refBankTransactionId` | uuid | ja | ID des gebuchten Umsatzes. |
| `finalized` | date-time | ja | Zeitpunkt der Festschreibung; `null` bei nicht festgeschriebenen Buchungen. |
| `updatedAt` | date-time | ja | Zeitpunkt der letzten Änderung. |

```json
{
  "kind": "and",
  "children": [
    {
      "kind": "range",
      "attribute": "bookingDate",
      "lower": "2026-01-01",
      "upper": "2026-12-31"
    }
  ],
  "limit": 50,
  "offset": 0,
  "sort": [
    "bookingDate"
  ],
  "direction": [
    "desc"
  ]
}
```

### Bankkonten suchen

`POST /api/bankaccount/filter` (Referenz: https://developer.bimetrics.de/reference/bank-accounts/filter-bank-accounts)

| Attribut | Typ | Sortierbar | Beschreibung |
| --- | --- | --- | --- |
| `id` | uuid | ja | ID des Bankkontos. |
| `iban` | string | ja | IBAN des Kontos. |
| `bankName` | string | ja | Name der Bank. |
| `ownerName` | string | ja | Name des Kontoinhabers laut Bank. |
| `currency` | string | ja | Kontowährung (ISO 4217). |
| `disabled` | boolean | ja | Konto ist deaktiviert. |
| `updatedAt` | date-time | ja | Zeitpunkt der letzten Änderung. |

```json
{
  "kind": "and",
  "children": [
    {
      "kind": "range",
      "attribute": "updatedAt",
      "lower": "2026-01-01T00:00:00Z",
      "upper": "2026-12-31T23:59:59Z"
    }
  ],
  "limit": 50,
  "offset": 0,
  "sort": [
    "updatedAt"
  ],
  "direction": [
    "desc"
  ]
}
```

### Umsätze suchen

`POST /api/banktransaction/filter` (Referenz: https://developer.bimetrics.de/reference/bank-transactions/filter-bank-transactions)

| Attribut | Typ | Sortierbar | Beschreibung |
| --- | --- | --- | --- |
| `id` | uuid | ja | ID des Umsatzes. |
| `bankAccountId` | uuid | ja | ID des Bankkontos. |
| `bookingDate` | date | ja | Buchungstag. |
| `valueDate` | date | ja | Wertstellung. |
| `transactionAmount` | integer | ja | Betrag in Cent, negativ bei Ausgängen. |
| `otherPartyName` | string | ja | Name der Gegenseite. |
| `remittanceInformation` | string | ja | Verwendungszweck. |
| `status` | string | ja | `booked` (gebucht) oder `pending` (vorgemerkt). |
| `updatedAt` | date-time | ja | Zeitpunkt der letzten Änderung. |

```json
{
  "kind": "and",
  "children": [
    {
      "kind": "range",
      "attribute": "bookingDate",
      "lower": "2026-01-01",
      "upper": "2026-12-31"
    }
  ],
  "limit": 50,
  "offset": 0,
  "sort": [
    "bookingDate"
  ],
  "direction": [
    "desc"
  ]
}
```

### Kontakte suchen

`POST /api/contact/filter` (Referenz: https://developer.bimetrics.de/reference/contacts/filter-contacts)

| Attribut | Typ | Sortierbar | Beschreibung |
| --- | --- | --- | --- |
| `id` | uuid | ja | ID des Kontakts. |
| `companyName` | string | ja | Name des Kontakts. |
| `customerNumber` | integer | ja | Kunden- bzw. Lieferantennummer. |
| `type` | string | ja | Art: `customer` (Kunde), `supplier` (Lieferant) oder `partner`. |
| `customerKind` | string | ja | Steuerlich: `business` (Unternehmen) oder `private` (Privatperson); leer, wenn unbekannt. |
| `contactInfo.email` | string | ja | E-Mail-Adresse. |
| `paymentInfo.iban` | string | ja | IBAN. |
| `paymentInfo.vatId` | string | ja | USt-IdNr. |
| `updatedAt` | date-time | ja | Zeitpunkt der letzten Änderung. |

```json
{
  "kind": "and",
  "children": [
    {
      "kind": "range",
      "attribute": "updatedAt",
      "lower": "2026-01-01T00:00:00Z",
      "upper": "2026-12-31T23:59:59Z"
    }
  ],
  "limit": 50,
  "offset": 0,
  "sort": [
    "updatedAt"
  ],
  "direction": [
    "desc"
  ]
}
```

### Belege suchen

`POST /api/document/filter` (Referenz: https://developer.bimetrics.de/reference/documents/filter-documents)

| Attribut | Typ | Sortierbar | Beschreibung |
| --- | --- | --- | --- |
| `id` | uuid | ja | ID des Belegs. |
| `kind` | string | ja | Belegart: `invoice` (Ausgangsrechnung) oder `receipt` (Eingangsbeleg). |
| `invoiceDate` | date | ja | Rechnungsdatum. |
| `invoiceNumber` | string | ja | Rechnungsnummer. |
| `issuer.name` | string | ja | Name des Ausstellers. |
| `recipient.name` | string | ja | Name des Empfängers. |
| `uploadDocument.ocrStatus` | string | nein | Stand der Erkennung: `pending`, `processing`, `success`, `failed` oder `quota_paused`. |
| `createdAt` | date-time | ja | Zeitpunkt der Anlage in bimetrics. |
| `updatedAt` | date-time | ja | Zeitpunkt der letzten Änderung. Für Abgleiche per Polling: `range` mit `lower` = `updatedAt` des zuletzt gelesenen Belegs minus 5 Minuten Überlappung, sortiert nach `updatedAt`; Belege nach `id` speichern, weil manche doppelt kommen. |

```json
{
  "kind": "and",
  "children": [
    {
      "kind": "range",
      "attribute": "invoiceDate",
      "lower": "2026-01-01",
      "upper": "2026-12-31"
    }
  ],
  "limit": 50,
  "offset": 0,
  "sort": [
    "invoiceDate"
  ],
  "direction": [
    "desc"
  ]
}
```
