# Kontakte suchen (https://developer.bimetrics.de/referenz/kontakte/filter-contacts)

`POST https://app.bimetrics.de/api/contact/filter`

operationId: `filterContacts` · Berechtigung (Scope): `read` · Bereich: Kontakte

Sucht Kontakte (Kunden und Lieferanten) der Firma mit einem Filter und liefert eine Seite der Treffer.

Benötigt einen Schlüssel mit der Berechtigung `read`.

### Authentifizierung

`Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich).

### Request-Body (`application/json`)

Filter, Sortierung und Seite. Dokumentierte Filterattribute: `x-bimetrics-filter`.

Schema `FilterBody`.

| Feld | Typ | Beschreibung |
| --- | --- | --- |
| `attribute` | string | Filterattribut für `eq`, `in`, `range` und `oneof`, siehe `x-bimetrics-filter` der Operation. Groß-/Kleinschreibung und Punkte werden ignoriert. |
| `children` | Array<FilterDescriptor> | Teilfilter für `and`, `or` und `not`. |
| `direction` | string: `asc`, `desc` \| Array<string: `asc`, `desc`> | Richtung je Eintrag in `sort`; Standard `asc`. |
| `kind` | string: ``, `and`, `or`, `eq`, `not`, `in`, `range`, `oneof` | Art des Filters: `and`/`or` verknüpfen `children`, `not` verneint `children`, `eq` vergleicht `attribute` mit `value` (`null` prüft auf leer), `in` sucht `value` als Text im Attribut (enthält, ohne Groß-/Kleinschreibung), `range` prüft `lower` ≤ Attribut ≤ `upper` (eine Grenze genügt), `oneof` prüft, ob das Attribut einem Wert der Liste `value` entspricht. Leer: alle Einträge. |
| `limit` | integer | Treffer je Seite. Standard und Höchstwert 1000; größere Werte werden auf 1000 begrenzt. |
| `lower` | beliebig, kann null sein | Untergrenze für `range`, einschließlich. |
| `offset` | integer | Anzahl übersprungener Treffer. |
| `sort` | string \| Array<string> | Attribute, nach denen sortiert wird; nur sortierbare Attribute (`sortable` in `x-bimetrics-filter`). Ein Attribut mit `sortable: false` ergibt `400`. |
| `upper` | beliebig, kann null sein | Obergrenze für `range`, einschließlich. |
| `value` | beliebig, kann null sein | Vergleichswert: für `eq` ein Wert oder `null`, für `in` ein Text, für `oneof` eine Liste. |

### Filterattribute

| Attribut | Typ | Sortierbar | Beschreibung |
| --- | --- | --- | --- |
| `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. |

Dokumentiert sind diese Attribute für `attribute`; für `sort` nur die als sortierbar markierten.

Filterarten: `and`, `or`, `eq`, `not`, `in`, `range`, `oneof`.

### Beispiel

```sh
curl --fail-with-body -X POST "https://app.bimetrics.de/api/contact/filter" \
  -H "Authorization: Bearer $BIMETRICS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"and","children":[],"limit":50,"offset":0,"sort":["companyName"],"direction":["desc"]}'
```

### Antworten

| Status | Beschreibung | Inhalt |
| --- | --- | --- |
| 200 | Eine Seite der Treffer. | `application/json`: ContactFilterResult |
| 400 | Ungültige Anfrage, z. B. ein ungültiger Filter (unbekannte Art `kind`, unbekanntes Attribut, `sort` nach einem Attribut mit `sortable: false`, `limit` < 0, `offset` > 1.000.000), eine ID, die keine UUID ist, oder ein Upload ohne gültige `X-Upload-Request-Id`, mit mehr als einer Datei oder einer Datei über 30 MiB. Code meist `BadRequest`. Anfrage korrigieren, nicht wiederholen. | `application/json`: Error |
| 401 | Kein gültiger Schlüssel: fehlt (`Unauthorized`), ist unbekannt, abgelaufen oder widerrufen oder wurde nicht in genau einem Header gesendet (`InvalidAPIKey`). Schlüssel prüfen, nicht wiederholen. Auch eine ID, die zu einer anderen Firma gehört, ergibt `401 Unauthorized`. | `application/json`: Error |
| 402 | Das Abo der Firma erlaubt die Anfrage nicht (`SubscriptionRequired`, `PlanRequired`, `LimitReached`); `context` nennt Einzelheiten. | `application/json`: Error |
| 403 | Dem Schlüssel fehlt die Berechtigung für diese Route (`APIKeyPermissionDenied`), oder der Tarif der Firma enthält die API nicht (`APIUnavailable`). | `application/json`: Error |
| 413 | Die Anfrage ist zu groß (`APIRequestTooLarge`), siehe `x-bimetrics-limits`. | `application/json`: Error |
| 429 | Zu viele Anfragen (`APIRateLimit`). Nach `Retry-After` Sekunden wiederholen; einen Upload mit derselben `X-Upload-Request-Id`. (Header: Retry-After) | `application/json`: Error |
| 500 | Serverfehler (`Internal`; `APIUnavailable`, wenn der Schlüssel gerade nicht geprüft werden kann). Später wiederholen, einen Upload mit derselben `X-Upload-Request-Id`. | `application/json`: Error |

#### Felder der Antwort 200 (`ContactFilterResult`)

| Feld | Typ | Beschreibung |
| --- | --- | --- |
| `items` | Array<Contact>, kann null sein | Die Treffer dieser Seite. |
| `limit` | integer, kann null sein | Verwendetes `limit`. |
| `offset` | integer | Verwendetes `offset`. |
| `total` | integer | Anzahl aller Treffer des Filters. |

Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json
