# bimetrics API > Die bimetrics API gibt eigenen Anwendungen Zugriff auf die Buchhaltungsdaten einer Firma in bimetrics: Belege, Kontakte, Bankkonten, Umsätze und Buchungen lesen sowie Belege hochladen. Authentifizierung mit einem firmengebundenen API-Schlüssel im Header `Authorization: Bearer bm_…`. Maschinenlesbare Beschreibung: https://app.bimetrics.de/api/openapi.json - Vor schreibenden Aufrufen (Upload, `POST /api/document/`) beim Nutzer nachfragen: Jeder Upload legt einen echten Beleg an, verbraucht Kontingent und wird im GoBD-Protokoll vermerkt. Es gibt keine Testumgebung. - Den API-Schlüssel nie in URLs, Logs, Quellcode oder Frontend-Code ablegen. - Bei `429` die Sekunden aus `Retry-After` abwarten; Uploads mit derselben `X-Upload-Request-Id` wiederholen. # Einführung (https://developer.bimetrics.de/) Mit der bimetrics API liest deine Anwendung Belege, Kontakte, Bankkonten, Umsätze und Buchungen einer Firma und lädt Belege hoch. Die bimetrics API verbindet eigene Anwendungen mit einer Firma in bimetrics. Typische Einsätze sind ein Belegimport aus einem anderen System, ein Abgleich mit einem Warenwirtschafts- oder Kassensystem oder ein Export von Buchungen in ein eigenes Reporting. ## Was die API kann * **Lesen:** Belege mit erkannten Werten und Originaldatei, Kontakte, Bankkonten, Umsätze, Sachkonten und Buchungen sowie Tarif und Kontingent. * **Hochladen:** Belege einreichen, die bimetrics wie einen Upload in der App verarbeitet. Bestehende Belege, Einstellungen, Team und Abrechnung lassen sich über die API nicht ändern. Webhooks gibt es nicht; Änderungen holst du per Abfrage (Polling). ## Wer die API nutzen kann * Firmen mit einem gültigen bezahlten Tarif oder einer Freischaltung durch bimetrics. In der Testphase ist die API nicht verfügbar. * API-Schlüssel legt der Inhaber einer Firma in der App an. Jeder Schlüssel gilt für genau eine Firma. ## Grundlagen | Thema | Wert | | ----------------------------- | ----------------------------------------------------------- | | Basis-URL | `https://app.bimetrics.de`, alle Pfade beginnen mit `/api/` | | Format | JSON, Upload als `multipart/form-data` | | Authentifizierung | `Authorization: Bearer bm_…` | | Maschinenlesbare Beschreibung | [OpenAPI 3.0](https://app.bimetrics.de/api/openapi.json) | ## Nächste Schritte ## Für KI-Agenten Jede Seite gibt es auch als Markdown: Hänge `.md` an die Adresse an, zum Beispiel [/schnellstart.md](/schnellstart.md). Eine Übersicht aller Seiten steht in [/llms.txt](/llms.txt), der gesamte Inhalt in einer Datei in [/llms-full.txt](/llms-full.txt). # Schnellstart (https://developer.bimetrics.de/schnellstart) API-Schlüssel anlegen und den ersten Aufruf senden. ## 1. Schlüssel anlegen Das geht nur als Inhaber der Firma und mit einem gültigen bezahlten Tarif oder einer Freischaltung durch bimetrics. 1. Öffne in der App **Einstellungen › API** ([app.bimetrics.de/settings/api-keys](https://app.bimetrics.de/settings/api-keys)). 2. Wähle **Schlüssel erstellen** und vergib einen Namen, zum Beispiel den Namen deiner Anwendung. 3. Wähle die Berechtigungen: **Daten lesen** (`read`) und bei Bedarf **Belege hochladen** (`upload`). 4. Wähle die Gültigkeit (30, 90 oder 365 Tage) und bestätige mit deinem aktuellen Passwort. Der Schlüssel beginnt mit `bm_` und wird nur einmal angezeigt. Alle Inhaber der Firma erhalten eine E-Mail über den neuen Zugang. > **Schlüssel sicher aufbewahren:** Wer den Schlüssel kennt, kann bis zum Ablauf alle Daten der Firma lesen und, mit der Berechtigung `upload`, Belege hochladen. Lege ihn nur serverseitig ab, etwa in einer Umgebungsvariable oder einem Secret-Store, nie im Frontend-Code. Mehr dazu unter [Authentifizierung](/authentifizierung). ## 2. Ersten Aufruf senden Speichere den Schlüssel als Umgebungsvariable und frage Tarif und Kontingent ab. Der Aufruf ändert nichts und eignet sich als Test. ```sh export BIMETRICS_API_KEY='bm_…' curl --fail-with-body https://app.bimetrics.de/api/entitlement/ \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` Die Antwort enthält unter anderem den Tarif und die Nutzung im laufenden Zeitraum (gekürzt): ```json { "active": true, "tier": "team", "period": { "start": "2026-09-01T00:00:00Z", "end": "2026-10-01T00:00:00Z" }, "usage": { "documentsPeriod": 42 } } ``` Die Firma ergibt sich aus dem Schlüssel. Eine Firmen-ID schickst du nie mit. ## 3. Daten lesen Belege, Kontakte, Bankkonten, Umsätze und Buchungen suchst du mit einer Filteranfrage. Dieses Beispiel liefert die ersten 20 Belege ohne weitere Bedingung: ```sh curl --fail-with-body https://app.bimetrics.de/api/document/filter \ -H "Authorization: Bearer $BIMETRICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"kind": "and", "children": [], "limit": 20}' ``` Die Antwort hat die Form `{ "total": …, "limit": …, "offset": …, "items": [ … ] }`. Wie du filterst, sortierst und blätterst, steht unter [Filtern und Paginieren](/filtern). ## Wie es weitergeht * [Authentifizierung und Scopes](/authentifizierung): Header, Berechtigungen, Laufzeit und Widerruf. * [Fehler](/fehler) und [Limits](/limits): was bei `4xx`, `5xx` und `429` zu tun ist. * [Beleg-Upload](/beleg-upload): Belege ohne Doppelungen einreichen. * [API-Referenz](/referenz): alle Endpunkte, mit Playground zum Ausprobieren. # Authentifizierung und Scopes (https://developer.bimetrics.de/authentifizierung) Wie der API-Schlüssel gesendet wird, welche Berechtigungen er hat und wie lange er gilt. ## Schlüssel senden Sende den Schlüssel in genau einem Header, ausschließlich über HTTPS: ```http Authorization: Bearer bm_… ``` Alternativ akzeptiert die API denselben Schlüssel im Header `X-API-KEY`: ```http X-API-KEY: bm_… ``` Abgelehnt werden mit `401`: * beide Header zugleich oder ein Header mehrfach, * der Schlüssel als URL-Parameter (`?token=…`) oder per Basic-Auth, * ein Schlüssel mit angehängter Firmen-ID (`bm_…:`). Die Firma ergibt sich aus dem Schlüssel. Ein Schlüssel besteht aus `bm_` und 43 Zeichen aus dem URL-sicheren Base64-Alphabet, insgesamt 46 Zeichen. Antworten auf Aufrufe mit Schlüssel tragen `Cache-Control: no-store`. ## Berechtigungen (Scopes) Jeder Schlüssel hat eine oder beide Berechtigungen. Welche Berechtigung ein Endpunkt braucht, steht in der [Referenz](/referenz) bei jedem Endpunkt. | Berechtigung | In der App | Erlaubt | | ------------ | ---------------- | ---------------------------------------------------------------------------------------------------------- | | `read` | Daten lesen | alle lesenden Endpunkte: Belege, Belegdateien, Kontakte, Bankkonten, Umsätze, Sachkonten, Buchungen, Tarif | | `upload` | Belege hochladen | [Beleg hochladen](https://developer.bimetrics.de/referenz/belege/upload-document.md) | Fehlt die Berechtigung oder ist ein Endpunkt nicht für API-Schlüssel freigegeben, antwortet die API mit `403` und dem Code `APIKeyPermissionDenied`. Vergib nur die Berechtigungen, die die Anwendung braucht. ## Laufzeit und Anzahl * Ein Schlüssel gilt 30, 90 oder 365 Tage ab dem Anlegen. Danach antwortet die API mit `401`. Eine automatische Verlängerung gibt es nicht. * Eine Firma hat höchstens fünf aktive Schlüssel gleichzeitig. * Zum Austauschen legst du einen neuen Schlüssel an, stellst die Anwendung um und widerrufst dann den alten. ## Bindung an Inhaber und Tarif Ein Schlüssel gehört zum Inhaber, der ihn angelegt hat, und zur gewählten Firma. Jeder Aufruf prüft Schlüssel, Ablauf, Widerruf, Mitgliedschaft und Tarif neu. * Endet die Mitgliedschaft des Erstellers oder verliert er die Inhaberrolle, werden seine Schlüssel dauerhaft widerrufen. * Ohne gültigen bezahlten Tarif oder eine Freischaltung durch bimetrics antwortet die API mit `403` und dem Code `APIUnavailable`. * Ein Passwortwechsel widerruft keine Schlüssel. ## Sicher aufbewahren > **Nie im Frontend-Code:** Wer den Schlüssel kennt, hat bis zum Ablauf vollen Lesezugriff auf die Daten der Firma und kann, mit der Berechtigung `upload`, Belege hochladen. Baue ihn nie in Browser-, Mobil- oder Desktop-Apps ein, die an Dritte gehen. * Lege den Schlüssel nur serverseitig ab, etwa in einer Umgebungsvariable oder einem Secret-Store. * Schreibe ihn nicht in URLs, Logs, Tickets oder Quellcode. * Nutze je Anwendung einen eigenen Schlüssel. So kannst du einen einzelnen Zugang widerrufen, ohne andere zu stören. ## Widerrufen Widerrufe einen Schlüssel in der App unter **Einstellungen › API** mit **Widerrufen**. Ab dann antwortet die API auf neue Aufrufe mit `401`; bereits laufende Aufrufe werden nicht abgebrochen. Widerrufe einen Schlüssel sofort, wenn er in falsche Hände geraten sein könnte oder du einen Zugang nicht kennst. # Fehler (https://developer.bimetrics.de/fehler) Fehlerformat, HTTP-Status, Fehlercodes und wann sich eine Wiederholung lohnt. ## Format Fehler kommen als JSON mit HTTP-Status `4xx` oder `5xx`: ```json { "code": "APIRateLimit", "status": 429, "detail": "Zu viele API-Anfragen. Bitte später erneut versuchen.", "context": {} } ``` | Feld | Bedeutung | | --------- | --------------------------------------------------------------------------- | | `code` | Maschinenlesbarer Fehlercode. Werte deine Logik an `status` und `code` aus. | | `status` | Derselbe Wert wie der HTTP-Status. | | `detail` | Optionaler Hinweis für Menschen. Der Text kann sich ändern. | | `context` | Optionale Zusatzangaben, je nach Fehler. | Das Schema heißt `Error` und steht in der [OpenAPI-Beschreibung](https://app.bimetrics.de/api/openapi.json). ## HTTP-Status | Status | Bedeutung | Was tun | | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | `400` | Ungültige Anfrage, etwa ein unbekanntes Filterattribut, eine unbekannte Filterart (`kind`), ein Filterwert, der nicht zum Typ des Attributs passt, `sort` nach einem nicht sortierbaren Attribut, ein `offset` über dem Höchstwert, eine ID im Pfad, die keine UUID ist, ein Upload ohne `X-Upload-Request-Id` oder eine Datei über 30 MiB | Anfrage korrigieren, nicht wiederholen | | `401` | Schlüssel ist ungültig, abgelaufen oder widerrufen oder wurde falsch gesendet (`InvalidAPIKey`), es wurde kein Schlüssel gesendet, oder die angefragte ID gehört zu einer anderen Firma (`Unauthorized`) | Schlüssel, Header und ID prüfen, siehe [Authentifizierung](/authentifizierung) | | `402` | Für den Aufruf fehlt ein aktiver Tarif oder ein Abo, oder eine Tarifgrenze ist erreicht | Tarif in der App prüfen | | `403` | Dem Schlüssel fehlt die Berechtigung, oder die API ist für die Firma nicht freigeschaltet | Berechtigung bzw. Tarif prüfen | | `404` | Die Ressource gibt es nicht | ID prüfen | | `409` | Die `X-Upload-Request-Id` wurde schon für einen anderen Upload verwendet | Für einen neuen Beleg eine neue ID wählen, siehe [Beleg-Upload](/beleg-upload) | | `413` | Die Anfrage ist größer als erlaubt | Größe prüfen, siehe [Limits](/limits) | | `429` | Zu viele Anfragen | Die Sekunden aus dem Header `Retry-After` warten, dann wiederholen | | `5xx` | Vorübergehender Fehler auf unserer Seite | Mit wachsendem Abstand wiederholen | ## Fehlercodes Die Liste ist nicht abschließend. Es können neue Codes hinzukommen; behandle unbekannte Codes wie ihren HTTP-Status. | Code | Status | Bedeutung | | ------------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------- | | `InvalidAPIKey` | `401` | Schlüssel ungültig, abgelaufen, widerrufen oder nicht in genau einem Header gesendet | | `Unauthorized` | `401` | Kein `bm_`-Schlüssel gesendet, oder die angefragte ID gehört nicht zur Firma des Schlüssels | | `APIKeyPermissionDenied` | `403` | Dem Schlüssel fehlt die Berechtigung für diesen Endpunkt, oder der Endpunkt ist für API-Schlüssel nicht freigegeben | | `APIUnavailable` | `403` | Die API ist für die Firma nicht freigeschaltet, etwa ohne gültigen bezahlten Tarif | | `APIUnavailable` | `500` | Die API ist vorübergehend nicht verfügbar | | `PlanRequired`, `SubscriptionRequired`, `LimitReached` | `402` | Tarif, Abo oder Tarifgrenze | | `BadRequest` | `400` | Ungültige Anfrage, auch eine ID im Pfad, die keine gültige UUID ist | | `NotFound` | `404` | Nicht gefunden | | `UploadRequestConflict` | `409` | Die `X-Upload-Request-Id` gehört zu einem anderen Upload, oder der ursprüngliche Beleg ist gelöscht | | `APIRequestTooLarge` | `413` | Anfrage zu groß | | `APIRateLimit` | `429` | Zu viele Anfragen | | `Internal` | `500` | Unerwarteter Fehler | ## Wann wiederholen Wiederhole nur, wenn der Fehler vorübergehend ist: * bei `429` nach der Wartezeit aus `Retry-After`, * bei `5xx`, Zeitüberschreitung oder Verbindungsabbruch mit wachsendem Abstand, zum Beispiel nach 1, 2, 4 und 8 Sekunden. Uploads wiederholst du mit **derselben** `X-Upload-Request-Id` und derselben Datei. So entsteht auch bei mehreren Versuchen nur ein Beleg. Bei `400`, `401`, `402`, `403`, `404`, `409` und `413` hilft eine Wiederholung nicht. Prüfe Anfrage, Schlüssel, Berechtigung oder Tarif. # Limits (https://developer.bimetrics.de/limits) Anfragen pro Minute, Upload-Grenzen und Größen von Anfragen. | Grenze | Wert | | --- | --- | | Anfragen je Schlüssel | 60 pro Minute | | Anfragen je Firma, alle Schlüssel zusammen | 120 pro Minute | | Uploads je Firma | 10 pro Minute | | Gleichzeitige Uploads je Firma | höchstens 2 | | Größe einer Datei beim Upload | 30 MiB | | Größe einer Upload-Anfrage (gesamt) | 31 MiB | | Größe einer JSON-Anfrage | 1 MiB | | Treffer je Seite (`limit`) | höchstens 1.000 | | Startposition (`offset`) | höchstens 1.000.000 | | Anfragen mit ungültigem Schlüssel je Client | 120 pro Minute | | Wartezeit nach `429` (`Retry-After`) | 60 Sekunden | Die Werte sind die aktuellen technischen Schutzgrenzen. Anpassungen richten sich nach Ziffer 5.4, 8.2 und 10 der [AGB](https://bimetrics.de/agb). ## So wirken die Grenzen * **Anfragen:** Die Zähler laufen je Minute. Jeder Schlüssel hat ein eigenes Budget; zusätzlich teilen sich alle Schlüssel einer Firma ein gemeinsames Budget. * **Uploads:** Uploads zählen zu den Anfragen und haben ein eigenes Budget je Firma. Außerdem laufen nur wenige Uploads einer Firma gleichzeitig. * **Ungültige Schlüssel:** Anfragen mit ungültigem, unbekanntem oder falsch gesendetem Schlüssel sind je Client (IP-Adresse) begrenzt. Das schützt vor dem Durchprobieren von Schlüsseln. * **Größe:** Anfragen über der erlaubten Größe lehnt die API mit `413` ab. Eine einzelne zu große Datei im Upload ergibt `400`. * **Filter:** `limit` und `offset` haben Höchstwerte, siehe [Filtern und Paginieren](/filtern). ## Wenn eine Grenze erreicht ist Die API antwortet mit `429` und dem Code `APIRateLimit`. Der Header `Retry-After` nennt die Wartezeit in Sekunden. Warte diese Zeit ab und wiederhole die Anfrage dann; Uploads mit derselben `X-Upload-Request-Id`. Plane Abrufe so, dass sie gleichmäßig verteilt laufen, statt viele Anfragen auf einmal zu senden. Frage große Datenmengen seitenweise mit dem höchsten erlaubten `limit` ab. # Filtern und Paginieren (https://developer.bimetrics.de/filtern) 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/referenz/belege/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. Datumswerte schreibst du als String, `JJJJ-MM-TT` oder mit Uhrzeit nach RFC 3339. * `{ "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 Datum in anderer Schreibweise. ## 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](/stabilitaet)) und können sich ohne Ankündigung ändern. ### Buchungen suchen `POST /api/accounting/booking/filter` (Referenz: https://developer.bimetrics.de/referenz/buchhaltung/filter-bookings) | Attribut | Typ | Sortierbar | Beschreibung | | --- | --- | --- | --- | | `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/referenz/bankkonten/filter-bank-accounts) | Attribut | Typ | Sortierbar | Beschreibung | | --- | --- | --- | --- | | `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/referenz/umsaetze/filter-bank-transactions) | Attribut | Typ | Sortierbar | Beschreibung | | --- | --- | --- | --- | | `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/referenz/kontakte/filter-contacts) | 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. | ```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/referenz/belege/filter-documents) | Attribut | Typ | Sortierbar | Beschreibung | | --- | --- | --- | --- | | `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` = Zeitpunkt des letzten Abrufs. | ```json { "kind": "and", "children": [ { "kind": "range", "attribute": "invoiceDate", "lower": "2026-01-01", "upper": "2026-12-31" } ], "limit": 50, "offset": 0, "sort": [ "invoiceDate" ], "direction": [ "desc" ] } ``` # Beleg-Upload (https://developer.bimetrics.de/beleg-upload) Belege hochladen, ohne Doppelungen wiederholen und den Verarbeitungsstatus abfragen. > **Achtung:** Erzeugt einen echten Beleg, verbraucht Kontingent und wird GoBD-protokolliert. Teste den Upload deshalb mit einer Firma und einem Beleg, die du dafür vorgesehen hast. Die [Referenz](/referenz) bietet für den Upload bewusst keinen Testversand an. ## Voraussetzungen * Ein Schlüssel mit der Berechtigung `upload` (in der App: **Belege hochladen**). * `POST` an [`POST /api/document/`](https://developer.bimetrics.de/referenz/belege/upload-document.md) als `multipart/form-data`. * Genau **eine Datei** je Anfrage, in genau einem dieser Felder: | Feld | Bedeutung | | ----------- | ---------------------------------------------------------------- | | `auto[]` | bimetrics erkennt die Belegart selbst | | `receipt[]` | Eingangsbeleg, etwa eine Rechnung eines Lieferanten | | `invoice[]` | Ausgangsrechnung, also eine Rechnung, die die Firma gestellt hat | Weitere Formularfelder oder mehrere Dateien lehnt die API mit `400` ab. Unterstützt werden PDF, PNG, JPEG und Textformate wie XML-E-Rechnungen; die Art wird am Inhalt erkannt, nicht an der Dateiendung. Eine Datei darf höchstens 30 MiB groß sein; eine größere Datei ergibt `400`. Ist die ganze Anfrage größer als erlaubt, antwortet die API mit `413` (siehe [Limits](/limits)). ## Upload-ID Jede Anfrage braucht den Header `X-Upload-Request-Id`: 1 bis 128 druckbare ASCII-Zeichen ohne Leerzeichen, zum Beispiel eine UUID oder die ID des Belegs in deinem System. * Für jeden **neuen** Beleg eine **neue** ID verwenden. * Bei einer **Wiederholung** derselben Übertragung ID, Datei, Dateiname und Feld gleich lassen. ```sh curl --fail-with-body https://app.bimetrics.de/api/document/ \ -H "Authorization: Bearer $BIMETRICS_API_KEY" \ -H "X-Upload-Request-Id: rechnung-2026-0001" \ -F "auto[]=@rechnung.pdf" ``` ## Sicher wiederholen Firma, Schlüssel und Upload-ID bilden zusammen die Identität eines Uploads. * Kommt dieselbe ID mit identischer Datei, gleichem Dateinamen und gleichem Feld erneut, liefert die API denselben Beleg zurück. Das gilt auch für parallele Anfragen. Die Wiederholung verbraucht kein weiteres Kontingent und startet keine zweite Verarbeitung. * Kommt dieselbe ID mit anderem Inhalt, Dateinamen oder Feld, antwortet die API mit `409` und dem Code `UploadRequestConflict`. Das ist kein vorübergehender Fehler. * Wurde der ursprüngliche Beleg inzwischen gelöscht, legt eine Wiederholung ihn nicht neu an, sondern antwortet ebenfalls mit `409`. Für einen neuen Upload brauchst du eine neue ID. * Ein anderer Schlüssel bildet einen eigenen Bereich: Dieselbe ID mit einem neuen Schlüssel ist ein neuer Upload. Wiederhole bei Zeitüberschreitung, Verbindungsabbruch, `5xx` und `429` (nach `Retry-After`) immer mit derselben ID. ## Antwort Die Antwort ist ein Array mit genau einem Beleg (gekürzt): ```json [ { "id": "0b5c…", "uploadDocument": { "ocrStatus": "pending" } } ] ``` Liegt dieselbe Datei in der Firma schon vor, legt bimetrics keinen zweiten Beleg an. Die Antwort enthält dann den vorhandenen Beleg und `"duplicate": true`. ## Verarbeitung abfragen Nach dem Upload erkennt bimetrics die Belegdaten im Hintergrund. Den Stand fragst du mit [`GET /api/document/{id}`](https://developer.bimetrics.de/referenz/belege/get-document.md) ab, im Feld `uploadDocument.ocrStatus`: | Status | Bedeutung | | -------------- | ----------------------------------------------------------------------------------- | | `pending` | Beleg gespeichert, Verarbeitung noch nicht gestartet | | `processing` | Verarbeitung läuft | | `success` | Verarbeitung abgeschlossen, die erkannten Werte stehen im Beleg | | `failed` | Verarbeitung fehlgeschlagen, der Beleg bleibt gespeichert | | `quota_paused` | Beleg gespeichert, Verarbeitung pausiert, weil das Belegkontingent ausgeschöpft ist | Frage den Status in Abständen von einigen Sekunden ab und beachte die [Limits](/limits). Bei `quota_paused` war der Upload erfolgreich: Lade den Beleg nicht mit einer neuen ID erneut hoch. ## Nachvollziehbarkeit Jeder Upload wird im Protokoll des Belegs als Upload über einen API-Schlüssel vermerkt und dem verwendeten Schlüssel zugeordnet. Die Originaldatei rufst du mit [`GET /api/document/{id}/content`](https://developer.bimetrics.de/referenz/belege/get-document-content.md) ab. # Stabilität und Änderungen (https://developer.bimetrics.de/stabilitaet) Welche Teile der API dokumentiert sind und worauf deine Integration achten sollte. ## Dokumentierter Umfang Dokumentiert sind die hier beschriebenen Felder und Filterattribute. Antworten können weitere Felder enthalten, die sich ohne Ankündigung ändern können. Zur Dokumentation gehören: * die Endpunkte der [Referenz](/referenz) mit ihren Berechtigungen und den dort beschriebenen Feldern in Anfragen und Antworten, * die [Filterattribute je Route](/filtern#attribute-je-route), in `sort` nur die als sortierbar markierten, * das [Fehlerformat](/fehler) mit `code` und `status`. ## Hinweise für deine Integration * **Nicht dokumentierte Felder:** Verwende nur dokumentierte Felder und ignoriere unbekannte. * **Nicht dokumentierte Filterattribute:** Sie können funktionieren, gehören aber nicht zum dokumentierten Umfang. * **Ergänzungen:** Neue Endpunkte, neue optionale Felder und neue Fehlercodes können ohne Ankündigung hinzukommen. Behandle unbekannte Fehlercodes wie ihren HTTP-Status. * **Texte:** Der Inhalt von `detail` und die Reihenfolge von Feldern sind nicht festgelegt. * **Limits:** Die [Limits](/limits) sind technische Schutzgrenzen. Siehe auch den [Changelog](/changelog). # Changelog (https://developer.bimetrics.de/changelog) Änderungen an der bimetrics API, neueste zuerst. ## 27.09.2026: Filter * Ein Filterwert, der nicht zum Typ des Attributs passt, und ein `not` ohne `children` ergeben `400 BadRequest` statt `500`. Das gilt auch für Zahlen mit Nachkommastellen bei Ganzzahl-Attributen, die bisher abgeschnitten wurden, und für Datumswerte außerhalb von `JJJJ-MM-TT` und RFC 3339. Die Datenbank las davon manche, etwa `05.06.2026` als 6. Mai. * `not` verneint seine Ausdrücke als Ganzes. Bisher lieferte ein `not` um ein `and` die Treffer eines `not` um ein `or`. ## 26.09.2026: Erste öffentliche Version * Dokumentation der API unter developer.bimetrics.de mit Leitfäden und Referenz für 15 Endpunkte. * Maschinenlesbare Beschreibung als OpenAPI 3.0 unter [app.bimetrics.de/api/openapi.json](https://app.bimetrics.de/api/openapi.json). * Fehlerantworten haben einheitlich die Felder `code`, `status`, `detail` und `context`. * Eine unbekannte Filterart (`kind`) und `sort` nach einem nicht sortierbaren Attribut ergeben `400 BadRequest` statt `500`. * `POST /api/accounting/booking/groupfilter` ist nicht mehr mit API-Schlüsseln erreichbar. Buchungen liefern [`POST /api/accounting/booking/filter`](https://developer.bimetrics.de/referenz/buchhaltung/filter-bookings.md) und [`GET /api/accounting/booking/{id}`](https://developer.bimetrics.de/referenz/buchhaltung/get-booking.md). # Endpunkte (https://developer.bimetrics.de/referenz) Alle Endpunkte der bimetrics API mit Parametern, Antworten und Playground. Die Referenz entsteht aus der [OpenAPI-Beschreibung](https://app.bimetrics.de/api/openapi.json) des Backends. Alle Pfade beginnen mit `https://app.bimetrics.de/api/`, authentifiziert wird mit `Authorization: Bearer bm_…` (siehe [Authentifizierung](/authentifizierung)). ### Belege | Endpunkt | Beschreibung | Berechtigung | | --- | --- | --- | | [`POST /api/document/`](https://developer.bimetrics.de/referenz/belege/upload-document.md) | Beleg hochladen | upload | | [`POST /api/document/filter`](https://developer.bimetrics.de/referenz/belege/filter-documents.md) | Belege suchen | read | | [`GET /api/document/{id}`](https://developer.bimetrics.de/referenz/belege/get-document.md) | Beleg lesen | read | | [`GET /api/document/{id}/content`](https://developer.bimetrics.de/referenz/belege/get-document-content.md) | Originaldatei eines Belegs laden | read | ### Kontakte | Endpunkt | Beschreibung | Berechtigung | | --- | --- | --- | | [`POST /api/contact/filter`](https://developer.bimetrics.de/referenz/kontakte/filter-contacts.md) | Kontakte suchen | read | | [`GET /api/contact/{id}`](https://developer.bimetrics.de/referenz/kontakte/get-contact.md) | Kontakt lesen | read | ### Bankkonten | Endpunkt | Beschreibung | Berechtigung | | --- | --- | --- | | [`POST /api/bankaccount/filter`](https://developer.bimetrics.de/referenz/bankkonten/filter-bank-accounts.md) | Bankkonten suchen | read | | [`GET /api/bankaccount/{id}`](https://developer.bimetrics.de/referenz/bankkonten/get-bank-account.md) | Bankkonto lesen | read | ### Umsätze | Endpunkt | Beschreibung | Berechtigung | | --- | --- | --- | | [`POST /api/banktransaction/filter`](https://developer.bimetrics.de/referenz/umsaetze/filter-bank-transactions.md) | Umsätze suchen | read | | [`GET /api/banktransaction/{id}`](https://developer.bimetrics.de/referenz/umsaetze/get-bank-transaction.md) | Umsatz lesen | read | ### Buchhaltung | Endpunkt | Beschreibung | Berechtigung | | --- | --- | --- | | [`GET /api/accounting/accounts/`](https://developer.bimetrics.de/referenz/buchhaltung/list-used-accounts.md) | Bebuchte Konten auflisten | read | | [`GET /api/accounting/accounts/labels/`](https://developer.bimetrics.de/referenz/buchhaltung/list-account-labels.md) | Kontenbezeichnungen auflisten | read | | [`POST /api/accounting/booking/filter`](https://developer.bimetrics.de/referenz/buchhaltung/filter-bookings.md) | Buchungen suchen | read | | [`GET /api/accounting/booking/{id}`](https://developer.bimetrics.de/referenz/buchhaltung/get-booking.md) | Buchung lesen | read | ### Tarif | Endpunkt | Beschreibung | Berechtigung | | --- | --- | --- | | [`GET /api/entitlement/`](https://developer.bimetrics.de/referenz/tarif/get-entitlement.md) | Tarif und Kontingent lesen | read | ## Playground Auf den Seiten der lesenden Endpunkte kannst du Anfragen direkt ausprobieren. Der Playground sendet sie aus deinem Browser unmittelbar an `app.bimetrics.de`; der Schlüssel läuft nicht über developer.bimetrics.de. * Aus dem Browser funktioniert nur `Authorization: Bearer`. Den Header `X-API-KEY` lässt der Browser nicht zu, weil `app.bimetrics.de` ihn bei Anfragen von anderen Websites (CORS) nicht erlaubt. * Der Schlüssel bleibt nur während deines Besuchs im Browser gespeichert. Er wird gelöscht, wenn du die Seite verlässt oder neu lädst. Überspringt der Browser das, wird er beim nächsten Besuch gelöscht. Die Antworten enthalten echte Daten deiner Firma. Nutze den Playground nur auf einem Gerät, dem du vertraust. Für den Upload gibt es keinen Testversand, weil jeder Aufruf einen echten Beleg anlegt. # Beleg hochladen (https://developer.bimetrics.de/referenz/belege/upload-document) `POST https://app.bimetrics.de/api/document/` operationId: `uploadDocument` · Berechtigung (Scope): `upload` · Bereich: Belege Lädt genau eine Datei als neuen Beleg hoch und stößt die Erkennung an. Die Antwort ist ein Array mit genau einem Beleg. Das Formularfeld bestimmt die Belegart: `invoice[]` Ausgangsrechnung, `receipt[]` Eingangsbeleg, `auto[]` Erkennung durch bimetrics. Unterstützt werden PDF, PNG, JPEG und XML-E-Rechnungen. `X-Upload-Request-Id` macht Wiederholungen sicher: Dieselbe ID mit identischer Datei, identischem Dateinamen und Feld liefert denselben Beleg, ohne weiteres Kontingent; dieselbe ID mit anderem Inhalt ergibt `409 UploadRequestConflict`. Für jeden neuen Beleg eine neue ID verwenden. Ist das Belegkontingent ausgeschöpft, wird der Beleg trotzdem gespeichert (`uploadDocument.ocrStatus` = `quota_paused`); dann keinen weiteren Upload mit neuer ID starten. Benötigt einen Schlüssel mit der Berechtigung `upload`. > **Achtung:** Erzeugt einen echten Beleg, verbraucht Kontingent und wird GoBD-protokolliert. > > KI-Agenten fragen vor diesem Aufruf beim Nutzer nach. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Parameter | Name | Ort | Pflicht | Typ | Beschreibung | | --- | --- | --- | --- | --- | | `X-Upload-Request-Id` | header | ja | string | Idempotenzschlüssel des Uploads: 1–128 druckbare ASCII-Zeichen ohne Leerzeichen. Für jeden neuen Beleg eine neue ID, bei Wiederholungen dieselbe. | ### Request-Body (`multipart/form-data`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `auto[]` | string (binary) | Belegart erkennt bimetrics. | | `invoice[]` | string (binary) | Ausgangsrechnung. | | `receipt[]` | string (binary) | Eingangsbeleg. | ### Beispiel ```sh curl --fail-with-body -X POST "https://app.bimetrics.de/api/document/" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" \ -H "X-Upload-Request-Id: rechnung-2026-0001" \ -F "auto[]=@rechnung.pdf" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Der angelegte oder bei Wiederholung derselbe Beleg, als Array mit genau einem Eintrag. | `application/json`: Array | | 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 | | 409 | Die `X-Upload-Request-Id` gehört schon zu einem Upload mit anderer Datei, anderem Dateinamen oder anderem Feld (`UploadRequestConflict`). Kein vorübergehender Fehler: nicht mit derselben ID wiederholen. | `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 Array aus `UploadResult`. | Feld | Typ | Beschreibung | | --- | --- | --- | | `bookings` | Array, kann null sein | Buchungen des Belegs. | | `cashDiscount` | CashDiscountSnapshot | Skonto der Zuordnung; fehlt ohne Skonto. | | `companyId` | string (uuid) | | | `contentSource` | string | Herkunft der Belegdaten: `auto` erkannt, `manual` erfasst, `collection` aus Vertrag oder Serie. | | `createdAt` | string (date-time) | Anlage in bimetrics. | | `deliveryDate` | NaiveDate | Liefer- bzw. Leistungsdatum. | | `documentContract` | DocumentContract | Der Vertrag, falls der Beleg zu einem gehört. | | `documentContractId` | string (uuid), kann null sein | ID des Vertrags, falls der Beleg zu einem gehört. | | `documentSeries` | DocumentSeries | Die Belegserie, falls der Beleg zu einer gehört. | | `documentSeriesId` | string (uuid), kann null sein | ID der Belegserie, falls der Beleg zu einer gehört. | | `dueDate` | NaiveDate | Fälligkeitsdatum. | | `duplicate` | boolean | Die Datei lag in der Firma schon als Beleg vor. Fehlt sonst. | | `id` | string (uuid) | ID des Belegs. | | `importOrigin` | string, kann null sein | Eingangsweg: `upload`, `email`, `generated` (in bimetrics erstellt) oder `collection`. | | `invoiceDate` | NaiveDate | Rechnungsdatum. | | `invoiceNumber` | string | Rechnungsnummer. | | `invoicePositions` | Array, kann null sein | Positionen; `null`, solange nichts erkannt ist. | | `issuer` | DocumentIssuer | Aussteller. | | `kind` | string: `invoice`, `receipt` | Belegart: `invoice` Ausgangsrechnung, `receipt` Eingangsbeleg. | | `match` | Match | Zuordnung zu Umsätzen und anderen Belegen; `null` ohne Zuordnung. | | `paymentTerms` | string | Zahlungsbedingungen als Text. | | `performancePeriodFrom` | NaiveDate | Beginn des Leistungszeitraums. | | `performancePeriodTo` | NaiveDate | Ende des Leistungszeitraums. | | `recipient` | DocumentRecipient | Empfänger. | | `updatedAt` | string (date-time) | Letzte Änderung. | | `uploadDocument` | UploadDocument | Die hochgeladene Datei und der Stand ihrer Erkennung. | | `uploadDocumentId` | string (uuid), kann null sein | ID der hochgeladenen Datei; `null` bei Belegen aus Verträgen oder Serien. | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # Belege suchen (https://developer.bimetrics.de/referenz/belege/filter-documents) `POST https://app.bimetrics.de/api/document/filter` operationId: `filterDocuments` · Berechtigung (Scope): `read` · Bereich: Belege Sucht Belege der Firma mit einem Filter und liefert eine Seite der Treffer (`items`) mit der Gesamtzahl (`total`). Ohne Filter (`{}`) liefert die Route alle Belege, höchstens 1000 je Seite. 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 | Teilfilter für `and`, `or` und `not`. | | `direction` | string: `asc`, `desc` \| Array | 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 | 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 | | --- | --- | --- | --- | | `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` = Zeitpunkt des letzten Abrufs. | 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/document/filter" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"kind":"and","children":[],"limit":50,"offset":0,"sort":["kind"],"direction":["desc"]}' ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Eine Seite der Treffer. | `application/json`: DocumentFilterResult | | 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 (`DocumentFilterResult`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `items` | Array, 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 # Beleg lesen (https://developer.bimetrics.de/referenz/belege/get-document) `GET https://app.bimetrics.de/api/document/{id}` operationId: `getDocument` · Berechtigung (Scope): `read` · Bereich: Belege Liefert einen Beleg mit erkannten Daten, Positionen, Zuordnung (`match`) und Buchungen. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Parameter | Name | Ort | Pflicht | Typ | Beschreibung | | --- | --- | --- | --- | --- | | `id` | path | ja | string (uuid) | ID des Belegs (UUID). | ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/document/{id}" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Erfolg. | `application/json`: Document | | 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 | | 404 | Nicht gefunden (`NotFound`). | `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 (`Document`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `bookings` | Array, kann null sein | Buchungen des Belegs. | | `cashDiscount` | CashDiscountSnapshot | Skonto der Zuordnung; fehlt ohne Skonto. | | `companyId` | string (uuid) | | | `contentSource` | string | Herkunft der Belegdaten: `auto` erkannt, `manual` erfasst, `collection` aus Vertrag oder Serie. | | `createdAt` | string (date-time) | Anlage in bimetrics. | | `deliveryDate` | NaiveDate | Liefer- bzw. Leistungsdatum. | | `documentContract` | DocumentContract | Der Vertrag, falls der Beleg zu einem gehört. | | `documentContractId` | string (uuid), kann null sein | ID des Vertrags, falls der Beleg zu einem gehört. | | `documentSeries` | DocumentSeries | Die Belegserie, falls der Beleg zu einer gehört. | | `documentSeriesId` | string (uuid), kann null sein | ID der Belegserie, falls der Beleg zu einer gehört. | | `dueDate` | NaiveDate | Fälligkeitsdatum. | | `id` | string (uuid) | ID des Belegs. | | `importOrigin` | string, kann null sein | Eingangsweg: `upload`, `email`, `generated` (in bimetrics erstellt) oder `collection`. | | `invoiceDate` | NaiveDate | Rechnungsdatum. | | `invoiceNumber` | string | Rechnungsnummer. | | `invoicePositions` | Array, kann null sein | Positionen; `null`, solange nichts erkannt ist. | | `issuer` | DocumentIssuer | Aussteller. | | `kind` | string: `invoice`, `receipt` | Belegart: `invoice` Ausgangsrechnung, `receipt` Eingangsbeleg. | | `match` | Match | Zuordnung zu Umsätzen und anderen Belegen; `null` ohne Zuordnung. | | `paymentTerms` | string | Zahlungsbedingungen als Text. | | `performancePeriodFrom` | NaiveDate | Beginn des Leistungszeitraums. | | `performancePeriodTo` | NaiveDate | Ende des Leistungszeitraums. | | `recipient` | DocumentRecipient | Empfänger. | | `updatedAt` | string (date-time) | Letzte Änderung. | | `uploadDocument` | UploadDocument | Die hochgeladene Datei und der Stand ihrer Erkennung. | | `uploadDocumentId` | string (uuid), kann null sein | ID der hochgeladenen Datei; `null` bei Belegen aus Verträgen oder Serien. | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # Originaldatei eines Belegs laden (https://developer.bimetrics.de/referenz/belege/get-document-content) `GET https://app.bimetrics.de/api/document/{id}/content` operationId: `getDocumentContent` · Berechtigung (Scope): `read` · Bereich: Belege Liefert die hochgeladene Originaldatei als Binärdaten. PDFs und Bilder kommen mit ihrem Typ (`application/pdf`, `image/png`, `image/jpeg`), alles andere, etwa XML-E-Rechnungen, als `application/octet-stream`. Der `ETag` ist der SHA-256 der Datei (Hex, ohne Anführungszeichen); mit genau diesem Wert in `If-None-Match` antwortet die Route mit `304` ohne Inhalt. `404`, wenn der Beleg keine Originaldatei hat. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Parameter | Name | Ort | Pflicht | Typ | Beschreibung | | --- | --- | --- | --- | --- | | `id` | path | ja | string (uuid) | ID des Belegs (UUID). | | `download` | query | nein | string | Beliebiger nicht leerer Wert, z. B. `1`: Die Antwort trägt `Content-Disposition: attachment` mit dem ursprünglichen Dateinamen. | | `If-None-Match` | header | nein | string | ETag einer früheren Antwort; stimmt er, antwortet die Route mit `304`. | ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/document/{id}/content" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Die Originaldatei. (Header: Content-Disposition, ETag) | `application/octet-stream`: string (binary), `application/pdf`: string (binary), `image/*`: string (binary) | | 304 | Nicht geändert: `If-None-Match` entspricht dem `ETag`. | | | 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 | | 404 | Nicht gefunden (`NotFound`). | `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 | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # 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 | Teilfilter für `and`, `or` und `not`. | | `direction` | string: `asc`, `desc` \| Array | 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 | 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, 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 # Kontakt lesen (https://developer.bimetrics.de/referenz/kontakte/get-contact) `GET https://app.bimetrics.de/api/contact/{id}` operationId: `getContact` · Berechtigung (Scope): `read` · Bereich: Kontakte Liefert einen Kontakt mit Anschriften, Kontakt- und Zahlungsdaten. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Parameter | Name | Ort | Pflicht | Typ | Beschreibung | | --- | --- | --- | --- | --- | | `id` | path | ja | string (uuid) | ID des Kontakts (UUID). | ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/contact/{id}" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Erfolg. | `application/json`: Contact | | 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 | | 404 | Nicht gefunden (`NotFound`). | `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 (`Contact`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `addresses` | Array
| Anschriften. | | `companyId` | string (uuid) | | | `companyName` | string | Name. | | `contactInfo` | ContactInfo | Kontaktdaten. | | `createdAt` | string (date-time) | | | `customerKind` | string: `business`, `private` | Steuerlich: `business` Unternehmen, `private` Privatperson. Fehlt, wenn unbekannt. | | `customerNumber` | integer | Kunden- bzw. Lieferantennummer; ergibt Debitor- und Kreditorkonto. | | `id` | string (uuid) | ID des Kontakts. | | `paymentInfo` | PaymentInfo | Zahlungsdaten. | | `type` | string: `customer`, `supplier`, `partner` | Art des Kontakts. | | `updatedAt` | string (date-time) | Letzte Änderung. | | `vatCheck` | ContactVatCheck | Letzte Prüfung der USt-IdNr. beim Bundeszentralamt für Steuern bzw. VIES. | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # Bankkonten suchen (https://developer.bimetrics.de/referenz/bankkonten/filter-bank-accounts) `POST https://app.bimetrics.de/api/bankaccount/filter` operationId: `filterBankAccounts` · Berechtigung (Scope): `read` · Bereich: Bankkonten Sucht die verbundenen Bankkonten der Firma mit einem Filter und liefert eine Seite der Treffer. `accountOwner` nennt nur die Mitgliedschaft des Kontoinhabers, keine Personendaten. 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 | Teilfilter für `and`, `or` und `not`. | | `direction` | string: `asc`, `desc` \| Array | 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 | 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 | | --- | --- | --- | --- | | `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. | 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/bankaccount/filter" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"kind":"and","children":[],"limit":50,"offset":0,"sort":["iban"],"direction":["desc"]}' ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Eine Seite der Treffer. | `application/json`: BankAccountFilterResult | | 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 (`BankAccountFilterResult`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `items` | Array, 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 # Bankkonto lesen (https://developer.bimetrics.de/referenz/bankkonten/get-bank-account) `GET https://app.bimetrics.de/api/bankaccount/{id}` operationId: `getBankAccount` · Berechtigung (Scope): `read` · Bereich: Bankkonten Liefert ein verbundenes Bankkonto mit Saldo. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Parameter | Name | Ort | Pflicht | Typ | Beschreibung | | --- | --- | --- | --- | --- | | `id` | path | ja | string (uuid) | ID des Bankkontos (UUID). | ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/bankaccount/{id}" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Erfolg. | `application/json`: BankAccount | | 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 | | 404 | Nicht gefunden (`NotFound`). | `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 (`BankAccount`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `IBAN` | string | IBAN. | | `accountOwner` | UserCompany | Diese Mitgliedschaft, ohne Personendaten. | | `accountOwnerId` | string (uuid) | ID der Mitgliedschaft, die das Konto verbunden hat. | | `balance` | integer | Saldo in Cent zum Zeitpunkt `balanceDate`. | | `balanceAvailable` | boolean | Die Bank hat einen Saldo geliefert. Fehlt bei älteren Konten. | | `balanceCurrency` | string | Währung des Saldos. Fehlt bei älteren Konten. | | `balanceDate` | string (date-time) | Zeitpunkt des Saldos. | | `bankName` | string | Name der Bank. | | `companyId` | string (uuid) | | | `createdAt` | string (date-time) | | | `currency` | string | Kontowährung (ISO 4217). | | `disabled` | boolean | Das Konto ist deaktiviert; seine Umsätze erscheinen nicht in `filterBankTransactions`. | | `id` | string (uuid) | ID des Bankkontos. | | `ownerName` | string | Kontoinhaber laut Bank. | | `productName` | string | Kontobezeichnung der Bank. | | `updatedAt` | string (date-time) | | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # Umsätze suchen (https://developer.bimetrics.de/referenz/umsaetze/filter-bank-transactions) `POST https://app.bimetrics.de/api/banktransaction/filter` operationId: `filterBankTransactions` · Berechtigung (Scope): `read` · Bereich: Umsätze Sucht Bankumsätze der Firma mit einem Filter und liefert eine Seite der Treffer. Umsätze deaktivierter Konten sind nicht enthalten. 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 | Teilfilter für `and`, `or` und `not`. | | `direction` | string: `asc`, `desc` \| Array | 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 | 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 | | --- | --- | --- | --- | | `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. | 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/banktransaction/filter" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"kind":"and","children":[],"limit":50,"offset":0,"sort":["bankAccountId"],"direction":["desc"]}' ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Eine Seite der Treffer. | `application/json`: BankTransactionFilterResult | | 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 (`BankTransactionFilterResult`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `items` | Array, 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 # Umsatz lesen (https://developer.bimetrics.de/referenz/umsaetze/get-bank-transaction) `GET https://app.bimetrics.de/api/banktransaction/{id}` operationId: `getBankTransaction` · Berechtigung (Scope): `read` · Bereich: Umsätze Liefert einen Bankumsatz mit Zuordnung (`match`) und Buchungen. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Parameter | Name | Ort | Pflicht | Typ | Beschreibung | | --- | --- | --- | --- | --- | | `id` | path | ja | string (uuid) | ID des Umsatzes (UUID). | ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/banktransaction/{id}" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Erfolg. | `application/json`: BankTransaction | | 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 | | 404 | Nicht gefunden (`NotFound`). | `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 (`BankTransaction`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `accountIBAN` | string | IBAN des eigenen Kontos beim Abruf des Umsatzes. | | `bankAccount` | BankAccount | Das Bankkonto. | | `bankAccountId` | string (uuid) | ID des Bankkontos. | | `bookingDate` | NaiveDate | Buchungstag. | | `bookingDateTime` | string (date-time), kann null sein | Buchungszeitpunkt, falls die Bank ihn liefert. | | `bookings` | Array, kann null sein | Buchungen des Umsatzes. | | `checkId` | string, kann null sein | Schecknummer, falls die Bank sie liefert. | | `companyId` | string (uuid) | | | `createdAt` | string (date-time) | | | `id` | string (uuid) | ID des Umsatzes. | | `mandateId` | string, kann null sein | Mandatsreferenz einer SEPA-Lastschrift, falls die Bank sie liefert. | | `match` | Match | Zuordnung zu Belegen; `null` ohne Zuordnung. | | `otherPartyIBAN` | string, kann null sein | IBAN der Gegenseite. | | `otherPartyName` | string, kann null sein | Name der Gegenseite. | | `otherPartyUltimate` | string, kann null sein | Abweichender Zahlungsempfänger (bei Ausgängen) bzw. abweichender Zahler (bei Eingängen), falls die Bank ihn liefert. | | `remittanceInformation` | string | Verwendungszweck. | | `status` | string: `booked`, `pending` | `booked` gebucht, `pending` vorgemerkt. | | `transactionAmount` | integer | Betrag in Cent, negativ bei Ausgängen. | | `transactionCurrency` | string | Währung (ISO 4217). | | `updatedAt` | string (date-time) | Letzte Änderung. | | `valueDate` | NaiveDate | Wertstellung. | | `valueDateTime` | string (date-time), kann null sein | Zeitpunkt der Wertstellung, falls die Bank ihn liefert. | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # Bebuchte Konten auflisten (https://developer.bimetrics.de/referenz/buchhaltung/list-used-accounts) `GET https://app.bimetrics.de/api/accounting/accounts/` operationId: `listUsedAccounts` · Berechtigung (Scope): `read` · Bereich: Buchhaltung Liefert die Nummern aller Konten, auf die die Firma gebucht hat. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Parameter | Name | Ort | Pflicht | Typ | Beschreibung | | --- | --- | --- | --- | --- | | `accountingModel` | query | nein | string | Kontenrahmen, dessen Buchungen zählen. Ohne Angabe der Kontenrahmen der Firma. | ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/accounting/accounts/" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Erfolg. | `application/json`: UsedAccounts | | 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 (`UsedAccounts`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `accounts` | Array, kann null sein | Kontonummern. | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # Kontenbezeichnungen auflisten (https://developer.bimetrics.de/referenz/buchhaltung/list-account-labels) `GET https://app.bimetrics.de/api/accounting/accounts/labels/` operationId: `listAccountLabels` · Berechtigung (Scope): `read` · Bereich: Buchhaltung Liefert die Kontenbezeichnungen des Kontenrahmens der Firma: Bankkonten, Debitoren und Kreditoren der Kontakte sowie die Standardkonten. Ein Eintrag gilt für die Kontonummern von `from` bis `to`. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/accounting/accounts/labels/" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Erfolg. | `application/json`: Array | | 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 Array aus `AccountLabel`. | Feld | Typ | Beschreibung | | --- | --- | --- | | `automatic` | boolean | Automatikkonto. Fehlt sonst. | | `from` | integer | Erste Kontonummer des Bereichs. | | `label` | string | Bezeichnung. | | `tax` | string | Steuerschlüssel des Automatikkontos. Fehlt sonst. | | `to` | integer | Letzte Kontonummer des Bereichs. | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # Buchungen suchen (https://developer.bimetrics.de/referenz/buchhaltung/filter-bookings) `POST https://app.bimetrics.de/api/accounting/booking/filter` operationId: `filterBookings` · Berechtigung (Scope): `read` · Bereich: Buchhaltung Sucht Buchungen 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 | Teilfilter für `and`, `or` und `not`. | | `direction` | string: `asc`, `desc` \| Array | 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 | 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 | | --- | --- | --- | --- | | `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. | 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/accounting/booking/filter" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"kind":"and","children":[],"limit":50,"offset":0,"sort":["bookingDate"],"direction":["desc"]}' ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Eine Seite der Treffer. | `application/json`: AccountBookingFilterResult | | 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 (`AccountBookingFilterResult`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `items` | Array, 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 # Buchung lesen (https://developer.bimetrics.de/referenz/buchhaltung/get-booking) `GET https://app.bimetrics.de/api/accounting/booking/{id}` operationId: `getBooking` · Berechtigung (Scope): `read` · Bereich: Buchhaltung Liefert eine Buchung. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Parameter | Name | Ort | Pflicht | Typ | Beschreibung | | --- | --- | --- | --- | --- | | `id` | path | ja | string (uuid) | ID der Buchung (UUID). | ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/accounting/booking/{id}" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Erfolg. | `application/json`: AccountBooking | | 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 | | 404 | Nicht gefunden (`NotFound`). | `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 (`AccountBooking`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `account` | integer | Konto. | | `accountContra` | integer | Gegenkonto. | | `accountingModel` | string | Kontenrahmen der Buchung. | | `amount` | string (decimal) | Betrag als Dezimalzahl (String), bezogen auf `account`: größer 0 Soll, kleiner 0 Haben. | | `bookingDate` | NaiveDate | Buchungsdatum. | | `bookingFlags` | string | | | `companyId` | string (uuid) | | | `createdAt` | string (date-time) | | | `finalized` | string (date-time), kann null sein | Zeitpunkt der Festschreibung; `null`, solange nicht festgeschrieben. | | `id` | string (uuid) | ID der Buchung. | | `label` | string | Buchungstext. | | `performanceFrom` | NaiveDate | Beginn des Leistungszeitraums. | | `performanceTo` | NaiveDate | Ende des Leistungszeitraums. | | `refBankTransactionId` | string (uuid), kann null sein | ID des gebuchten Umsatzes. | | `refDocumentId` | string (uuid), kann null sein | ID des gebuchten Belegs. | | `refMatch` | string (uuid), kann null sein | ID der Zuordnung, aus der die Buchung entstand. | | `revertsAccountBookingId` | string (uuid), kann null sein | Diese Buchung storniert die Buchung mit dieser ID. | | `updatedAt` | string (date-time) | Letzte Änderung. | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json # Tarif und Kontingent lesen (https://developer.bimetrics.de/referenz/tarif/get-entitlement) `GET https://app.bimetrics.de/api/entitlement/` operationId: `getEntitlement` · Berechtigung (Scope): `read` · Bereich: Tarif Liefert Tarif, Grenzen und die aktuelle Nutzung der Firma. Ein einfacher erster Aufruf, um Schlüssel und Verbindung zu prüfen. Benötigt einen Schlüssel mit der Berechtigung `read`. ### Authentifizierung `Authorization: Bearer bm_…` (alternativ `X-API-KEY: bm_…`, nie beide zugleich). ### Beispiel ```sh curl --fail-with-body "https://app.bimetrics.de/api/entitlement/" \ -H "Authorization: Bearer $BIMETRICS_API_KEY" ``` ### Antworten | Status | Beschreibung | Inhalt | | --- | --- | --- | | 200 | Erfolg. | `application/json`: Entitlement | | 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 | | 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 (`Entitlement`) | Feld | Typ | Beschreibung | | --- | --- | --- | | `active` | boolean | Der Tarif ist aktiv. | | `addonCompanies` | integer | Zusätzlich gebuchte Firmen. | | `creditsIncluded` | integer | Im Tarif enthaltene Credits. | | `features` | PlanFeatures | Enthaltene Funktionen. | | `limits` | PlanLimits | Grenzen des Tarifs. | | `period` | EntitlementPeriod | Laufender Abrechnungszeitraum. | | `tier` | string: `solo`, `team`, `scale`, `legacy`, `none` | Tarif. | | `usage` | EntitlementUsage | Aktuelle Nutzung. | | `usageScope` | string: `monthly`, `trial_total` | Bezug von `usage.documentsPeriod`: `monthly` je Monat, `trial_total` für die gesamte Testphase. | Verschachtelte Schemas stehen vollständig in der OpenAPI-Beschreibung: https://app.bimetrics.de/api/openapi.json