#%RAML 1.0
title: Xentral-API
description: Die API befindet sich in ihrer Xentral-Installation im Unterordner `/www/api/`.
version: v1, v2
baseUri: http://www.example.com/api/{version}/
mediaType: application/json
securedBy: [ Digest ]
securitySchemes:
  Digest:
    type: Digest Authentication
    displayName: Digest Authentifizierung
    description: |
      Die API unterstützt nur die Digest Authentifizierung.
      Grundsätzlich empfehlen wir aber die zusätzliche Absicherung mit HTTPS-Verschlüsselung.
    describedBy:
      responses:
        401:
          description: |
            Fehler bei der Authentifizierung werden immer mit dem HTTP-Status `401 Unauthorized` ausgeliefert.

            **Beispiel-Response beim Zugriff ohne Authentifizierung:**
            ```
            {
                "error": {
                    "code": 7411,
                    "http_code": 401,
                    "message": "Unauthorized. You need to login.",
                    "href": "http://www.example.com/api/docs.html#error-7411"
                }
            }
            ```

documentation:
  - title: Authentifizierung
    content: |
      Die REST-API unterstützt momentan nur die Digest Authentifizierung, da nur diese Authentifizierungsmethode auch
      ohne HTTPS ausreichend Sicherheit bietet. Wir empfehlen grundsätzlich aber die zusätzliche Absicherung mit
      HTTPS-Verschlüsselung.

      ## API-Account anlegen

      In Xentral unter *Administration > Einstellungen > API-Account*. Dort auf *Neu* klicken.

      Wichtig sind folgende Felder:
      * *Aktiv*: Hacken muss gesetzt sein, damit API-Account genutzt werden kann.
      * *App Name / Benutzername* und *Initkey / Passwort*: Benutzername und Kennwort für Digest-Authentifizierung.

  - title: Authorisierung
    content: |
      Der Zugriff eines API-Accounts kann über Berechtigungen granular eingeschränkt werden.

      ## Berechtigungen bearbeiten

      In Xentral unter *Administration > Einstellungen > API-Account* muss der gewünschte API-Account mit einem Klick
      auf den Stift bearbeitet werden. Dort ist eine Liste der vorhandenen Berechtigungen.

      ### Alte API-Accounts

      Alle API-Accounts, die vor der Einführung der Berechtigungen existierten, haben automatisch alle
      Berechtigungen erhalten.

  - title: Requests
    content: |
      ## Ressourcen
      Grundsätzlich können alle API-Ressourcen nach folgendem Schema angesprochen werden.

      **Beispiel mit der `Addressen` Ressource:**

      | Method    | Endpoint           | Aktion                         |
      | --------- | ------------------ | ------------------------------ |
      | `GET`     | `/v1/adressen`     | Alle Adressen auflisten        |
      | `GET`     | `/v1/adressen/10`  | Einzelne Adresse abrufen       |
      | `PUT`     | `/v1/adressen/10`  | Vorhandene Adresse bearbeiten  |
      | `POST`    | `/v1/adressen`     | Neue Adresse anlegen           |
      | `DELETE`  | `/v1/adressen/10`  | Vorhandene Adresse löschen     |

      Bei vereinzelten Ressourcen kann es Abweichungen von diesem Schema geben.

      ## Content-Types
      Die API erwartet Anfragen mit dem Content-Type `application/json` oder `application/xml`.

      ## Zeichensatz
      Alle Anfragen mit Nutzdaten müssen mit `UTF-8` kodiert sein.

      ## Nutzdaten
      Nutzdaten müssen im Request-Body mitgeschickt werden. Nutzdaten sind nur bei POST- und PUT-Request zulässig;
      also nur Anfragen bei denen Ressourcen (z.B. Adressen) angelegt oder bearbeitet werden.

      **Beispiel HTTP-Request:**
      ```
      PUT /v1/adressen/7 HTTP/1.1
      Host: api.example.com
      Accept: application/json
      Content-Type: application/json; charset=utf-8
      Authorization: Digest XXXXXXXXXXX

      {
          "name": "Schrauben Meier",
          "telefon": "0987654321"
      }
      ```

      ### Aufbau Nutzdaten

      #### JSON
      JSON-Nutzdaten werden ohne einheitliches Root-Element erwartet. Die zu ändernden Feldnamen werden in der ersten
      Ebene erwartet.

      **Beispiel JSON:**
      ```json
      {
          "name": "Schrauben Meier GmbH",
          "strasse": "Dorfstrasse 123",
          "ort": "Musterdorf",
          "plz": "12345",
          "telefon": "0987654321",
      }
      ```

      #### XML
      XML-Nutzdaten müssen von einem Root-Element umschlossen sein. Der Name des Root-Elements kann beliebig lauten.
      Die zu ändernden Feldnamen werden in der zweiten Ebene erwartet.

      **Beispiel XML:**
      ```xml
      <data>
          <name>Schrauben Meier GmbH</name>
          <strasse>Dorfstrasse 123</strasse>
          <ort>Musterdorf</ort>
          <plz>12345</plz>
          <telefon>0987654321</telefon>
      </data>
      ```

  - title: Responses
    content: |
      Die API liefert Antworten im `JSON`- oder `XML`-Format aus; abhängig vom `Accept`-Header der Anfrage.

      Es wird die `JSON`-Ausgabe bevorzugt, wenn der `Accept`-Header fehlt oder ein nicht unterstütztes Format aufweist.

      ## Content-Types
      Antworten werden mit dem Content-Type `application/json` oder `application/xml` ausgeliefert; abhängig
      vom gesendeten Format.

      ## Zeichensatz
      Alle Antworten sind `UTF-8` kodiert.

      ## Response-Body
      ### Erfolgreiche Anfrage
      Der Response-Body einer erfolgreichen Anfrage beinhaltet immer ein `data`-Property als Root-Element.

      #### Einzelne Ressource
      **Beispiel mit einzelnem Ergebnis:**
      ```
      {
          "data": {
              "id": 1,
              "title": "Bernhardt Bieber"
          }
      }
      ```

      #### Mehrere Ressourcen
      Anworten mit mehreren Ressourcen beinhalten zusätzlich ein `pagination` Root-Element.

      **Beispiel mit mehreren Ergebnissen:**
      ```
      {
          "data": [
              {
                  "id": 1,
                  "title": "Phillipp Pabst"
              },
              {
                  "id": 2,
                  "name": "Peter Pfaff"
              }
          ],
          "pagination": {
              "items_total": 50,
              "items_current": 20,
              "items_per_page": 20,
              "page_current": 1,
              "page_last": 3
          }
      }
      ```
      Die Paginierung lässt sich über die GET-Parameter `page` und `items` steuern.

      ### Fehler
      Auch Fehler besitzen ein einheitliches Schema mit `error`-Property als Root-Element:
      ```
      {
          "error": {
              "code": 7452,
              "http_code": 404,
              "message": "Resource not found",
              "href": "http://www.example.com/api/docs.html#error-7452"
          }
      }
      ```

      Fehler-Responses beinhalten in der Regel ein `code` Property. Jeder Code steht für einen spezifischen Fehler.
      Im Helpdesk (oder dieser Dokumentation) ist zu jedem Code eine genaue Beschreibung und idealerweise
      Lösungsvorschläge zu finden.

  - title: Filter/Sortierung/Paginierung
    content: |
      Suchfilter, Sortierung und Paginierung stehen bei allen Endpunkten zur Verfügung die eine Liste zurückliefern.

      ## Filter

      ### Einfache Filter

      Beispiel: `/resource?ausverkauft=1&typ=produkt`

      Welche Filter-Parameter zur Verfügung stehen erfahren Sie in der jeweiligen Endpunkt-Beschreibung.

      ### Komplexe Filter

      Komplexe Filter sind grundsätzlich bei allen Endpunkt verfügbar die eine Liste zurückliefern; unabhängig
      von den einfachen Filtern.

      Beispiele:
      - `/resource?filter[0][property]=mwst_satz&filter[0][expression]=gte&filter[0][value]=10`
      - `/resource?filter[0][property]=beschreibung&filter[0][value]=%Schraube%`
      - `/resource?filter[0][property]=land&filter[0][value]=DE&filter[0][operation]=OR&filter[1][property]=land&filter[1][value]=AT`

      Parameter:
      - `property`\
        Feld in dem gesucht werden soll (Pflichtangabe).

      - `value`\
        Wert nach dem gesucht werden soll (Pflichtangabe).

      - `expression`\
        Vergleichsoperator\
        Mögliche Werte:
        - `eq` entspricht **=**
        - `not` entspricht **!=**
        - `gt` entspricht **>**
        - `gte` entspricht **>=**
        - `lt` entspricht **<**
        - `lte` entspricht **<=**
        - `like` entspricht **LIKE**
        - `not_like` entspricht **NOT LIKE**
        Default-Wert: `like`

      - `operation`\
        Verknüpfungsart bei der Anwendung mehrerer Filter.\
        Mögliche Werte: `and`, `or`.\
        Default-Wert: `and`

      ## Sortierung

      Welche Felder für die Sortierung zur Verfügung stehen, erfahren Sie in der jeweiligen Endpunkt-Beschreibung.

      Ein Minuszeichen vor dem Feldnamen kehrt die Sortierung um.

      Beispiel: `/resource?sort=titel,-projekt`

      ## Paginierung

      | Parameter  | Beschreibung                     | Default  | Wertebereich   |
      | ---------- | -------------------------------- | -------- | -------------- |
      | `page`     | Auswahl der Seite                | `1`      | `1` bis `1000` |
      | `items`    | Anzahl der Ergebnisse pro Seite  | `20`     | `1` bis `1000` |

      Beispiel: `/resource?page=2&items=5`

  - title: Fehler-Codes
    content: |

      TODO: Erklärungen hinzufügen

      ## Auth-Fehler
      ### <a name="error-7411"></a> #7411 - Unauthorized
      Zugriff ohne Authentifizierung. Authorization-Header fehlt komplett.

      ### <a name="error-7412"></a> #7412 - Digest header incomplete
      Digest-Header unvollständig; benötigte Teile fehlen.

      ### <a name="error-7413"></a> #7413 - Api account missing
      Es ist kein API-Account angelegt oder aktiv.

      ### <a name="error-7414"></a> #7414 - Api account invalid
      Der verwendete API-Account ist nicht gültig. Eventuell wurde der Account auf inaktiv gestellt.

      ### <a name="error-7415"></a> #7415 - Digest validation failed
      Die Prüfung der Digest-Authentifizierung ist fehlgeschlagen.

      ### <a name="error-7416"></a> #7416 - Digest nonce invalid
      Server-Nonce ist auf Server nicht vorhanden. Mögliche Ursachen:
      - Der Client hat einen beliebigen Nonce-Key mitgeschickt der dem Server nicht bekannt ist.
      - Der Nonce-Key ist schon länger abgelaufen und wurde gelöscht. Abgelaufene Nonce-Keys werden nach einigen Tagen
      gelöscht.

      ### <a name="error-7417"></a> #7417 - Digest nonce expired
      Server-Nonce ist abgelaufen. Nonce-Keys sind maximal 24 Stunden gültig und danach muss die Authentifizierung neu
      initialisiert werden. Beim erneuten Zugriff (auch schon beim Ausliefern des Fehlers) wird automatisch ein neuer
      Nonce-Key erzeugt und dem Client mitgeteilt (im www-authenticate Header). Der Client muss bei den weiteren
      Zugriffen den neuen Nonce-Key verwenden.

      ### <a name="error-7418"></a> #7418 - Auth username empty
      Der Benutzername darf nicht leer sein.

      ### <a name="error-7419"></a> #7419 - Authorization type not allowed
      Authorization-Header war vorhanden, aber die Authentifizierung-Methode ist nicht erlaubt. Vermutlich Zugriff mit
      Basic-Auth.

      ### <a name="error-7420"></a> #7420 - Digest nonce count not matching
      Fehler nicht möglich: Der Nonce-Count wird momentan nicht geprüft.

      ### <a name="error-7421"></a> #7421 - Missing Permission
      API-Account hat nicht die benötigten Berechtigungen

      ## Routing-Fehler
      ### <a name="error-7431"></a> #7431 - Route not found
      ### <a name="error-7432"></a> #7432 - Method not allowed
      ### <a name="error-7433"></a> #7433 - API-Method not found

      ## Endpoint-Fehler
      ### <a name="error-7451"></a> #7451 - Bad Request
      ### <a name="error-7452"></a> #7452 - Resource not found
      Mögliche Ursachen:
      - Das Ergebnis wurde über Filter zu stark begrenzt.
      - Beim Abrufen einer einzelnen Resource wurde eine nicht existierende ID angegeben.
      - Über die Paginierung wurde eine zu hohe Seite eingestellt. Siehe `pagination`-Property; der Wert von
      `page_current` darf nicht über dem von `page_last` liegen.
      - Die entsprechende Datenbanktabelle hat keine Inhalte.

      ### <a name="error-7453"></a> #7453 - Validation error
      Dieser Fehler kann nur beim Ändern oder Anlegen von Resourcen auftreten. Bei der Validierung der Eingabedaten
      ist ein Fehler aufgetreten.

      In diesem Fall beinhaltet der Error-Response das Property `details`, das Aufschluss über die fehlerhaften Felder
      gibt.

      ### <a name="error-7454"></a> #7454 - Invalid argument
      Es wurde ein unzulässiger Request-Parameter (GET-Parameter) verwendet z.B. ein Filter-Parameter der nicht
      zulässig ist.

      ### <a name="error-7455"></a> #7455 - Malformed request body
      Das JSON- oder XML-Dokument im Request-Body konnte nicht dekodiert werden. Ungültige Zeichen oder eine
      fehlerhafte Struktur können die Ursache sein. Überprüfen Sie die Daten ggf. mit Online-Validatoren.

      ### <a name="error-7456"></a> #7456 - Content type not supported
      Der Request-Body konnte nicht dekodiert werden, weil kein gültiger Content-Type übergeben wurde.

      ## Webserver-Konfiguration fehlerhaft

      ### <a name="error-7481"></a> #7481 - Webserver-Konfiguration fehlerhaft (nicht genauer beschrieben)

      ### <a name="error-7482"></a> #7482 - PATH_INFO ist nicht gesetzt oder leer
      Die PHP-Variable `$_SERVER['PATH_INFO']` ist nicht gesetzt oder leer, obwohl die aufgerufene URL darauf
      schließen lässt dass die Variable gefüllt sein müsste. Der Fehler deutet darauf hin dass die
      Webserver-Konfiguration fehlerhaft ist. Sie können sich mit der <a href="#failsafe">Failsafe-Variante</a>
      behelfen. Damit kann die API auch ohne eine spezielle Webserver-Konfiguration verwendet werden, z.B. auf einem
      Webspace bei dem die Änderung der Webserver-Konfiguration eingeschränkt ist.
      Zur Fehlerbehebung siehe Abschnitt <a href="#nginx">Nginx-Konfiguration</a> oder
      <a href="#apache">Apache-Konfiguration</a>

  - title: Debug-Modus
    content: |
      Im Auslieferungszustand gibt die REST-API bei Fehlern nur ausgewählte Fehlertypen zurück (siehe
      <a href="#fehler_codes">Fehler-Codes</a>).

      ### Beispiel Fehler-Response; Debug-Modus inaktiv
      ```json
      {
          "error": {
              "code": 7482,
              "http_code": 500,
              "message": "Webserver configuration incorrect. Pathinfo is invalid.",
              "href": "http://www.example.com/api/docs.html#error-7482"
          }
      }
      ```

      Zur Fehleranalyse kann der Debug-Modus aktiviert werden um zusätzliche Informationen über Request- und
      Konfigurationsvariablen zu erhalten. Debug-Informationen werden nur beim Auftreten eines Fehlers angehangen.

      ### Beispiel Fehler-Response mit aktivierten Debug-Modus
      ```json
      {
          "error": {
              "code": 7482,
              "http_code": 500,
              "message": "Webserver configuration incorrect. Pathinfo is invalid.",
              "href": "http://www.example.com/api/docs.html#error-7482"
          },
          "debug": {
              "router": {
                  "controllerClass": "Xentral\\Modules\\Api\\Controller\\Version1\\StartController",
                  "controllerAction": "indexAction",
                  "resourceClass": "Xentral\\Modules\\Api\\Resource\\Resource",
                  "routerParams": []
              },
              "request": {
                  "isFailsafe": false,
                  "pathInfo": {
                      "actual": "",
                      "expected": "/v1/adressen/123"
                  },
                  "info": {
                      "method": "PUT",
                      "requestUri": "/api/v1/adressen/123",
                      "fullUri": "http://www.example.com/api/v1/adressen/123"
                  },
                  "serverParams": {

                      // Ausgabe entfernt; wie PHP-Variable `$_SERVER`

                  },
                  "header": {
                      "Content-Type": "application/json",
                      "Authorization": "Digest .........",
                      "Host": "www.example.com",
                      "Accept": "application/json"
                  },
                  "getParams": [],
                  "postParams": [],
                  "additionalParams": []
              }
          }
      }
      ```

      ## Debug-Modus aktivieren

      **Der Debug-Modus ist nicht für Produktiv-Systeme geeignet und sollte nur zur Fehlersuche aktiviert werden.**

      ### Debug-Modus global aktivieren

      In der Datei `/www/api/index.php` die Konstante `DEBUG_MODE` auf `true` stellen.

      ```php
      define('DEBUG_MODE', true);
      ```

      Der Debug-Modus ist dann global für alle API-Accounts aktiviert. Debug-Informationen werden aber nur beim
      Auftreten eines Fehlers erzeugt.

  - title: PHP Beispiel-Clients
    content: |
      ## cURL
      ```php
      if (!function_exists('curl_version')) {
          throw new Exception('curl-Extension fehlt');
      }

      $api = array(
          'url' => 'http://www.example.com/api/',
          'resource' => 'v1/adressen?page=1&items=5',
          'username' => 'Your-Username',
          'password' => 'Your-Passwort',
      );

      $options = array(
          CURLOPT_URL => $api['url'] . $api['resource'],
          CURLOPT_HEADER => false,
          CURLOPT_HTTPHEADER => array('Accept: application/json'), // oder 'application/xml'
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_FOLLOWLOCATION => true,
          CURLOPT_HTTPAUTH => CURLAUTH_DIGEST, // Digest Authentifizierung
          CURLOPT_USERPWD => $api['username'] . ':' . $api['password'],
      );

      $ch = curl_init();
      curl_setopt_array($ch, $options);
      $response = curl_exec($ch);

      if (curl_errno($ch)) {
          throw new Exception(curl_error($ch));
      }

      $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
      $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      $result = json_decode($response, true);

      echo "<pre>";
      echo "<h1>HTTP-Status: {$statusCode}</h1>";
      echo "<h2>Content-Type: {$contentType}</h2>";
      var_dump($result);
      echo "</pre>";

      if ($ch != null) {
          curl_close($ch);
      }
      ```

      ## Guzzle
      ```php
      if (!class_exists('GuzzleHttp\Client')) {
          throw new Exception('Guzzle konnte nicht gefunden werden');
      }

      $api = array(
          'url' => 'http://www.example.com/api/',
          'resource' => 'v1/adressen?page=1&items=5',
          'username' => 'Your-Username',
          'password' => 'Your-Passwort',
      );

      $client = new GuzzleHttp\Client(array(
          'base_url' => $api['url'],
      ));

      $options = array(
          'headers' => array('Accept' => 'application/json'), // oder 'application/xml'
          'auth' => array($api['username'], $api['password'], 'digest'), // Digest Authentifizierung
      );
      $request = $client->createRequest('GET', $api['resource'], $options);
      $response = $client->send($request);

      $contentType = $response->getHeader('Content-Type');
      $statusCode = $response->getStatusCode();
      $statusMsg = $response->getReasonPhrase();
      $result = json_decode($response->getBody()->getContents(), true);

      echo "<pre>";
      echo "<h1>HTTP-Status: {$statusCode} {$statusMsg}</h1>";
      echo "<h2>Content-Type: {$contentType}</h2>";
      var_dump($result);
      echo "</pre>";
      ```

  - title: Webserver-Konfiguration
    content: |
      ## <a name="apache"></a> Apache

      Damit die API richtig funktioniert sollte `mod_rewrite` aktiviert sein.

      Der Aufruf ohne `mod_rewrite` ist ebenfalls möglich, dann muss allerdings die index.php in der URL vorkommen:
      z.B.: `/www/api/index.php/v1/adressen`

      ### mod_rewrite aktivieren
      ```
      $ sudo a2enmod rewrite
      Enabling module rewrite.
      To activate the new configuration, you need to run:
        systemctl restart apache2

      $ sudo systemctl restart apache2
      ```

      ### .htaccess Einbindung erlauben
      Bei Ubuntu- und Debian-basierten Betriebssystemen geschieht das für den gesamten Webserver in der Datei
      `/etc/apache2/apache2.conf`. Dort nach folgendem Eintrag suchen:

      ```
      <Directory /var/www/>
      	Options Indexes FollowSymLinks
      	AllowOverride None
      	Require all granted
      </Directory>
      ```

      Hier muss das `AllowOverride None` zu `AllowOverride All` geändert werden. Anschließend die Apache2-Konfiguration
      neu einlesen mit: `sudo service apache2 reload`.

      Wichtig: Diese Anpassung ist nur exemplarisch. Aus Sicherheitsgründen sollten Sie die Einstellung nicht für
      den gesamten Webserver erlauben. Um die Einstellung für einzelne Webseites vorzunehmen, sollten sie die
      entsprechende VHost-Konfiguration anpassen.

      ### Beispiel VHost-Konfiguration für Apache 2.4
      ```
      <VirtualHost *:80>
          # ServerName auskommentieren falls Sie per IP zugreifen
          ServerName xentral.example.com
          ServerAdmin webmaster@example.com

          # Pfad zum www-Verzeichnis ihrer Xentral-Installation
          DocumentRoot /var/www/xentral/www

          <Directory /var/www/xentral/www/>
              AllowOverride All
              Require all granted
          </Directory>

          ErrorLog ${APACHE_LOG_DIR}/xentral-error.log
          CustomLog ${APACHE_LOG_DIR}/xentral-access.log combined
      </VirtualHost>
      ```

      ## <a name="nginx"></a> Nginx

      ### Beispiel-Konfiguration

      ```
      server {
      	listen 80 default_server;
      	listen [::]:80 default_server;

      	root /var/www/xentral/www;

      	index index.php index.html index.htm;

      	server_name www.example.com;

      	location / {
      		# First attempt to serve request as file, then
      		# as directory, then fall back to displaying a 404.
      		try_files $uri $uri/ =404;
      	}

      	location /api/ {
      		# '/api/' befindet sich relativ zum Document-Root und muss ggf. angepasst werden.
      		try_files $uri $uri/ @xentral_api;
      	}

      	location @xentral_api {
      		# '/api/' befindet sich relativ zum Document-Root und muss ggf. angepasst werden.
      		rewrite ^/api/(.*)$ /api/index.php/$1 last;
      	}

      	location ~ [^/]\.php(/|$) {
      		# Path Info korrekt an PHP-Skript weitergeben
      		fastcgi_split_path_info ^(.+?\.php)(/.*)$;
      		if (!-f $document_root$fastcgi_script_name) {
      			return 404;
      		}

      		# Mitigate https://httpoxy.org/ vulnerabilities
      		fastcgi_param HTTP_PROXY "";

      		# With php-fpm (or other unix sockets):
      		fastcgi_pass unix:/var/run/php/php-fpm.sock;
      		# With php-cgi (or other tcp sockets):
      		#fastcgi_pass 127.0.0.1:9000;

      		fastcgi_index index.php;

      		include fastcgi_params;
      		fastcgi_param PATH_INFO         $fastcgi_path_info;
      		fastcgi_param PATH_TRANSLATED   $document_root$fastcgi_path_info;
      		fastcgi_param SCRIPT_FILENAME   $document_root$fastcgi_script_name;
      	}

      	# deny access to .htaccess files, if Apache's document root concurs with nginx's one
      	location ~ /\.ht {
      		deny all;
      	}
      }
      ```

      Außerdem muss `cgi.fix_pathinfo` in der php.ini auf `1` gestellt sein (Default).

      Quelle: <https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/>

      ## <a name="failsafe"></a> Failsafe-Alternative

      Sollte die Konfiguration des Webservers Probleme bereiten, oder aus anderen Gründen nicht möglich sein, so gibt
      es die Möglichkeit die API ohne Anpassung der Webserver-Konfiguration zu nutzen.

      Der Endpunkt wird dann nicht als Teil der Pfades übergeben, sondern als Query-Parameter `path`.

      Beispiel: `/api/index.php?path=/v1/artikelkategorien&sort=bezeichnung`

  - title: Standard API-Aufrufe
    content: |
      Es gibt auch die Möglichkeit die standard API über die neue URL abzurufen.

      Struktur: `http://www.example.com/api/{Action}`

      Beispiel: `http://www.example.com/api/ArtikelGet`

      Eine Übersicht der möglichen Requests/Actions mit Beispielen:
      <https://xentral.biz/helpdesk/api>

      **In diesem Fall erwartet die API immer einen POST-Request und die Nutzdaten müssen im Request-Body
      mitgeschickt werden.**

  - title: Test-System
    content: |
      Um auf die API eines <a href="https://xentral.com/helpdesk/testsystem" target="_blank">Test-Systems</a>
      zugreifen zu können, kann im HTTP-Header `MultiDb` der Datenbankname des Test-Systems angegeben werden.
      Der Header muss bei jedem Request mitgeschickt werden.

      ### Beispiel HTTP-Request
      ```http
      GET /api/v1/adressen HTTP/1.1
      Host: www.example.com
      Accept: application/json
      MultiDb: xentral_test
      ```


/v1/aboartikel:
  get:
    displayName: Abo-Artikel abrufen
    description: |
     Endpunkt zum Abrufen von Abo-Artikeln.

     Permission: `list_subscriptions`
    queryParameters:
      bezeichnung:
        description: Suche nach Abo-Artikel-Bezeichnung (ungefähre Übereinstimmung)
        type: string
        required: false
      bezeichnung_equals:
        description: Suche nach Abo-Artikel-Bezeichnung (genaue Übereinstimmung)
        type: string
        required: false
      bezeichnung_startswith:
        description: Suche nach Abo-Artikel-Bezeichnung (Übereinstimmung am Anfang)
        type: string
        required: false
      bezeichnung_endswith:
        description: Suche nach Abo-Artikel-Bezeichnung (Übereinstimmung am Ende)
        type: string
        required: false
      rabatt:
        description: Suche nach Rabatt in Prozent (genaue Übereinstimmung)
        type: number
        multipleOf: 0.01
        required: false
      rabatt_gt:
        description: Suche nach Rabatt in Prozent (Rabatt größer Suchwert)
        type: number
        multipleOf: 0.01
        required: false
      rabatt_gte:
        description: Suche nach Rabatt in Prozent (Rabatt größer gleich Suchwert)
        type: number
        multipleOf: 0.01
        required: false
      rabatt_lt:
        description: Suche nach Rabatt in Prozent (Rabatt kleiner Suchwert)
        type: number
        multipleOf: 0.01
        required: false
      rabatt_lte:
        description: Suche nach Rabatt in Prozent (Rabatt kleiner gleich Suchwert)
        type: number
        multipleOf: 0.01
        required: false
      preis:
        description: Suche nach Preis (genaue Übereinstimmung)
        type: number
        multipleOf: 0.0001
        required: false
      preis_gt:
        description: Suche nach Preis (Preis größer Suchwert)
        type: number
        multipleOf: 0.0001
        required: false
      preis_gte:
        description: Suche nach Preis (Preis größer gleich Suchwert)
        type: number
        multipleOf: 0.0001
        required: false
      preis_lt:
        description: Suche nach Preis (Preis kleiner Suchwert)
        type: number
        multipleOf: 0.0001
        required: false
      preis_lte:
        description: Suche nach Preis (Preis kleiner gleich Suchwert)
        type: number
        multipleOf: 0.0001
        required: false
      menge:
        description: Suche nach Menge (Menge Übereinstimmung)
        type: integer
        required: false
      menge_gt:
        description: Suche nach Menge (Menge größer Suchwert)
        type: integer
        required: false
      menge_gte:
        description: Suche nach Menge (Menge größer gleich Suchwert)
        type: integer
        required: false
      menge_lt:
        description: Suche nach Menge (Menge kleiner Suchwert)
        type: integer
        required: false
      menge_lte:
        description: Suche nach Menge (Menge kleiner gleich Suchwert)
        type: integer
        required: false
      startdatum:
        description: Suche nach Startdatum (Startdatum Übereinstimmung)
        type: string
        required: false
      startdatum_gt:
        description: Suche nach Startdatum (Startdatum größer Suchwert)
        type: string
        required: false
      startdatum_gte:
        description: Suche nach Startdatum (Startdatum größer gleich Suchwert)
        type: string
        required: false
      startdatum_lt:
        description: Suche nach Startdatum (Startdatum kleiner Suchwert)
        type: string
        required: false
      startdatum_lte:
        description: Suche nach Startdatum (Startdatum kleiner gleich Suchwert)
        type: string
        required: false
      enddatum:
        description: Suche nach Enddatum (Enddatum Übereinstimmung)
        type: string
        required: false
      enddatum_gt:
        description: Suche nach Enddatum (Enddatum größer Suchwert)
        type: string
        required: false
      enddatum_gte:
        description: Suche nach Enddatum (Enddatum größer gleich Suchwert)
        type: string
        required: false
      enddatum_lt:
        description: Suche nach Enddatum (Enddatum kleiner Suchwert)
        type: string
        required: false
      enddatum_lte:
        description: Suche nach Enddatum (Enddatum kleiner gleich Suchwert)
        type: string
        required: false
      waehrung:
        description: Suche nach Waehrungscode (ISO3; genaue Übereinstimmung)
        type: string
        required: false
      preisart:
        description: |
          Suche nach Preisart

          (Gültige Werte `monat`, `monatx`, `jahr`, `wochen`, `30tage`, `360tage` oder `einmalig`)
        type: string
        required: false
      dokumenttyp:
        description: Suche nach Dokument-Typ (Gültige Werte `rechnung` oder `auftrag`)
        type: string
        required: false
      artikel:
        description: Suche nach Artikel-ID (genaue Übereinstimmung)
        type: integer
        required: false
      adresse:
        description: Suche nach Adressen-ID (genaue Übereinstimmung)
        type: integer
        required: false
      kundennummer:
        description: Suche nach Kundennummer (genaue Übereinstimmung)
        type: string
        required: false
      gruppe:
        description: Suche nach Abogruppen-ID (genaue Übereinstimmung)
        type: integer
        required: false
      projekt:
        description: Suche nach Projekt-ID (genaue Übereinstimmung)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=-bezeichnung,rabatt`)

          Verfügbare Felder: `bezeichnung`, `rabatt`, `preis`, `menge`, `startdatum`, `enddatum`,
          `abgerechnet_bis`, `reihenfolge`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=artikel`)

          Verfügbare Includes: `gruppe`, `artikel`, `adresse`, `projekt`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Abo-Artikel anlegen
    description: |
      Abo-Artikel anlegen

      Permission: `create_subscription`
    body:
      application/json:
        properties:
          artikelnummer:
            description: Artikelnummer (Pflichfeld)
            required: true
            type: string
          bezeichnung:
            description: Name des Abo-Artikels (Pflichtfeld)
            required: true
            type: string
          beschreibung:
            description: Abo-Artikel-Beschreibung
            required: false
            type: string
          beschreibung_ersetzen:
            description: |
              Wenn `1`, wird nur die Beschreibung von hier ohne Artikelbeschreibung aus den Stammdaten
              angezeigt. (Default `0`)
            required: false
            type: integer
          startdatum:
            description: Erstes Startdatum (Format `YYYY-MM-DD`) (Default = Aktuelles Datum)
            required: false
            type: date-only
          enddatum:
            description: Enddatum (Format `YYYY-MM-DD`) (Default `0000-00-00`)
            required: false
            type: date-only
          preisart:
            description: |
              Zulässige Werte `monat`, `monatx`, `jahr`, `wochen`, `einmalig`, `30tage`, `360tage`

              (Default `monat`)
            required: false
            type: string
          zahlzyklus:
            description: abhängig von `preisart` (Default `1`)
            required: false
            type: integer
          dokumenttyp:
            description: Automatisch anlegen als Auftrag oder Rechnung.
              Zulässige Werte `rechnung`, `auftrag` (Default `rechnung`)
            required: false
            type: string
          preis:
            description: Netto Artikelpreis (Default `0.00`)
            required: false
            type: number
            multipleOf: 0.0001
          menge:
            description: Artikelmenge (Default `0`)
            required: false
            type: number
            multipleOf: 0.01
          rabatt:
            description: Rabatt in Prozent (Default `0.00`)
            required: false
            type: number
            multipleOf: 0.01
          waehrung:
            description: Währung; dreistelliger ISO-Code (Default `EUR`)
            required: false
            type: string
          gruppe:
            description: Abo-Gruppen-ID (Default `0`)
            required: false
            type: integer
          adresse:
            description: |
              Adressen-ID (Default `0`)

              Wird überschrieben wenn Feld `kundennummer` gefüllt ist.
            required: false
            type: integer
          kundennummer:
            description: |
              Kundennummer (kein Default)

              Wenn gefüllt, wird Adress-ID ermittelt und in Feld `adresse` geschrieben.
            required: false
            type: string
          projekt:
            description: |
              Projekt-ID (Default `0`)

              Die erstellte Rechnung läuft auf dieses Projekt
            required: false
            type: integer
          reihenfolge:
            description: |
              Wenn mehrere Artikel in einer Rechnung vorkommen, kann die Reihenfolge der Artikel damit
              angepasst werden (Default `1`)
            required: false
            type: integer
        example: |
          {
              "bezeichnung": "Abo-Artikel 001",
              "artikelnummer": "700006",
              "preis": 9.52,
              "zahlzyklus": 2,
              "preisart": "wochen",
              "kundennummer": "10001"
          }
    responses:
      201:
        description: Request erfolgreich; Angelegter Abo-Artikel wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 21,
                      "bezeichnung": "Abo-Artikel 001",
                      "beschreibung": "",
                      "beschreibung_ersetzen": 0,
                      "startdatum": "2019-05-27",
                      "enddatum": "0000-00-00",
                      "abgerechnet_bis": "0000-00-00",
                      "zahlzyklus": 2,
                      "preis": "9.5200",
                      "rabatt": "0.00",
                      "waehrung": "EUR",
                      "menge": 0,
                      "preisart": "wochen",
                      "dokumenttyp": "rechnung",
                      "artikel": 6,
                      "gruppe": 0,
                      "adresse": 3,
                      "kundennummer": "10000",
                      "reihenfolge": 1,
                      "projekt": 0
                  }
              }

  /{id}:
    description: Einzelnen Abo-Artikel abrufen oder bearbeiten.
    uriParameters:
      id:
        type: integer
        description: Abo-Artikel-ID
    get:
      displayName: Einzelnen Abo-Artikel abrufen
      description: |
        Einzelnen Abo-Artikel abrufen

        Permission: `edit_subscription`
    put:
      displayName: Abo-Artikel bearbeiten
      description: |
        Abo-Artikel bearbeiten (Felder siehe "Abo-Artikel anlegen")

        Permission: `view_subscription`
      body:
        application/json:
          example: |
            {
                "bezeichnung": "Abo-Artikel 001",
                "beschreibung_ersetzen": 0,
                "startdatum": "2019-01-01",
                "enddatum": "2019-12-31",
                "rabatt": "3.00",
                "zahlzyklus": 1,
                "waehrung": "EUR",
                "preisart": "wochen",
                "dokumenttyp": "rechnung",
                "kundennummer": "10000"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierter Abo-Artikel wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 1,
                        "bezeichnung": "Abo-Artikel 001",
                        "beschreibung": "",
                        "beschreibung_ersetzen": 0,
                        "startdatum": "2019-01-01",
                        "enddatum": "2019-12-31",
                        "abgerechnet_bis": "2019-07-31",
                        "zahlzyklus": 1,
                        "preis": "0.17",
                        "rabatt": "3.00",
                        "waehrung": "EUR",
                        "menge": 100,
                        "preisart": "wochen",
                        "dokumenttyp": "rechnung",
                        "artikel": 2,
                        "gruppe": 1,
                        "adresse": 3,
                        "kundennummer": "10000",
                        "reihenfolge": 1,
                        "projekt": 0
                    }
                }

    delete:
      displayName: Abo-Artikel löschen
      description: |
        Endpunkt zum Löschen von Abo-Artikeln

        Permission: `delete_subscription`
      responses:
        200:
          description: Request erfolgreich; id des gelöschten Aboartikels wird zurückgegeben
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 1
                    }
                }
        404:
          description: id wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://localhost/xentral/20.1/www/api/docs.html#error-7452"
                    }
                }

/v1/abogruppen:
  get:
    displayName: Abo-Gruppen abrufen
    description: |
      Endpunkt zum Abrufen von Abo-Gruppen

      Permission: `list_subscription_groups`
    queryParameters:
      bezeichnung:
        description: Suche nach bestimmter Abo-Gruppen-Bezeichnung (ungefähre Übereinstimmung)
        type: string
        required: false
      bezeichnung_equals:
        description: Suche nach bestimmter Abo-Gruppen-Bezeichnung (genaue Übereinstimmung)
        type: string
        required: false
      bezeichnung_startswith:
        description: Suche nach bestimmter Abo-Gruppen-Bezeichnung (Übereinstimmung am Anfang)
        type: string
        required: false
      bezeichnung_endswith:
        description: Suche nach bestimmter Abo-Gruppen-Bezeichnung (Übereinstimmung am Ende)
        type: string
        required: false
      gruppensumme:
        description: Suche nach Gruppensumme-Kennzeichen (1 = aktiv / 0 = inaktiv)
        type: integer
        required: false
      rabatt:
        description: Suche nach Rabatt in Prozent (genaue Übereinstimmung)
        type: number
        multipleOf: 0.01
        required: false
      rabatt_gt:
        description: Suche nach Rabatt in Prozent (Rabatt größer Suchwert)
        type: number
        multipleOf: 0.01
        required: false
      rabatt_gte:
        description: Suche nach Rabatt in Prozent (Rabatt größer gleich Suchwert)
        type: number
        multipleOf: 0.01
        required: false
      rabatt_lt:
        description: Suche nach Rabatt in Prozent (Rabatt kleiner Suchwert)
        type: number
        multipleOf: 0.01
        required: false
      rabatt_lte:
        description: Suche nach Rabatt in Prozent (Rabatt kleiner gleich Suchwert)
        type: number
        multipleOf: 0.01
        required: false
      projekt:
        description: Suche nach bestimmter Projekt-ID (genaue Übereinstimmung)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=-bezeichnung,rabatt`)

          Verfügbare Felder: `bezeichnung`, `rabatt`, `reihenfolge`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

          Verfügbare Includes: `projekt`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Abo-Gruppe anlegen
    description: |
      Abo-Gruppe anlegen

      Permission: `create_subscription_group`
    body:
      application/json:
        properties:
          bezeichnung:
            description: Name der Gruppe; erscheint auf der Rechnung (Pflichtfeld)
            required: true
            type: string
          beschreibung:
            description: Beschreibung der Gruppe; erscheint auf der Rechnung (optional)
            required: false
            type: string
          rabatt:
            description: Rabatt in Prozent (Default = 0.00)
            required: false
            type: number
            multipleOf: 0.01
          gruppensumme:
            description: Nach jeder Auflistung der Artikel einer Gruppe, wird eine Gruppensumme auf dem Beleg
              ausgegeben (1 = aktiv / 0 = inaktiv) (Default = 0)
            required: false
            type: integer
          projekt:
            description: |
              Projekt-ID (Default = 0)

              Die erstellte Rechnung läuft auf dieses Projekt
            required: false
            type: integer
          reihenfolge:
            description: Wenn mehrere Gruppen in einer Rechnung vorkommen, kann die Reihenfolge der Gruppen damit
              angepasst werden (ab Version 18.3) (Default = 0)
            required: false
            type: integer
        example: |
          {
              "bezeichnung": "Abo-Gruppe Verbrauchsmaterial",
              "rabatt": 2.50,
              "gruppensumme": 1,
              "projekt": 1,
              "reihenfolge": 123
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Abo-Gruppe wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 14,
                      "bezeichnung": "Abo-Gruppe Verbrauchsmaterial",
                      "beschreibung": "",
                      "rabatt": "2.50",
                      "gruppensumme": 1,
                      "projekt": 1,
                      "reihenfolge": 123
                  }
              }

  /{id}:
    description: Einzelne Abo-Gruppe abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Abo-Gruppen-ID
    get:
      displayName: Einzelne Abo-Gruppe abrufen
      description: |
        Einzelne Abo-Gruppe abrufen

        Permission: `view_subscription_group`
    put:
      displayName: Abo-Gruppe bearbeiten
      description: |
        Abo-Gruppe bearbeiten (Felder siehe "Abo-Gruppe anlegen")

        Permission: `edit_subscription_group`
      body:
        application/json:
          example: |
            {
                "bezeichnung": "Abo-Gruppe Verbrauchsmaterial",
                "rabatt": 3.00
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Abo-Gruppe wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 14,
                        "bezeichnung": "Abo-Gruppe Verbrauschsmaterial",
                        "beschreibung": "",
                        "rabatt": "3.00",
                        "gruppensumme": 1,
                        "projekt": 1,
                        "reihenfolge": 123
                    }
                }


/v1/adressen:
  description: Adressen anlegen, bearbeiten und abrufen
  get:
    displayName: Adressliste abrufen
    description: |
      Adressenliste abrufen

      Permission: `list_addresses`
    queryParameters:
      kundennummer:
        description: Suche nach bestimmter Adresse mit Kundennummer
        type: string
        required: false
        default: ""
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
    responses:
      200:
        body:
          application/json:
            example: |
              {
                "data": [
                  {
                    "id": 7,
                    "typ": "firma",
                    "sprache": "deutsch",
                    "name": "Schrauben Meier",
                    "abteilung": "",
                    "unterabteilung": "",
                    "land": "DE",
                    "strasse": "Musterstrasse 6",
                    "ort": "Musterdorf",
                    "plz": "13245",
                    "telefon": "12345678",
                    "telefax": "",
                    "mobile": "",
                    "email": "schrauben@meiermusterdorf.de",
                    "projekt": 1,
                    "...": "Ausgabe gekürzt"
                  },
                  {
                    "id": 8,
                    "...": "Ausgabe gekürzt"
                  }
                ],
                "pagination": {
                  "items_total": 50,
                  "items_current": 20,
                  "items_per_page": 20,
                  "page_current": 1,
                  "page_last": 3
                }
              }
  post:
    displayName: Adressen anlegen
    description: |
      Neue Adresse anlegen

      Permission: `create_address`
    body:
      application/json:
        example: |
          {
            "typ": "firma",
            "sprache": "deutsch",
            "name": "Max Muster",
            "land": "DE",
            "strasse": "Musterstrasse 6",
            "ort": "Musterdorf",
            "plz": "12345",
            "telefon": "0821123456789",
            "telefax": "0821123456790",
            "email": "info@maxmuellermuster.de",
            "projekt": 1
          }
    responses:
      200:
        description: Request erfolgreich; Angelegte Adresse wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                "data": {
                  "id": 33,
                  "typ": "firma",
                  "sprache": "deutsch",
                  "name": "Max Muster",
                  "abteilung": "",
                  "unterabteilung": "",
                  "land": "DE",
                  "strasse": "Musterstrasse 6",
                  "ort": "Musterdorf",
                  "plz": "12345",
                  "telefon": "0821123456789",
                  "telefax": "0821123456790",
                  "mobile": "",
                  "email": "info@maxmuellermuster.de",
                  "projekt": 1,
                  "...": "Ausgabe gekürzt"
                }
              }

  /{id}:
    description: Einzelne Adresse per ID abrufen
    uriParameters:
      id:
        type: integer
        description: Adressen-ID
    get:
      displayName: Einzelne Adresse abrufen
      description: |
        Einzelne Adresse abrufen

        Permission: `view_address`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                  "data": {
                    "id": 7,
                    "typ": "firma",
                    "sprache": "deutsch",
                    "name": "Schrauben Meier GmbH",
                    "abteilung": "",
                    "unterabteilung": "",
                    "land": "DE",
                    "strasse": "Musterstrasse 6",
                    "ort": "Musterdorf",
                    "plz": "13245",
                    "telefon": "12345678",
                    "telefax": "",
                    "mobile": "",
                    "email": "schrauben@meiermusterdorf.de",
                    "projekt": 1,
                    "...": "Ausgabe gekürzt"
                  }
                }
        404:
          description: Adresse wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Adresse bearbeiten
      description: |
        Adresse bearbeiten

        Permission: `edit_address`
      body:
        application/json:
          example: |
            {
              "name": "Schrauben Meier GmbH",
              "strasse": "Dorfstrasse 123",
              "ort": "Musterdorf",
              "plz": "12345",
              "telefon": "0987654321"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Adresse wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                  "data": {
                    "id": 7,
                    "typ": "firma",
                    "sprache": "deutsch",
                    "name": "Schrauben Meier GmbH",
                    "abteilung": "",
                    "unterabteilung": "",
                    "land": "DE",
                    "strasse": "Dorfstrasse 123",
                    "ort": "Musterdorf",
                    "plz": "12345",
                    "telefon": "0987654321",
                    "telefax": "",
                    "mobile": "",
                    "email": "schrauben@meiermusterdorf.de",
                    "projekt": 1,
                    "...": "Ausgabe gekürzt"
                  }
                }


/v2/adressen:
  description: Adressen abrufen
  get:
    displayName: Adressenliste abrufen
    description: |
      Adressenliste abrufen

      Permission: `list_addresses`
    queryParameters:
      projekt:
        description: Suche nach bestimmter Projekt-ID (genaue Übereinstimmung)
        type: integer
        required: false
      firma:
        description: Suche nach bestimmter Firmen-ID (genaue Übereinstimmung)
        type: integer
        required: false
      rolle:
        description: Suche nach bestimmter Rolle (Wert `kunde` oder `lieferant`)
        type: string
        required: false
      typ:
        description: Suche nach bestimmtem Adresstyp (genaue Übereinstimmung)
        type: string
        required: false
      sprache:
        description: Suche nach bestimmter Sprache (genaue Übereinstimmung)
        type: string
        required: false
      waehrung:
        description: Suche nach bestimmtem Währungscode (genaue Übereinstimmung)
        type: string
        required: false
      land:
        description: Suche nach bestimmtem Ländercode (genaue Übereinstimmung)
        type: string
        required: false
      kundennummer:
        description: Suche nach bestimmter Kundennummer (ungefähre Übereinstimmung)
        type: string
        required: false
      kundennummer_equals:
        description: Suche nach bestimmter Kundennummer (genaue Übereinstimmung)
        type: string
        required: false
      kundennummer_startswith:
        description: Suche nach bestimmter Kundennummer (Übereinstimmung am Anfang)
        type: string
        required: false
      kundennummer_endswith:
        description: Suche nach bestimmter Kundennummer (Übereinstimmung am Ende)
        type: string
        required: false
      lieferantennummer:
        description: Suche nach bestimmter Lieferantennummer (ungefähre Übereinstimmung)
        type: string
        required: false
      lieferantennummer_equals:
        description: Suche nach bestimmter Lieferantennummer (genaue Übereinstimmung)
        type: string
        required: false
      lieferantennummer_startswith:
        description: Suche nach bestimmter Lieferantennummer (Übereinstimmung am Anfang)
        type: string
        required: false
      lieferantennummer_endswith:
        description: Suche nach bestimmter Lieferantennummer (Übereinstimmung am Ende)
        type: string
        required: false
      mitarbeiternummer:
        description: Suche nach bestimmter Mitarbeiternummer (ungefähre Übereinstimmung)
        type: string
        required: false
      mitarbeiternummer_equals:
        description: Suche nach bestimmter Mitarbeiternummer (genaue Übereinstimmung)
        type: string
        required: false
      mitarbeiternummer_startswith:
        description: Suche nach bestimmter Mitarbeiternummer (Übereinstimmung am Anfang)
        type: string
        required: false
      mitarbeiternummer_endswith:
        description: Suche nach bestimmter Mitarbeiternummer (Übereinstimmung am Ende)
        type: string
        required: false
      email:
        description: Suche nach bestimmter E-Mail-Adresse (ungefähre Übereinstimmung)
        type: string
        required: false
      email_equals:
        description: Suche nach bestimmter E-Mail-Adresse (genaue Übereinstimmung)
        type: string
        required: false
      email_startswith:
        description: Suche nach bestimmter E-Mail-Adresse (Übereinstimmung am Anfang)
        type: string
        required: false
      email_endswith:
        description: Suche nach bestimmter E-Mail-Adresse (Übereinstimmung am Ende)
        type: string
        required: false
      freifeld[1-10]:
        description: |
          Suche nach bestimmtem Wert im Freifeld1 bis Freifeld10 (ungefähre Übereinstimmung)

          (Beispiel: `freifeld3=42`)
        type: string
        required: false
      freifeld[1-10]_equals:
        description: |
          Suche nach bestimmtem Wert im Freifeld1 bis Freifeld10 (genaue Übereinstimmung)

          (Beispiel: `freifeld3_equals=42`)
        type: string
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=name,-kundennummer`)

          Verfügbare Felder: `name`, `kundennummer`, `lieferantennummer`, `mitarbeiternummer`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
    responses:
      200:
        body:
          application/json:
            example: |
              {
                "data": [
                  {
                    "id": 7,
                    "rolle": "lieferant",
                    "typ": "firma",
                    "sprache": "deutsch",
                    "name": "Schrauben Meier",
                    "abteilung": "",
                    "unterabteilung": "",
                    "land": "DE",
                    "strasse": "Musterstrasse 6",
                    "ort": "Musterdorf",
                    "plz": "13245",
                    "telefon": "12345678",
                    "telefax": "",
                    "mobile": "",
                    "email": "schrauben@meiermusterdorf.de",
                    "projekt": 1,
                    "...": "Ausgabe gekürzt"
                  },
                  {
                    "id": 8,
                    "...": "Ausgabe gekürzt"
                  }
                ],
                "pagination": {
                  "items_total": 50,
                  "items_current": 20,
                  "items_per_page": 20,
                  "page_current": 1,
                  "page_last": 3
                }
              }

  /{id}:
    description: Einzelne Adresse per ID abrufen
    uriParameters:
      id:
        type: integer
        description: Adressen-ID
    get:
      displayName: Einzelne Adresse abrufen
      description: |
        Einzelne Adresse abrufen

        Permission: `view_address`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                  "data": {
                    "id": 7,
                    "rolle": "lieferant",
                    "typ": "firma",
                    "sprache": "deutsch",
                    "name": "Schrauben Meier GmbH",
                    "abteilung": "",
                    "unterabteilung": "",
                    "land": "DE",
                    "strasse": "Musterstrasse 6",
                    "ort": "Musterdorf",
                    "plz": "13245",
                    "telefon": "12345678",
                    "telefax": "",
                    "mobile": "",
                    "email": "schrauben@meiermusterdorf.de",
                    "projekt": 1,
                    "...": "Ausgabe gekürzt"
                  }
                }
        404:
          description: Adresse wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }


/v1/adresstyp:
  description: Adresstyp anlegen, bearbeiten und abrufen
  get:
    displayName: Adresstypen abrufen
    description: |
      Adresstypen abrufen

      Permission: `list_address_types`
    queryParameters:
      bezeichnung:
        description: Adresstyp mit bestimmter Bezeichnung suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      bezeichnung_exakt:
        description: Adresstyp mit bestimmter Bezeichnung suchen (genaue Übereinstimmung)
        type: string
        required: false
      type:
        description: |
          Nach bestimmten Typ filtern (genaue Übereinstimmung)

          Mögliche Werte: `herr`, `frau`, `firma`
        type: string
        required: false
      projekt:
        description: Adresstyp eines Projekts filtern (genaue Übereinstimmung)
        type: integer
        required: false
      netto:
        description: Netto-Adresstypen filtern (1 = netto / 0 = brutto)
        type: boolean
        required: false
      aktiv:
        description: Aktive/Inaktive Adresstypen filtern (1 = aktiv / 0 = inaktiv)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=type,-bezeichnung`)

          Verfügbare Felder: `bezeichnung`, `type`, `projekt`, `modul`, `aktiv`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

          Verfügbare Includes: `projekt`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Adresstyp anlegen
    description: |
      Adresstyp anlegen

      Permission: `create_address_type`
    body:
      application/json:
        properties:
          bezeichnung:
            description: Bezeichnung des Adresstyps
            required: true
            type: string
          type:
            description: Adresstyp; Mögliche Werte `herr`, `frau`, `firma`
            required: true
            type: string
          projekt:
            description: Projekt
            required: false
            type: integer
          netto:
            description: Anzeige Belege in Netto (`1` = netto / `0` = brutto)
            required: false
            type: integer
          aktiv:
            description: Aktiv (`1` = aktiv / `0` = inaktiv)
            required: false
            type: integer
        example: |
          {
              "type": "herr",
              "bezeichnung": "Gentleman",
              "aktiv": 1,
              "projekt": 1
          }
    responses:
      201:
        description: Request erfolgreich; Angelegter Adresstyp wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": "5",
                      "type": "herr",
                      "bezeichnung": "Gentleman",
                      "projekt": "1",
                      "netto": "0",
                      "aktiv": "1"
                  }
              }

  /{id}:
    description: Einzelner Adresstyp abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Adresstyp-ID
    get:
      displayName: Einzelnen Adresstyp abrufen
      description: |
        Einzelnen Adresstyp abrufen

        Permission: `view_address_type`
      queryParameters:
        include:
          description: |
            Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

            Verfügbare Includes: `projekt`
          type: string
          required: false
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": "1",
                        "type": "firma",
                        "bezeichnung": "Firma",
                        "projekt": "0",
                        "netto": "1",
                        "aktiv": "1"
                    }
                }
        404:
          description: Adresstyp wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Adresstyp bearbeiten
      description: |
        Adresstyp bearbeiten

        Permission: `edit_address_type`
      body:
        application/json:
          example: |
            {
                "type": "herr",
                "bezeichnung": "Mr",
                "aktiv": "1",
                "projekt": "1"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierter Adresstyp wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": "5",
                        "type": "herr",
                        "bezeichnung": "Mr",
                        "projekt": "1",
                        "netto": "0",
                        "aktiv": "1"
                    }
                }


/v1/artikel:
  description: Artikel abrufen
  get:
    displayName: Artikelliste abrufen
    description: |
      Artikelliste abrufen

      Permission: `list_articles`
    queryParameters:
      typ:
        description: |
          Artikel eines bestimmten Typs suchen (genaue Übereinstimmung)

          Mögliche Werte: `produkt`, `gebuehr`
        type: string
        required: false
      nummer:
        description: Suche nach Artikeln mit bestimmter Artikelnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      nummer_equals:
        description: Suche nach Artikeln mit bestimmter Artikelnummer (genaue Übereinstimmung)
        type: string
        required: false
      nummer_startswith:
        description: Suche nach Artikeln mit bestimmter Artikelnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      nummer_endswith:
        description: Suche nach Artikeln mit bestimmter Artikelnummer (Übereinstimmung am Ende)
        type: string
        required: false
      name_de:
        description: Suche nach Artikeln mit bestimmtem deutschem Namen (ungefähre Übereinstimmung)
        type: string
        required: false
      name_de_equals:
        description: Suche nach Artikeln mit bestimmtem deutschem Namen (genaue Übereinstimmung)
        type: string
        required: false
      name_de_startswith:
        description: Suche nach Artikeln mit bestimmtem deutschem Namen (Übereinstimmung am Anfang)
        type: string
        required: false
      name_de_endswith:
        description: Suche nach Artikeln mit bestimmtem deutschem Namen (Übereinstimmung am Ende)
        type: string
        required: false
      name_en:
        description: Suche nach Artikeln mit bestimmtem englischem Namen (ungefähre Übereinstimmung)
        type: string
        required: false
      name_en_equals:
        description: Suche nach Artikeln mit bestimmtem englischem Namen (genaue Übereinstimmung)
        type: string
        required: false
      name_en_startswith:
        description: Suche nach Artikeln mit bestimmtem englischem Namen (Übereinstimmung am Anfang)
        type: string
        required: false
      name_en_endswith:
        description: Suche nach Artikeln mit bestimmtem englischem Namen (Übereinstimmung am Ende)
        type: string
        required: false
      projekt:
        description: Artikel nach Projekt filtern
        type: integer
        required: false
      adresse:
        description: Artikel nach Adresse filtern
        type: integer
        required: false
      firma:
        description: Artikel nach Firma filtern
        type: integer
        required: false
      katalog:
        description: Artikel nach Katalog filtern
        type: integer
        required: false
      ausverkauft:
        description: Suche nach ausverkauften Artikeln (1 = ausverkauft / 0 = nicht ausverkauft)
        type: integer
        required: false
      startseite:
        description: Suche nach Artikeln auf Startseite (1 = Startseite / 0 = nicht Startseite)
        type: integer
        required: false
      topseller:
        description: Suche nach Topseller-Artikeln (1 = Topseller / 0 = kein Topseller)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=typ,-nummer`)

          Verfügbare Felder: `name_de`, `name_en`, `nummer`, `typ`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt,verkaufpreise`)

          Verfügbare Includes: `projekt`, `verkaufspreise`, `dateien`, `lagerbestand`

          ###### Lagerbestand

          **Beispiel – Lagerartikel**

          ```json
          "lagerbestand": {
              "lagernd": 12,
              "reserviert": 0,
              "offene_auftraege": 33,
              "offene_bestellungen": 1,
              "berechneter_bestand": -21,
              "verkaufbar": 0
          }
          ```

          **Beispiel – Kein Lagerartikel**

          ```json
          "lagerbestand": []
          ```

          **Erklärung**

          * **Lagernd**: Lagernde Menge über alle Lager, außer Sperrlager;
          * **Reserviert**: Reservierte Menge
          * **Offene Aufträge**: Menge aus offenen Aufträgen;
            Es werden nur Aufträge mit dem Status FREIGEGEBEN berücksichtigt;
            Aufträge mit Status ANGELEGT werden nicht berücksichtigt;
          * **Offene Bestellungen**:
            Es werden nur Bestellungen mit dem Status FREIGEGEBEN berücksichtigt;
            Bestellungen mit Status ANGELEGT werden nicht berücksichtigt;
          * **Berechneter Bestand**: *Lagernder Bestand* minus *Offene Aufträge*
          * **Verkaufbar**: Wie *Berechneter Bestand*; wird nur nicht kleiner als `0`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
    responses:
      200:
        body:
          application/json:
            example: |
              {
                  "data": [
                      {
                          "id": 1,
                          "typ": "produkt",
                          "nummer": "700001",
                          "checksum": "",
                          "projekt": 1,
                          "inaktiv": "",
                          "ausverkauft": 0,
                          "warengruppe": "",
                          "name_de": "Schraube M10x20",
                          "name_en": "",
                          "kurztext_de": "",
                          "kurztext_en": "",
                          "beschreibung_de": "",
                          "beschreibung_en": "",
                          "uebersicht_de": "",
                          "uebersicht_en": "",
                          "links_de": "",
                          "links_en": "",
                          "startseite_de": "",
                          "startseite_en": "",
                          "standardbild": "",
                          "herstellerlink": "",
                          "hersteller": "",
                          "teilbar": "",
                          "...": "Ausgabe gekürzt"
                      },
                      {
                          "id": 2,
                          "...": "Ausgabe gekürzt"
                      }
                  ]
              }
#  post:
#    displayName: Artikel anlegen
#    description: Neuen Artikel anlegen
#    body:
#      application/json:
#        example: |
#          {
#              "name_de": "Name vom Artikel",
#              "aktiv": "1",
#              "hersteller": "Herstellername",
#              "herstellernummer": "123",
#              "ean": "234",
#              "zolltarifnummer": "345",
#              "mindestlager": "10",
#              "mindestbestellung": "5",
#              "gewicht": "1.5",
#              "lagerartikel": "1",
#              "einkaufspreise": {
#                  "staffelpreis": {
#                      "lieferantennummer": "70000",
#                      "ab_menge": "1",
#                      "bestellnummer": "123456789",
#                      "bezeichnunglieferant": "Artikel 123456789",
#                      "preis": "1.20",
#                      "waehrung": "EUR"
#                  }
#              },
#              "verkaufspreise": {
#                  "staffelpreis": {
#                      "ab_menge": "1",
#                      "preis": "2.20",
#                      "waehrung": "EUR"
#                  }
#              }
#          }
#    responses:
#      200:
#        description: Request erfolgreich; Angelegte Adresse wird zurückgeliefert
#        body:
#          application/json:
#            example: |
#              {
#                  "data": {
#                      "id": 20,
#                      "typ": "",
#                      "nummer": "1000005",
#                      "projekt": 0,
#                      "inaktiv": "0",
#                      "ausverkauft": "0",
#                      "name_de": "Name vom Artikel",
#                      "name_en": "",
#                      "kurztext_de": "",
#                      "kurztext_en": "",
#                      "beschreibung_de": "",
#                      "beschreibung_en": "",
#                      "hersteller": "Herstellername",
#                      "gewicht": "1.5",
#                      "lagerartikel": "1",
#                      "mindestlager": "10",
#                      "mindestbestellung": "5",
#                      "herstellernummer": "123",
#                      "ean": "234",
#                      "...": "Ausgabe gekürzt",
#                      "einkaufspreise": {
#                          "staffelpreis": {
#                              "ab_menge": "1.0000",
#                              "preis": "1.20000000",
#                              "waehrung": "EUR",
#                              "lieferantennummer": "70000",
#                              "projekt": "STANDARD",
#                              "bestellnummer": "123456789",
#                              "bezeichnunglieferant": "Artikel 123456789"
#                          }
#                      },
#                      "verkaufspreise": {
#                          "staffelpreis": {
#                              "ab_menge": "1.0000",
#                              "preis": "2.20000000",
#                              "vpe": "1",
#                              "waehrung": "EUR"
#                          }
#                      }
#                  }
#              }

  /{id}:
    description: Einzelnen Artikel per ID abrufen
    uriParameters:
      id:
        type: integer
        description: Artikel-ID
    get:
      displayName: Einzelnen Artikel abrufen
      description: |
        Einzelnen Artikel abrufen

        Permission: `view_article`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 1,
                        "typ": "produkt",
                        "nummer": "700001",
                        "checksum": "",
                        "projekt": 1,
                        "inaktiv": "",
                        "ausverkauft": 0,
                        "warengruppe": "",
                        "name_de": "Schraube M10x20",
                        "name_en": "",
                        "kurztext_de": "",
                        "kurztext_en": "",
                        "beschreibung_de": "",
                        "beschreibung_en": "",
                        "uebersicht_de": "",
                        "uebersicht_en": "",
                        "links_de": "",
                        "links_en": "",
                        "startseite_de": "",
                        "startseite_en": "",
                        "standardbild": "",
                        "herstellerlink": "",
                        "hersteller": "",
                        "teilbar": "",
                        "nteile": "",
                        "...": "Ausgabe gekürzt"
                    }
                }
        404:
          description: Artikel wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
#    put:
#      displayName: Artikel bearbeiten
#      description: Artikel bearbeiten
#      body:
#        application/json:
#          example: |
#            {
#                "nummer": "100001",
#                "name_de": "Name neu von Artikel",
#                "aktiv": "1",
#                "anabregs_text": "Text für Angebot, Auftrag, Rechnung usw.",
#                "hersteller": "Herstellername",
#                "herstellernummer": "123",
#                "ean": "234",
#                "zolltarifnummer": "345",
#                "mindestlager": "10",
#                "mindestbestellung": "5",
#                "gewicht": "1.5",
#                "lagerartikel": "1"
#            }
#      responses:
#        200:
#          description: Request erfolgreich; Aktualisierter Artikel wird zurückgeliefert
#          body:
#            application/json:
#              example: |
#                {
#                    "data": {
#                        "id": 1,
#                        "typ": "produkt",
#                        "nummer": "700001",
#                        "checksum": "",
#                        "projekt": 1,
#                        "inaktiv": "",
#                        "ausverkauft": 0,
#                        "warengruppe": "",
#                        "name_de": "Schraube M10x20",
#                        "name_en": "",
#                        "kurztext_de": "",
#                        "kurztext_en": "",
#                        "beschreibung_de": "",
#                        "beschreibung_en": "",
#                        "uebersicht_de": "",
#                        "uebersicht_en": "",
#                        "links_de": "",
#                        "links_en": "",
#                        "startseite_de": "",
#                        "startseite_en": "",
#                        "standardbild": "",
#                        "herstellerlink": "",
#                        "hersteller": "",
#                        "teilbar": "",
#                        "nteile": "",
#                        "...": "Ausgabe gekürzt"
#                    }
#                }


/v1/artikelkategorien:
  description: Artikelkategorien anlegen, bearbeiten und abrufen
  get:
    displayName: Artikelkategorien abrufen
    description: |
      Artikelkategorien abrufen

      Permission: `list_article_categories`
    queryParameters:
      parent:
        description: Artikelkategorien mit Parent-ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      projekt:
        description: Artikelkategorien mit Projekt filtern (genaue Übereinstimmung)
        type: integer
        required: false
      bezeichnung:
        description: Artikelkategorie mit bestimmter Bezeichnung suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      bezeichnung_exakt:
        description: Artikelkategorie mit bestimmter Bezeichnung suchen (genaue Übereinstimmung)
        type: string
        required: false
      id_ext:
        description: Artikelkategorie mit externer ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=parent,-bezeichnung`)

          Verfügbare Felder: `bezeichnung`, `parent`, `projekt`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Artikelkategorie anlegen
    description: |
      Artikelkategorie anlegen

      Permission: `create_article_category`
    body:
      application/json:
        properties:
          bezeichnung:
            description: Name der Artikelkategorie
            required: true
            type: string
          projekt:
            description: Projekt-ID
            required: false
            type: integer
          parent:
            description: ID der Elternkategorie
            required: false
            type: integer
        example: |
          {
              "bezeichnung": "Schaufelradbagger",
              "projekt": 1,
              "parent": 10
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Artikelkategorie wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 19,
                      "bezeichnung": "Schaufelradbagger",
                      "next_nummer": "",
                      "projekt": 1,
                      "geloescht": "0",
                      "externenummer": "0",
                      "parent": 10,
                      "steuer_erloese_inland_normal": "",
                      "steuer_aufwendung_inland_normal": "",
                      "steuer_erloese_inland_ermaessigt": "",
                      "steuer_aufwendung_inland_ermaessigt": "",
                      "steuer_erloese_inland_steuerfrei": "",
                      "steuer_aufwendung_inland_steuerfrei": "",
                      "steuer_erloese_inland_innergemeinschaftlich": "",
                      "steuer_aufwendung_inland_innergemeinschaftlich": "",
                      "steuer_erloese_inland_eunormal": "",
                      "steuer_erloese_inland_nichtsteuerbar": "",
                      "steuer_erloese_inland_euermaessigt": "",
                      "steuer_aufwendung_inland_nichtsteuerbar": "",
                      "steuer_aufwendung_inland_eunormal": "",
                      "steuer_aufwendung_inland_euermaessigt": "",
                      "steuer_erloese_inland_export": "",
                      "steuer_aufwendung_inland_import": "",
                      "steuertext_innergemeinschaftlich": null,
                      "steuertext_export": null,
                      "id_ext": 0
                  }
              }

  /{id}:
    description: Einzelne Artikelkategorie abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Artikelkategorie-ID
    get:
      displayName: Einzelne Artikelkategorie abrufen
      description: |
        Einzelne Artikelkategorie abrufen

        Permission: `view_article_category`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 1,
                        "bezeichnung": "1000000 Sonstiges",
                        "next_nummer": "1000000",
                        "projekt": 0,
                        "geloescht": "0",
                        "externenummer": "0",
                        "parent": 0,
                        "...": "Ausgabe gekürzt",
                        "id_ext": 0
                    }
                }
        404:
          description: Artikelkategorie wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Artikelkategorie bearbeiten
      description: |
        Artikelkategorie bearbeiten

        Permission: `edit_article_category`
      body:
        application/json:
          example: |
            {
                "bezeichnung": "Schwimmbagger"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Artikelkategorie wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 19,
                        "bezeichnung": "Schwimmbagger",
                        "next_nummer": "",
                        "projekt": 1,
                        "geloescht": "0",
                        "externenummer": "0",
                        "parent": 0,
                        "...": "Ausgabe gekürzt",
                        "id_ext": 0
                    }
                }

/v1/eigenschaften:
  description: Eigenschaften für Artikel abrufen, erstellen, bearbeiten und löschen
  get:
    displayName: Eigenschaften abrufen
    description: |
      Eigenschaften abrufen

      Permission: `list_property`
    queryParameters:
      artikel:
        description: Artikel Id der die Eigenschaft zugewiesen ist (genaue Übereinstimmung) - Standardmäßig 0, da die Zuordnung zum Artikel über den Wert realisiert wird
        type: integer
        required: false
      name:
        description: Name der Eigenschaft (genaue Übereinstimmung)
        type: string
        required: false
      typ:
        description: Typ der Eigenschaft (genaue Übereinstimmung)
        type: string
        required: false
      projekt:
        description: Projekt dem die Eigenschaft zugewiesen ist (genaue Übereinstimmung)
        type: integer
        required: false
      geloescht:
        description: Markiert die Eigenschaft als gelöscht (genaue Übereinstimmung)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=artikel,-name`)

          Verfügbare Felder: `artikel`, `name`, `typ`, `projekt`, `geloescht`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Eigenschaft anlegen
    description: |
      Eigenschaft anlegen

      Permission: `create_property`
    body:
      application/json:
        properties:
          artikel:
            description: Artikel Id der die Eigenschaft zugewiesen werden soll
            type: integer
            required: false
          name:
            description: Name der Eigenschaft (muss eindeutig sein)
            type: string
            required: true
          typ:
            description: Typ der Eigenschaft
            type: string
            required: false
          projekt:
            description: Projekt dem die Eigenschaft zugewiesen ist
            type: integer
            required: false
          geloescht:
            description: Markiert die Eigenschaft als gelöscht
            type: integer
            required: false
        example: |
          {
              "name": "Farbe",
              "typ": "einzeilig"
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Eigenschaft wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                       "id": 19,
                       "artikel": 0,
                       "name": "Farbe",
                       "typ": "einzeilig",
                       "projekt": 0,
                       "geloescht": "0"
                  }
              }

  /{id}:
    description: Einzelne Eigenschaft abrufen, bearbeiten, oder löschen
    uriParameters:
      id:
        type: integer
        description: Eigenschaft-ID
    get:
      displayName: Einzelne Eigenschaft abrufen
      description: |
        Einzelne Eigenschaft abrufen

        Permission: `view_property`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 19,
                        "artikel": 0,
                        "name": "Farbe",
                        "typ": "einzeilig",
                        "projekt": 0,
                        "geloescht": "0"
                    }
                }
        404:
          description: Eigenschaft wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Eigenschaft bearbeiten
      description: |
        Eigenschaft bearbeiten

        Permission: `edit_property`
      body:
        application/json:
          example: |
            {
                "name": "Material"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Eigenschaft wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 19,
                        "artikel": 0,
                        "name": "Material",
                        "typ": "einzeilig",
                        "projekt": 0,
                        "geloescht": "0"
                    }
                }
    delete:
      displayName: Einzelne Eigenschaft löschen
      description: |
        Einzelne Eigenschaft löschen - Eigenschaften sollten nur dann gelöscht werden wenn auch keine Werte mehr für sie vorliegen

        Permission: `delete_property`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 19
                    }
                }
        404:
          description: Eigenschaft wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://localhost/xentral/20.1/www/api/docs.html#error-7452"
                    }
                }

/v1/eigenschaftenwerte:
  description: Eigenschaftenwerte für Artikel abrufen, erstellen, bearbeiten und löschen
  get:
    displayName: Eigenschaftenwerte abrufen
    description: |
      Eigenschaften abrufen

      Permission: `list_property_value`
    queryParameters:
      artikel:
        description: Artikel Id der die Eigenschaft zugewiesen ist (genaue Übereinstimmung)
        type: integer
        required: false
      artikeleigenschaften:
        description: Id der Eigenschaft (genaue Übereinstimmung)
        type: string
        required: false
      wert:
        description: Wert der Eigenschaft (genaue Übereinstimmung)
        type: string
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=artikel,-wert`)

          Verfügbare Felder: `artikel`, `wert`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Eigenschaftwert anlegen
    description: |
      Eigenschaftenwert anlegen

      Permission: `create_property_value`
    body:
      application/json:
        properties:
          artikel:
            description: Artikel Id der der Eigenschaftenwert zugewiesen werden soll
            type: integer
            required: true
          artikeleigenschaften:
            description: Id der Eigenschaft
            type: integer
            required: true
          wert:
            description: Wert der Eigenschaft
            type: string
            required: false
        example: |
          {
              "artikel": 1,
              "artikeleigenschaften": 19,
              "wert": "Gelb"
          }
    responses:
      201:
        description: Request erfolgreich; Angelegter Eigenschaftenwert wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 203,
                      "artikel": 1,
                      "artikeleigenschaften": 19,
                      "wert": "Gelb"
                  }
              }

  /{id}:
    description: Einzelnen Eigenschaftenwert abrufen, bearbeiten, oder löschen
    uriParameters:
      id:
        type: integer
        description: Eigenschaftenwert-ID
    get:
      displayName: Einzelnen Eigenschaftenwert abrufen
      description: |
        Einzelnen Eigenschaftenwert abrufen

        Permission: `view_property_value`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 203,
                        "artikel": 1,
                        "artikeleigenschaften": 19,
                        "wert": "Gelb"
                    }
                }
        404:
          description: Eigenschaftenwert wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Eigenschaftenwert bearbeiten
      description: |
        Eigenschaftenwert bearbeiten

        Permission: `edit_property_value`
      body:
        application/json:
          example: |
            {
                "wert": "Holz"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierter Eigenschaftenwert wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 203,
                        "artikel": 1,
                        "artikeleigenschaften": 19,
                        "wert": "Holz"
                    }
                }
    delete:
      displayName: Einzelnen Eigenschaftenwert löschen
      description: |
        Einzelnen Eigenschaftenwert löschen

        Permission: `delete_property_value`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 203
                    }
                }
        404:
          description: Eigenschaftenwert wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://localhost/xentral/20.1/www/api/docs.html#error-7452"
                    }
                }

/v1/belege/angebote:
  description: Angebote abrufen
  get:
    displayName: Angebotsliste abrufen
    description: |
      Angebotsliste abrufen und Angebote suchen

      Permission: `list_quotes`
    queryParameters:
      status:
        description: |
          Suche nach Angebotsstatus (genaue Übereinstimmung)

          Mögliche Werte: `angelegt`, `abgelehnt`, `beauftragt`, `bestellt`, `freigegeben`, `versendet`, `storniert`
        type: string
        required: false
      belegnr:
        description: Suche nach Belegnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      belegnr_equals:
        description: Suche nach Belegnummer (genaue Übereinstimmung)
        type: string
        required: false
      belegnr_startswith:
        description: Suche nach Belegnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      belegnr_endswith:
        description: Suche nach Belegnummer (Übereinstimmung am Ende)
        type: string
        required: false
      kundennummer:
        description: Suche nach Kundennummer (ungefähre Übereinstimmung)
        type: string
        required: false
      kundennummer_equals:
        description: Suche nach Kundennummer (genaue Übereinstimmung)
        type: string
        required: false
      kundennummer_startswith:
        description: Suche nach Kundennummer (Übereinstimmung am Anfang)
        type: string
        required: false
      kundennummer_endswith:
        description: Suche nach Kundennummer (Übereinstimmung am Ende)
        type: string
        required: false
      datum:
        description: Suche nach bestimmtem Belegdatum (genaue Übereinstimmung)
        type: string
        required: false
      datum_gt:
        description: Suche nach bestimmtem Belegdatum (Datum größer Suchwert)
        type: string
        required: false
      datum_gte:
        description: Suche nach bestimmtem Belegdatum (Datum größer gleich Suchwert)
        type: string
        required: false
      datum_lt:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner Suchwert)
        type: string
        required: false
      datum_lte:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      projekt:
        description: Angebote eines bestimmten Projekt filtern
        type: integer
        required: false
      sort:
        description:  |
          Sortierung (Beispiel: `sort=belegnr`)

          Verfügbare Felder: `belegnr`, `datum`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=positionen`)

          Verfügbare Includes: `positionen`, `protokoll`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000

  /{id}:
    description: Einzelnes Angebot abrufen
    uriParameters:
      id:
        type: integer
        description: Angebots-ID
    get:
      displayName: Einzelnes Angebot abrufen
      description: |
        Einzelnes Angebot abrufen

        Permission: `list_quotes`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 4,
                        "firma": 1,
                        "projekt": "1",
                        "status": "versendet",
                        "belegnr": "100003",
                        "kundennummer": "10000",
                        "datum": "2019-06-28",
                        "gueltigbis": "2019-04-10",
                        "adresse": 3,
                        "typ": "firma",
                        "name": "Max Muster",
                        "titel": "",
                        "strasse": "Musterstrasse 6",
                        "plz": "12345",
                        "ort": "Musterdorf",
                        "land": "DE",
                        "...": "Ausgabe gekürzt"
                    }
                }
        404:
          description: Angebot wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }


/v1/belege/auftraege:
  description: Aufträge abrufen
  get:
    displayName: Auftragsliste abrufen
    description: |
      Auftragsliste abrufen und Aufträge suchen

      Permission: `list_orders`
    queryParameters:
      status:
        description: |
          Suche nach Auftragssstatus (genaue Übereinstimmung)

          Mögliche Werte: `angelegt`, `bestellt`, `freigegeben`, `versendet`, `abgeschlossen`, `storniert`,
        type: string
        required: false
      belegnr:
        description: Suche nach Belegnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      belegnr_equals:
        description: Suche nach Belegnummer (genaue Übereinstimmung)
        type: string
        required: false
      belegnr_startswith:
        description: Suche nach Belegnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      belegnr_endswith:
        description: Suche nach Belegnummer (Übereinstimmung am Ende)
        type: string
        required: false
      kundennummer:
        description: Suche nach Kundennummer (ungefähre Übereinstimmung)
        type: string
        required: false
      kundennummer_equals:
        description: Suche nach Kundennummer (genaue Übereinstimmung)
        type: string
        required: false
      kundennummer_startswith:
        description: Suche nach Kundennummer (Übereinstimmung am Anfang)
        type: string
        required: false
      kundennummer_endswith:
        description: Suche nach Kundennummer (Übereinstimmung am Ende)
        type: string
        required: false
      datum:
        description: Suche nach bestimmtem Belegdatum (genaue Übereinstimmung)
        type: string
        required: false
      datum_gt:
        description: Suche nach bestimmtem Belegdatum (Datum größer Suchwert)
        type: string
        required: false
      datum_gte:
        description: Suche nach bestimmtem Belegdatum (Datum größer gleich Suchwert)
        type: string
        required: false
      datum_lt:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner Suchwert)
        type: string
        required: false
      datum_lte:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      angebot:
        description: Aufträge nach Angebotsnummer filtern (genaue Übereinstimmung)
        type: string
        required: false
      angebotid:
        description: Aufträge nach Angebots-ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      projekt:
        description: Aufträge eines bestimmten Projekt filtern
        type: integer
        required: false
      sort:
        description:  |
          Sortierung (Beispiel: `sort=belegnr`)

          Verfügbare Felder: `belegnr`, `datum`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=positionen`)

          Verfügbare Includes: `positionen`, `protokoll`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000

  /{id}:
    description: Einzelnen Auftrag abrufen
    uriParameters:
      id:
        type: integer
        description: Auftrag-ID
    get:
      displayName: Einzelnen Auftrag abrufen
      description: |
        Einzelnen Auftrag abrufen

        Permission: `list_orders`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 4,
                        "firma": 1,
                        "projekt": "1",
                        "status": "freigegeben",
                        "belegnr": "200003",
                        "kundennummer": "10002",
                        "ihrebestellnummer": null,
                        "datum": "2019-02-26",
                        "adresse": 5,
                        "typ": "firma",
                        "name": "Hans Huber",
                        "titel": "",
                        "strasse": "Musterstrasse 6",
                        "plz": "12345",
                        "ort": "Musterstadt",
                        "land": "DE",
                        "...": "Ausgabe gekürzt"
                    }
                }
        404:
          description: Auftrag wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }


/v1/belege/lieferscheine:
  description: Lieferscheine abrufen
  get:
    displayName: Lieferscheinliste abrufen
    description: |
      Lieferscheinliste abrufen und Lieferscheine suchen

      Permission: `list_delivery_notes`
    queryParameters:
      status:
        description: |
          Suche nach Lieferschein-Status (genaue Übereinstimmung)

          Mögliche Werte: `angelegt`, `freigegeben`, `abgeschlossen`, `versendet`, `storniert`
        type: string
        required: false
      belegnr:
        description: Suche nach Belegnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      belegnr_equals:
        description: Suche nach Belegnummer (genaue Übereinstimmung)
        type: string
        required: false
      belegnr_startswith:
        description: Suche nach Belegnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      belegnr_endswith:
        description: Suche nach Belegnummer (Übereinstimmung am Ende)
        type: string
        required: false
      internet:
        description: Suche nach Internetnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      internet_equals:
        description: Suche nach Internetnummer (genaue Übereinstimmung)
        type: string
        required: false
      internet_startswith:
        description: Suche nach Internetnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      internet_endswith:
        description: Suche nach Internetnummer (Übereinstimmung am Ende)
        type: string
        required: false
      kundennummer:
        description: Suche nach Kundennummer (ungefähre Übereinstimmung)
        type: string
        required: false
      kundennummer_equals:
        description: Suche nach Kundennummer (genaue Übereinstimmung)
        type: string
        required: false
      kundennummer_startswith:
        description: Suche nach Kundennummer (Übereinstimmung am Anfang)
        type: string
        required: false
      kundennummer_endswith:
        description: Suche nach Kundennummer (Übereinstimmung am Ende)
        type: string
        required: false
      datum:
        description: Suche nach bestimmtem Belegdatum (genaue Übereinstimmung)
        type: string
        required: false
      datum_gt:
        description: Suche nach bestimmtem Belegdatum (Datum größer Suchwert)
        type: string
        required: false
      datum_gte:
        description: Suche nach bestimmtem Belegdatum (Datum größer gleich Suchwert)
        type: string
        required: false
      datum_lt:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner Suchwert)
        type: string
        required: false
      datum_lte:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      auftrag:
        description: Lieferscheine nach Auftragsnummer filtern (genaue Übereinstimmung)
        type: string
        required: false
      auftragid:
        description: Lieferscheine nach Auftrags-ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      projekt:
        description: Lieferscheine eines bestimmten Projekt filtern
        type: integer
        required: false
      sort:
        description:  |
          Sortierung (Beispiel: `sort=belegnr`)

          Verfügbare Felder: `belegnr`, `datum`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=positionen`)

          Verfügbare Includes: `positionen`, `protokoll`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000

  /{id}:
    description: Einzelnen Lieferschein abrufen
    uriParameters:
      id:
        type: integer
        description: Lieferschein-ID
    get:
      displayName: Einzelnen Lieferschein abrufen
      description: |
        Einzelnen Lieferschein abrufen

        Permission: `list_delivery_notes`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 4,
                        "firma": 1,
                        "projekt": "1",
                        "status": "freigegeben",
                        "lieferscheinart": "",
                        "belegnr": "300003",
                        "kundennummer": "10001",
                        "ihrebestellnummer": "",
                        "datum": "2019-06-12",
                        "adresse": 4,
                        "typ": "frau",
                        "name": "Eva Müller",
                        "strasse": "Musterweg 12a",
                        "plz": "12345",
                        "ort": "Musterdorf",
                        "land": "DE",
                        "...": "Ausgabe gekürzt"
                    }
                }
        404:
          description: Lieferschein wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }


/v1/belege/rechnungen:
  description: Rechnungen abrufen
  get:
    displayName: Rechnungsliste abrufen
    description: |
      Rechnungsliste abrufen und Rechnungen suchen

      Permission: `list_invoices`
    queryParameters:
      status:
        description: |
          Suche nach Rechnungs-Status (genaue Übereinstimmung)

          Mögliche Werte: `angelegt`, `freigegeben`, `versendet`, `storniert`
        type: string
        required: false
      belegnr:
        description: Suche nach Belegnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      belegnr_equals:
        description: Suche nach Belegnummer (genaue Übereinstimmung)
        type: string
        required: false
      belegnr_startswith:
        description: Suche nach Belegnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      belegnr_endswith:
        description: Suche nach Belegnummer (Übereinstimmung am Ende)
        type: string
        required: false
      kundennummer:
        description: Suche nach Kundennummer (ungefähre Übereinstimmung)
        type: string
        required: false
      kundennummer_equals:
        description: Suche nach Kundennummer (genaue Übereinstimmung)
        type: string
        required: false
      kundennummer_startswith:
        description: Suche nach Kundennummer (Übereinstimmung am Anfang)
        type: string
        required: false
      kundennummer_endswith:
        description: Suche nach Kundennummer (Übereinstimmung am Ende)
        type: string
        required: false
      datum:
        description: Suche nach bestimmtem Belegdatum (genaue Übereinstimmung)
        type: string
        required: false
      datum_gt:
        description: Suche nach bestimmtem Belegdatum (Datum größer Suchwert)
        type: string
        required: false
      datum_gte:
        description: Suche nach bestimmtem Belegdatum (Datum größer gleich Suchwert)
        type: string
        required: false
      datum_lt:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner Suchwert)
        type: string
        required: false
      datum_lte:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      auftrag:
        description: Rechnungen nach Auftragsnummer filtern (genaue Übereinstimmung)
        type: string
        required: false
      auftragid:
        description: Rechnungen nach Auftrags-ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      projekt:
        description: Rechnungen eines bestimmten Projekt filtern
        type: integer
        required: false
      sort:
        description:  |
          Sortierung (Beispiel: `sort=belegnr`)

          Verfügbare Felder: `belegnr`, `datum`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=positionen`)

          Verfügbare Includes: `positionen`, `protokoll`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000

  /{id}:
    description: Einzelne Rechnung abrufen oder löschen
    uriParameters:
      id:
        type: integer
        description: Rechnungs-ID
    get:
      displayName: Einzelne Rechnung abrufen
      description: |
        Einzelne Rechnung abrufen

        Permission: `view_invoice`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 4,
                        "firma": 1,
                        "projekt": "1",
                        "status": "versendet",
                        "belegnr": "400002",
                        "datum": "2019-05-21",
                        "kundennummer": "10000",
                        "adresse": 3,
                        "typ": "firma",
                        "name": "Max Muster",
                        "strasse": "Musterstrasse 6",
                        "plz": "12345",
                        "ort": "Musterdorf",
                        "land": "DE",
                        "...": "Ausgabe gekürzt"
                    }
                }
        404:
          description: Rechnung wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }

    delete:
      displayName: Einzelne Rechnung löschen
      description: |
        Einzelne Rechnung löschen

        Permission: `delete_invoice`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 18
                    }
                }
        404:
          description: Rechnung wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://localhost/xentral/20.1/www/api/docs.html#error-7452"
                    }
                }


/v1/belege/gutschriften:
  description: Gutschriften/Stornorechnungen abrufen
  get:
    displayName: Gutschriftenliste abrufen
    description: |
      Gutschriftenliste abrufen und Gutschriften suchen

      Permission: `list_credit_memos`
    queryParameters:
      status:
        description: |
          Suche nach Gutschriften-Status (genaue Übereinstimmung)

          Mögliche Werte: `angelegt`, `freigegeben`, `versendet`, `storniert`
        type: string
        required: false
      belegnr:
        description: Suche nach Belegnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      belegnr_equals:
        description: Suche nach Belegnummer (genaue Übereinstimmung)
        type: string
        required: false
      belegnr_startswith:
        description: Suche nach Belegnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      belegnr_endswith:
        description: Suche nach Belegnummer (Übereinstimmung am Ende)
        type: string
        required: false
      kundennummer:
        description: Suche nach Kundennummer (ungefähre Übereinstimmung)
        type: string
        required: false
      kundennummer_equals:
        description: Suche nach Kundennummer (genaue Übereinstimmung)
        type: string
        required: false
      kundennummer_startswith:
        description: Suche nach Kundennummer (Übereinstimmung am Anfang)
        type: string
        required: false
      kundennummer_endswith:
        description: Suche nach Kundennummer (Übereinstimmung am Ende)
        type: string
        required: false
      datum:
        description: Suche nach bestimmtem Belegdatum (genaue Übereinstimmung)
        type: string
        required: false
      datum_gt:
        description: Suche nach bestimmtem Belegdatum (Datum größer Suchwert)
        type: string
        required: false
      datum_gte:
        description: Suche nach bestimmtem Belegdatum (Datum größer gleich Suchwert)
        type: string
        required: false
      datum_lt:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner Suchwert)
        type: string
        required: false
      datum_lte:
        description: Suche nach bestimmtem Belegdatum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      rechnung:
        description: Gutschriften nach Rechnungsnummer filtern (genaue Übereinstimmung)
        type: string
        required: false
      rechnungid:
        description: Gutschriften nach Rechnungs-ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      projekt:
        description: Gutschriften eines bestimmten Projekt filtern
        type: integer
        required: false
      sort:
        description:  |
          Sortierung (Beispiel: `sort=belegnr`)

          Verfügbare Felder: `belegnr`, `datum`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=positionen`)

          Verfügbare Includes: `positionen`, `protokoll`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000

  /{id}:
    description: Einzelne Gutschrift abrufen
    uriParameters:
      id:
        type: integer
        description: Gutschriften-ID
    get:
      displayName: Einzelne Gutschrift abrufen
      description: |
        Einzelne Gutschrift abrufen

        Permission: `view_credit_memo`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 1,
                        "firma": 1,
                        "projekt": "1",
                        "status": "versendet",
                        "belegnr": "900000",
                        "datum": "2019-08-07",
                        "stornorechnung": 0,
                        "kundennummer": "10001",
                        "adresse": 4,
                        "typ": "frau",
                        "name": "Eva Müller",
                        "strasse": "Musterweg 12a",
                        "plz": "12345",
                        "ort": "Musterdorf",
                        "land": "DE",
                        "...": "Ausgabe gekürzt"
                    }
                }
        404:
          description: Gutschrift wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }

/v1/crmdokumente:
  description: CRM-Dokumente abrufen, anlegen und bearbeiten
  get:
    displayName: CRM-Dokumente abrufen
    description: |
      CRM-Dokumente abrufen und suchen

      Permission: `list_crm_documents`
    queryParameters:
      typ:
        description: Suche nach CRM-Dokumenten eines Typs (ungefähre Übereinstimmung)
        type: string
        required: false
      typ_equals:
        description: |
          Suche nach CRM-Dokumenten eines Typs (genaue Übereinstimmung)

          Verfügbare Typen: `brief`, `email`, `telefon`, `notiz`
        type: string
        required: false
      typ_exact:
        description: (deprecated) gleich wie typ_equals
        type: string
        required: false
      betreff:
        description: Suche nach Betreff (ungefähre Übereinstimmung)
        type: string
        required: false
      betreff_equals:
        description: Suche nach Betreff (genaue Übereinstimmung)
        type: string
        required: false
      betreff_exakt:
        description: (deprecated) gleich wie betreff_equals
        type: string
        required: false
      projekt:
        description: Filtere nach Projekt (Projekt-ID)
        type: integer
        required: false
      adresse_from:
        description: Filtere nach Absender (Adresse-ID)
        type: integer
        required: false
      adresse_to:
        description: Filtere nach Empfänger (Adresse-ID)
        type: integer
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

          Verfügbare Includes: `projekt`, `adresse_to`, `adresse_from`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: CRM-Dokument anlegen
    description: |
      CRM-Dokument anlegen

      Permission: `create_crm_document`
    body:
      application/json:
        properties:
          typ:
            description: Mögliche Werte sind `email`, `brief`, `telefon`, `notiz`
            required: true
            type: string
          betreff:
            description: Betreff des CRM-Dokuments
            required: true
            type: string
          content:
            description: Inhalt des CRM-Dokuments
            required: false
            type: string
          adresse_from:
            description: Absender/Mitarbeiter (Adresse-ID)
            required: false
            type: integer
          adresse_to:
            description: Empfänger/Kunde (Adresse-ID)
            required: false
            type: integer
          von:
            description: Anzeigename Absender
            required: false
            type: string
          an:
            description: Anzeigename Empfänger
            required: false
            type: string
          email_an:
            description: E-Mail Adresse Empfänger
            required: false
            type: string
          email_cc:
            description: E-Mail Adresse CC
            required: false
            type: string
          email_bcc:
            description: E-Mail Adresse BCC
            required: false
            type: string
          adresse:
            description: Anschrift 1. Adresszeile
            required: false
            type: string
          plz:
            description: Anschrift Postleitzahl
            required: false
            type: string
          ort:
            description: Anschrift Ort
            required: false
            type: string
          land:
            description: Anschrift Land
            required: false
            type: string
          datum:
            description: Datum des Dokuments
            required: false
            type: date-only
          uhrzeit:
            description: Uhrzeit des Dokuments
            required: false
            type: time-only
          projekt:
            description: Projekt-ID
            required: false
            type: integer
          signatur:
            description: Signatur verwendet (1=ja, 0=nein)
            required: false
            type: integer
          printer:
            description: Nachricht wurde gedruckt (1=ja, 0=nein)
            required: false
            type: integer
          fax:
            description: Fax wurde versendet (1=ja, 0=nein)
            required: false
            type: integer
          sent:
            description: Nachricht wurde versendet (1=ja, 0=nein)
            required: false
            type: integer
          deleted:
            description: Nachricht wurde gelöscht (1=ja, 0=nein)
            required: false
            type: integer
        example: |
          {
            "typ": "email",
            "betreff": "AW: Antwort auf eine Frage",
            "adresse_from": 1,
            "adresse_to": 7,
            "projekt": 1
          }
    responses:
      200:
        description: Request erfolgreich
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 14,
                      "adresse_from": 1,
                      "adresse_to": 7,
                      "typ": "email",
                      "von": "",
                      "an": "",
                      "email_an": "",
                      "send_as": "",
                      "email": "",
                      "email_cc": null,
                      "email_bcc": null,
                      "bearbeiter": null,
                      "firma_an": "",
                      "adresse": "",
                      "ansprechpartner": null,
                      "plz": "",
                      "ort": "",
                      "land": "",
                      "datum": "0000-00-00",
                      "uhrzeit": null,
                      "betreff": "AW: Antwort auf eine Frage",
                      "content": "",
                      "projekt": 1,
                      "internebezeichnung": "",
                      "signatur": 0,
                      "fax": 0,
                      "sent": 0,
                      "printer": 0,
                      "deleted": 0
                  }
              }
      400:
        description: Request Body Fehlerhaft
        body:
          application/json:
            example: |
              {
                  "error": {
                      "code": 7453,
                      "http_code": 400,
                      "message": "Validation error",
                      "href": "http://localhost/xentral/20.1/www/api/docs.html#error-7453",
                      "details": [
                          "The attribute 'betreff' is required."
                      ]
                  }
              }

  /{id}:
    description: Einzelne CRM-Dokumente abrufen
    uriParameters:
      id:
        type: integer
        description: CRM-Dokumenten-ID
    get:
      displayName: Einzelnes CRM-Dokument abrufen
      description: |
        Einzelnes CRM-Dokument abrufen.

        Permission: `view_crm_document`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 4,
                        "adresse_from": 1,
                        "adresse_to": 7,
                        "typ": "telefon",
                        "von": "",
                        "an": "",
                        "email_an": "",
                        "send_as": "",
                        "email": "",
                        "email_cc": "",
                        "email_bcc": "",
                        "bearbeiter": "Mitarbeiter XY",
                        "firma_an": "",
                        "adresse": "",
                        "ansprechpartner": "",
                        "plz": "",
                        "ort": "",
                        "land": "",
                        "datum": "2019-11-05",
                        "uhrzeit": "12:04:00",
                        "betreff": "Fragen zur Bedienung",
                        "content": "- Keine Fragen, alles klar",
                        "projekt": 1,
                        "internebezeichnung": "",
                        "signatur": 0,
                        "fax": 0,
                        "sent": 0,
                        "printer": 0,
                        "deleted": 0
                    }
                }
        404:
          description: CRM-Dokument wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: CRM-Dokument bearbeiten
      description: |
        CRM-Dokument bearbeiten

        Permission: `view_crm_document`
      body:
        application/json:
          properties:
            typ:
              description: Mögliche Werte sind `email`, `brief`, `telefon`, `notiz`
              required: true
              type: string
            betreff:
              description: Betreff des CRM-Dokuments
              required: true
              type: string
            content:
              description: Inhalt des CRM-Dokuments
              required: false
              type: string
            adresse_from:
              description: Absender/Mitarbeiter (Adresse-ID)
              required: false
              type: integer
            adresse_to:
              description: Empfänger/Kunde (Adresse-ID)
              required: false
              type: integer
            von:
              description: Anzeigename Absender
              required: false
              type: string
            an:
              description: Anzeigename Empfänger
              required: false
              type: string
            email_an:
              description: E-Mail Adresse Empfänger
              required: false
              type: string
            email_cc:
              description: E-Mail Adresse CC
              required: false
              type: string
            email_bcc:
              description: E-Mail Adresse BCC
              required: false
              type: string
            adresse:
              description: Anschrift 1. Adresszeile
              required: false
              type: string
            plz:
              description: Anschrift Postleitzahl
              required: false
              type: string
            ort:
              description: Anschrift Ort
              required: false
              type: string
            land:
              description: Anschrift Land
              required: false
              type: string
            datum:
              description: Datum des Dokuments
              required: false
              type: date-only
            uhrzeit:
              description: Uhrzeit des Dokuments
              required: false
              type: time-only
            projekt:
              description: Projekt-ID
              required: false
              type: integer
            signatur:
              description: Signatur verwendet (1=ja, 0=nein)
              required: false
              type: integer
            printer:
              description: Nachricht wurde gedruckt (1=ja, 0=nein)
              required: false
              type: integer
            fax:
              description: Fax wurde versendet (1=ja, 0=nein)
              required: false
              type: integer
            sent:
              description: Nachricht wurde versendet (1=ja, 0=nein)
              required: false
              type: integer
            deleted:
              description: Nachricht wurde gelöscht (1=ja, 0=nein)
              required: false
              type: integer
          example: |
            {
            	"typ": "brief",
            	"betreff": "Test Brief 14"
            }
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 14,
                        "adresse_from": 1,
                        "adresse_to": 7,
                        "typ": "brief",
                        "von": "",
                        "an": "",
                        "email_an": "",
                        "send_as": "",
                        "email": "",
                        "email_cc": null,
                        "email_bcc": null,
                        "bearbeiter": null,
                        "firma_an": "",
                        "adresse": "",
                        "ansprechpartner": null,
                        "plz": "",
                        "ort": "",
                        "land": "",
                        "datum": "0000-00-00",
                        "uhrzeit": null,
                        "betreff": "Test Brief 14",
                        "content": "",
                        "projekt": 1,
                        "internebezeichnung": "",
                        "signatur": 0,
                        "fax": 0,
                        "sent": 0,
                        "printer": 0,
                        "deleted": 0
                    }
                }
        400:
          description: Request Body Fehlerhaft
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7453,
                        "http_code": 400,
                        "message": "Validation error",
                        "href": "http://localhost/xentral/20.1/www/api/docs.html#error-7453",
                        "details": [
                            "The attribute 'betreff' is required."
                        ]
                    }
                }
        404:
          description: CRM-Dokument wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    delete:
      displayName: CRM-Dokument löschen
      description: |
        CRM-Dokument löschen

        Permission: `delete_crm_document`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 14
                    }
                }
        404:
          description: CRM-Dokument wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }

/v1/dateien:
  description: Dateiliste abrufen und Dateien downloaden
  get:
    displayName: Dateiliste abrufen
    description: |
      Dateiliste abrufen.

      Permission: `list_files`
    queryParameters:
      titel:
        description: Suche nach Dateititel (ungefähre Übereinstimmung)
        type: string
        required: false
      titel_equals:
        description: Suche nach Dateititel (genaue Übereinstimmung)
        type: string
        required: false
      titel_startswith:
        description: Suche nach Dateititel (Übereinstimmung am Anfang)
        type: string
        required: false
      titel_endswith:
        description: Suche nach Dateititel (Übereinstimmung am Ende)
        type: string
        required: false
      dateiname:
        description: Suche nach Dateiname (ungefähre Übereinstimmung)
        type: string
        required: false
      dateiname_equals:
        description: Suche nach Dateiname (genaue Übereinstimmung)
        type: string
        required: false
      dateiname_startswith:
        description: Suche nach Dateiname (Übereinstimmung am Anfang)
        type: string
        required: false
      dateiname_endswith:
        description: Suche nach Dateiname (Übereinstimmung am Ende)
        type: string
        required: false
      belegtyp:
        description: Suche nach Zuweisungen zu Belegtyp (ungefähre Übereinstimmung)
        type: string
        required: false
      stichwort:
        description: Suche nach Stichwort (ungefähre Übereinstimmung)
        type: string
        required: false
      sort:
        description:  |
          Sortierung (Beispiel: `sort=dateiname`)

          Verfügbare Felder: `dateiname`, `datum`, `titel`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=stichwoerter`)

          Verfügbare Includes: `stichwoerter`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Datei anlegen/hochladen
    description: |
      Datei anlegen/hochladen

      Permission: `create_files`
    body:
      application/x-www-form-urlencoded:
        properties:
          file_content:
            description: Datei-Inhalt (Raw-Daten)
            required: true
            type: file
          titel:
            description: Datei-Titel
            required: true
            type: string
          dateiname:
            description: Dateiname (ohne Verzeichnis; Beispiel `foo.jpg`)
            required: true
            type: string
          beschreibung:
            description: Beschreibungstext
            required: false
            type: string
    responses:
      201:
        description: Request erfolgreich; Angelegte Datei wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 123,
                      "titel": "Rechnung 400027",
                      "beschreibung": "Rechnung 400027 von Kunde Max Mustermann",
                      "nummer": "",
                      "firma": 1,
                      "ersteller": "",
                      "datum": "2018-11-15",
                      "version": 1,
                      "dateiname": "RE400027.pdf",
                      "bemerkung": "Initiale Version",
                      "size": "8427",
                      "stichwoerter": null,
                      "belegtypen": null,
                      "mimetype": "application/pdf",
                      "links": {
                          "download": "http://www.example.com/api/v1/dateien/123/download",
                          "base64": "http://www.example.com/api/v1/dateien/123/base64"
                      }
                  }
              }

  /{id}:
    description: Informationen zu einer Datei abrufen
    uriParameters:
      id:
        type: integer
        description: Datei-ID
    get:
      displayName: Informationen zu einer Datei abrufen
      description: |
        Informationen zu einer Datei abrufen

        Permission: `view_file`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 115,
                        "titel": "Rechnung 400027",
                        "beschreibung": "",
                        "nummer": "",
                        "firma": 1,
                        "ersteller": "Max Mustermann",
                        "datum": "2018-11-15",
                        "version": 1,
                        "dateiname": "RE400027.pdf",
                        "bemerkung": "Initiale Version",
                        "size": "8427",
                        "stichwoerter": "Belege",
                        "belegtypen": "Verbindlichkeiten",
                        "mimetype": "application/pdf",
                        "links": {
                            "download": "http://www.example.com/api/v1/dateien/115/download",
                            "base64": "http://www.example.com/api/v1/dateien/115/base64"
                        }
                    }
                }
        404:
          description: Datei wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    /download:
      description: Datei downloaden
      get:
        displayName: Datei downloaden
        description: |
          Datei downloaden

          Permission: `handle_assets`
        responses:
          200:
            description: |
              Request erfolgreich

              Der Content-Type ist abhängig vom Mime-Type der Datei die gesendet wird.
    /base64:
      description: Dateiinhalt base64-kodiert abrufen
      get:
        displayName: Dateiinhalt base64-kodiert abrufen
        description: |
          Dateiinhalt base64-kodiert abrufen

          Permission: `handle_assets`
        responses:
          200:
            description: Request erfolgreich
            body:
              text/plain:
                example: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=

/v1/docscan:
  description: DocumentScanner-Dateiliste abrufen und Dateien downloaden
  get:
    displayName: DocumentScanner-Dateiliste abrufen
    description: |
      DocumentScanner-Dateiliste abrufen

      Permission: `list_scanned_documents`
    queryParameters:
      titel:
        description: Suche nach Dateititel (ungefähre Übereinstimmung)
        type: string
        required: false
      titel_equals:
        description: Suche nach Dateititel (genaue Übereinstimmung)
        type: string
        required: false
      titel_startswith:
        description: Suche nach Dateititel (Übereinstimmung am Anfang)
        type: string
        required: false
      titel_endswith:
        description: Suche nach Dateititel (Übereinstimmung am Ende)
        type: string
        required: false
      dateiname:
        description: Suche nach Dateiname (ungefähre Übereinstimmung)
        type: string
        required: false
      dateiname_equals:
        description: Suche nach Dateiname (genaue Übereinstimmung)
        type: string
        required: false
      dateiname_startswith:
        description: Suche nach Dateiname (Übereinstimmung am Anfang)
        type: string
        required: false
      dateiname_endswith:
        description: Suche nach Dateiname (Übereinstimmung am Ende)
        type: string
        required: false
      datum:
        description: Suche nach Datum (genaue Übereinstimmung; Format `YYYY-MM-DD`)
        type: string
        required: false
      datum_gt:
        description: Suche nach Datum (Datum größer Suchwert)
        type: string
        required: false
      datum_gte:
        description: Suche nach Datum (Datum größer gleich Suchwert)
        type: string
        required: false
      datum_lt:
        description: Suche nach Datum (Datum kleiner Suchwert)
        type: string
        required: false
      datum_lte:
        description: Suche nach Datum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      belegtyp:
        description: Suche nach Zuweisungen zu Belegtyp (ungefähre Übereinstimmung)
        type: string
        required: false
      stichwort:
        description: Suche nach Stichwort (ungefähre Übereinstimmung)
        type: string
        required: false
      firma:
        description: Suche nach Firmen-ID
        type: integer
        required: false
      sort:
        description:  |
          Sortierung (Beispiel: `sort=dateiname`)

          Verfügbare Felder: `dateiname`, `datum`, `titel`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=stichwoerter`)

          Verfügbare Includes: `stichwoerter`, `metadata`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: DocumentScanner-Datei anlegen/hochladen
    description: |
      DocumentScanner-Datei anlegen/hochladen

      Permission: `create_scanned_documents`
    body:
      multipart/form-data:
        properties:
          file_content:
            description: Datei-Inhalt
            required: true
            type: file
          titel:
            description: Datei-Titel
            required: true
            type: string
          dateiname:
            description: Dateiname (ohne Verzeichnis; Beispiel `beleg.pdf`)
            required: true
            type: string
          beschreibung:
            description: Datei-Beschreibungstext
            required: false
            type: string
          meta:
            description: Meta-Daten
            required: false
            type: array
          meta.invoice_number:
            description: Rechnungsnummer
            required: false
            type: string
          meta.invoice_date:
            description: Rechnungsdatum (Format `YYYY-MM-DD`)
            required: false
            type: string
          meta.invoice_amount:
            description: Rechnungsbetrag brutto (Beispiel `12345.67`)
            required: false
            type: string
          meta.invoice_tax:
            description: Mehrwertsteuerbetrag der Rechnung (Beispiel `12345.67`)
            required: false
            type: string
          meta.invoice_currency:
            description: Währungscode der Rechnung (Beispiel `EUR`)
            required: false
            type: string
      application/x-www-form-urlencoded:
        properties:
          file_content:
            description: Datei-Inhalt (Raw-Daten)
            required: true
            type: string
          titel:
            description: Datei-Titel
            required: true
            type: string
          dateiname:
            description: Dateiname (ohne Verzeichnis; Beispiel `beleg.pdf`)
            required: true
            type: string
          beschreibung:
            description: Datei-Beschreibungstext
            required: false
            type: string
          meta:
            description: Meta-Daten
            required: false
            type: array
          meta.invoice_number:
            description: Rechnungsnummer
            required: false
            type: string
          meta.invoice_date:
            description: Rechnungsdatum (Format `YYYY-MM-DD`)
            required: false
            type: string
          meta.invoice_amount:
            description: Rechnungsbetrag brutto (Beispiel `12345.67`)
            required: false
            type: string
          meta.invoice_tax:
            description: Mehrwertsteuerbetrag der Rechnung (Beispiel `12345.67`)
            required: false
            type: string
          meta.invoice_currency:
            description: Währungscode der Rechnung (Beispiel `EUR`)
            required: false
            type: string
    responses:
      201:
        description: Request erfolgreich; Angelegte Datei wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 123,
                      "titel": "Rechnung 400027",
                      "beschreibung": "Rechnung 400027 von Kunde Max Mustermann",
                      "nummer": "",
                      "firma": 1,
                      "ersteller": "",
                      "datum": "2018-11-15",
                      "version": 1,
                      "dateiname": "RE400027.pdf",
                      "bemerkung": "Initiale Version",
                      "size": "8427",
                      "mimetype": "application/pdf",
                      "links": {
                          "download": "http://www.example.com/api/v1/dateien/123/download",
                          "base64": "http://www.example.com/api/v1/dateien/123/base64"
                      }
                  }
              }

  /{id}:
    description: Informationen zu einer DocumentScanner-Datei abrufen
    uriParameters:
      id:
        type: integer
        description: Datei-ID
    get:
      displayName: Informationen zu einer DocumentScanner-Datei abrufen
      description: |
        Informationen zu einer DocumentScanner-Datei abrufen

        Permission: `view_scanned_documents`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 115,
                        "titel": "Rechnung 400027",
                        "beschreibung": "",
                        "nummer": "",
                        "firma": 1,
                        "ersteller": "Max Mustermann",
                        "datum": "2018-11-15",
                        "version": 1,
                        "dateiname": "RE400027.pdf",
                        "bemerkung": "Initiale Version",
                        "size": "8427",
                        "mimetype": "application/pdf",
                        "links": {
                            "download": "http://www.example.com/api/v1/dateien/115/download",
                            "base64": "http://www.example.com/api/v1/dateien/115/base64"
                        }
                    }
                }
        404:
          description: Datei wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }

/v1/gruppen:
  description: Gruppen anlegen, bearbeiten und abrufen
  get:
    displayName: Gruppenliste abrufen
    description: |
      Gruppenliste abrufen

      Permission: `list_groups`
    queryParameters:
      name:
        description: Gruppe mit bestimmter Bezeichnung suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      name_exakt:
        description: Gruppe mit bestimmter Bezeichnung suchen (genaue Übereinstimmung)
        type: string
        required: false
      kennziffer:
        description: Gruppen mit bestimmter Kennziffer suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      kennziffer_exakt:
        description: Gruppen mit bestimmter Kennziffer suchen (genaue Übereinstimmung)
        type: string
        required: false
      art:
        description: |
          Gruppen mit bestimmter Art suchen (genaue Übereinstimmung)

          Mögliche Werte: `gruppe`, `preisgruppe`, `verband`, `regionalgruppe`, `kategorie`, `vertreter`
        type: string
        required: false
      projekt:
        description: Gruppen mit bestimmten Projekt filtern
        type: integer
        required: false
      kategorie:
        description: Gruppen mit bestimmter Kategorie filtern
        type: integer
        required: false
      aktiv:
        description: Aktive/Inaktive Gruppen filtern (1 = aktiv / 0 = inaktiv)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=projekt,-bezeichnung`)

          Verfügbare Felder: `name`, `art`, `kennziffer`, `projekt`, `kategorie`, `aktiv`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

          Verfügbare Includes: `projekt`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Gruppe anlegen
    description: |
      Gruppe anlegen

      Permission: `create_groups`
    body:
      application/json:
        properties:
          name:
            description: Bezeichnung der Gruppe
            required: true
            type: string
          art:
            description: Mögliche Werte sind `gruppe`, `preisgruppe`, `verband`, `regionalgruppe`, `kategorie` , `vertreter`
            required: true
            type: string
          kennziffer:
            description: Einmalige Kennziffer
            required: true
            type: string
          projekt:
            description: Projekt-ID
            required: false
            type: integer
          kategorie:
            description: Projekt-ID
            required: false
            type: integer
          aktiv:
            description: Gruppe aktiv? (1 = Aktiv / 0 = Inaktiv)
            required: false
            type: integer
        example: |
          {
              "name": "Support",
              "art": "gruppe",
              "kennziffer": "SUPPORT",
              "projekt": 0,
              "kategorie": 0,
              "aktiv": 1
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Gruppe wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": "11",
                      "name": "Support",
                      "art": "gruppe",
                      "kennziffer": "SUPPORT",
                      "internebemerkung": "",
                      "projekt": "0",
                      "kategorie": "0",
                      "aktiv": "1"
                  }
              }

  /{id}:
    description: Einzelne Gruppe abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Gruppe-ID
    get:
      displayName: Einzelne Gruppe abrufen
      description: |
        Einzelne Gruppe abrufen

        Permission: `view_group`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": "1",
                        "name": "Vertriebsleiter",
                        "art": "vertreter",
                        "kennziffer": "VETRL",
                        "internebemerkung": "",
                        "projekt": "0",
                        "kategorie": "0",
                        "aktiv": "1"
                    }
                }
        404:
          description: Gruppe wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Gruppe bearbeiten
      description: |
        Gruppe bearbeiten

        Permission: `update_group`
      body:
        application/json:
          example: |
            {
                "name": "Support (inaktiv)",
                "art": "gruppe",
                "kennziffer": "SUPPORT",
                "aktiv": "0"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Gruppe wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": "11",
                        "name": "Support (inaktiv)",
                        "art": "gruppe",
                        "kennziffer": "SUPPORT",
                        "internebemerkung": "",
                        "projekt": "0",
                        "kategorie": "0",
                        "aktiv": "0"
                    }
                }


/v1/laender:
  description: Länder anlegen, bearbeiten und abrufen
  get:
    displayName: Länderliste abrufen
    description: |
      Länderliste abrufen

      Permission: `list_countries`
    queryParameters:
      eu:
        description: Länder innerhalb/außerhalb EU filtern (1 = EU / 0 = Nicht EU)
        type: integer
        required: false
      iso:
        description: Länder mit ISO-Code filtern (genaue Übereinstimmung)
        type: string
        required: false
      bezeichnung_de:
        description: Länder mit bestimmter Bezeichnung suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      bezeichnung_en:
        description: Länder mit bestimmter Bezeichnung suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      id_ext:
        description: Land mit externer ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=iso,-bezeichnung`)

          Verfügbare Felder: `bezeichnung`, `bezeichnung_de`, `bezeichnung_en`, `iso` , `eu`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Land anlegen
    description: |
      Land anlegen

      Permission: `create_countries`
    body:
      application/json:
        properties:
          bezeichnung_de:
            description: Deutsche Bezeichnung des Landes
            required: true
            type: string
          bezeichnung_en:
            description: Englische Bezeichnung des Landes
            required: true
            type: string
          iso:
            description: ISO-Code (ISO-3166 ALPHA 2)
            required: true
            type: string
          eu:
            description: EU (1 = EU / 0 = Nicht EU)
            required: false
            type: integer
        example: |
          {
              "bezeichnung_de": "Republik Togo",
              "bezeichnung_en": "République Togolaise",
              "iso": "TG",
              "eu": 0
          }
    responses:
      201:
        description: Request erfolgreich; Angelegtes Land wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": "246",
                      "iso": "TG",
                      "bezeichnung_de": "Republik Togo",
                      "bezeichnung_en": "République Togolaise",
                      "eu": "0",
                      "id_ext": null
                  }
              }

  /{id}:
    description: Einzelnes Land abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Land-ID
    get:
      displayName: Einzelnes Land abrufen
      description: |
        Einzelnes Land abrufen

        Permission: `view_country`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": "43",
                        "iso": "DE",
                        "bezeichnung_de": "Deutschland",
                        "bezeichnung_en": "Germany",
                        "eu": "1",
                        "id_ext": null
                    }
                }
        404:
          description: Land wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Land bearbeiten
      description: |
        Land bearbeiten

        Permission: `edit_country`
      body:
        application/json:
          example: |
            {
              "bezeichnung_de": "Togo",
              "bezeichnung_en": "Republique Togolaise",
              "iso": "TX",
              "eu": 0
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisiertes Land wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": "246",
                        "iso": "TX",
                        "bezeichnung_de": "Togo",
                        "bezeichnung_en": "Republique Togolaise",
                        "eu": "0",
                        "id_ext": null
                    }
                }


/v1/lagercharge:
  description: Lagercharge abrufen
  get:
    displayName: Lagercharge abrufen
    description: |
      Lagercharge abrufen

      Permission: `view_storage_batch`
    queryParameters:
      artikelnummer:
        description: Suche nach bestimmter Artikelnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      artikelnummer_equals:
        description: Suche nach bestimmter Artikelnummer (genaue Übereinstimmung)
        type: string
        required: false
      artikelnummer_startswith:
        description: Suche nach bestimmter Artikelnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      artikelnummer_endswith:
        description: Suche nach bestimmter Artikelnummer (Übereinstimmung am Ende)
        type: string
        required: false
      artikel:
        description: Suche nach bestimmter Artikel-ID (genaue Übereinstimmung)
        type: integer
        required: false
      lagerplatzbezeichnung:
        description: Suche nach bestimmter Lagerplatzbezeichnung (ungefähre Übereinstimmung)
        type: string
        required: false
      lagerplatzbezeichnung_equals:
        description: Suche nach bestimmter Lagerplatzbezeichnung (genaue Übereinstimmung)
        type: string
        required: false
      lagerplatzbezeichnung_startswith:
        description: Suche nach bestimmter Lagerplatzbezeichnung (Übereinstimmung am Anfang)
        type: string
        required: false
      lagerplatzbezeichnung_endswith:
        description: Suche nach bestimmter Lagerplatzbezeichnung (Übereinstimmung am Ende)
        type: string
        required: false
      lagerplatz:
        description: Suche nach bestimmter Lagerplatz-ID (genaue Übereinstimmung)
        type: integer
        required: false
      charge:
        description: Suche nach bestimmter Charge (ungefähre Übereinstimmung)
        type: integer
        required: false
      charge_equals:
        description: Suche nach bestimmter Charge (genaue Übereinstimmung)
        type: string
        required: false
      charge_startswith:
        description: Suche nach bestimmter Charge (Übereinstimmung am Anfang)
        type: string
        required: false
      charge_endswith:
        description: Suche nach bestimmter Charge (Übereinstimmung am Ende)
        type: string
        required: false
      datum:
        description: Suche nach bestimmtem Datum (genaue Übereinstimmung)
        type: string
        required: false
      datum_gt:
        description: Suche nach bestimmtem Datum (Datum größer Suchwert)
        type: string
        required: false
      datum_gte:
        description: Suche nach bestimmtem Datum (Datum größer gleich Suchwert)
        type: string
        required: false
      datum_lt:
        description: Suche nach bestimmtem Datum (Datum kleiner Suchwert)
        type: string
        required: false
      datum_lte:
        description: Suche nach bestimmtem Datum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=artikelnummer,-menge`)

          Verfügbare Felder: `lagerplatzbezeichnung`, `artikelnummer`, `charge`, `datum` , `menge`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=artikel`)

          Verfügbare Includes: `artikel`, `lagerplatz`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
    responses:
      200:
        description: |
          Request erfolgreich

          Die Menge wird gruppiert über drei Felder: `artikel`, `lagerplatz` und `charge`.
        body:
          application/json:
            example: |
              {
                  "data": [
                      {
                          "artikel": 1,
                          "artikelnummer": "700001",
                          "lagerplatz": 1,
                          "lagerplatzbezeichnung": "HL001A",
                          "charge": "111111",
                          "datum": "2018-12-21",
                          "menge": "200.0000",
                          "internebemerkung": ""
                      },
                      {
                          "artikel": 1,
                          "artikelnummer": "700001",
                          "lagerplatz": 2,
                          "lagerplatzbezeichnung": "HL001B",
                          "charge": "222222",
                          "datum": "2018-12-21",
                          "menge": "300.0000",
                          "internebemerkung": ""
                      }
                  ],
                  "pagination": {
                      "items_per_page": 20,
                      "items_current": 2,
                      "items_total": 2,
                      "page_current": 1,
                      "page_last": 1
                  }
              }


/v1/lagermhd:
  description: Lager-Mindesthaltbarkeitdatum abrufen
  get:
    displayName: Lager-Mindesthaltbarkeitdatum abrufen
    description: |
      Lager-Mindesthaltbarkeitdatum abrufen

      Permission: `view_storage_best_before`
    queryParameters:
      artikelnummer:
        description: Suche nach bestimmter Artikelnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      artikelnummer_equals:
        description: Suche nach bestimmter Artikelnummer (genaue Übereinstimmung)
        type: string
        required: false
      artikelnummer_startswith:
        description: Suche nach bestimmter Artikelnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      artikelnummer_endswith:
        description: Suche nach bestimmter Artikelnummer (Übereinstimmung am Ende)
        type: string
        required: false
      artikel:
        description: Suche nach bestimmter Artikel-ID (genaue Übereinstimmung)
        type: integer
        required: false
      lagerplatzbezeichnung:
        description: Suche nach bestimmter Lagerplatzbezeichnung (ungefähre Übereinstimmung)
        type: string
        required: false
      lagerplatzbezeichnung_equals:
        description: Suche nach bestimmter Lagerplatzbezeichnung (genaue Übereinstimmung)
        type: string
        required: false
      lagerplatzbezeichnung_startswith:
        description: Suche nach bestimmter Lagerplatzbezeichnung (Übereinstimmung am Anfang)
        type: string
        required: false
      lagerplatzbezeichnung_endswith:
        description: Suche nach bestimmter Lagerplatzbezeichnung (Übereinstimmung am Ende)
        type: string
        required: false
      lagerplatz:
        description: Suche nach bestimmter Lagerplatz-ID (genaue Übereinstimmung)
        type: integer
        required: false
      charge:
        description: Suche nach bestimmter Charge (ungefähre Übereinstimmung)
        type: integer
        required: false
      charge_equals:
        description: Suche nach bestimmter Charge (genaue Übereinstimmung)
        type: string
        required: false
      charge_startswith:
        description: Suche nach bestimmter Charge (Übereinstimmung am Anfang)
        type: string
        required: false
      charge_endswith:
        description: Suche nach bestimmter Charge (Übereinstimmung am Ende)
        type: string
        required: false
      mhddatum:
        description: Suche nach bestimmtem MHD-Datum (genaue Übereinstimmung)
        type: string
        required: false
      mhddatum_gt:
        description: Suche nach bestimmtem MHD-Datum (MHD-Datum größer Suchwert)
        type: string
        required: false
      mhddatum_gte:
        description: Suche nach bestimmtem MHD-Datum (MHD-Datum größer gleich Suchwert)
        type: string
        required: false
      mhddatum_lt:
        description: Suche nach bestimmtem MHD-Datum (MHD-Datum kleiner Suchwert)
        type: string
        required: false
      mhddatum_lte:
        description: Suche nach bestimmtem MHD-Datum (MHD-Datum kleiner gleich Suchwert)
        type: string
        required: false
      datum:
        description: Suche nach bestimmtem Datum (genaue Übereinstimmung)
        type: string
        required: false
      datum_gt:
        description: Suche nach bestimmtem Datum (Datum größer Suchwert)
        type: string
        required: false
      datum_gte:
        description: Suche nach bestimmtem Datum (Datum größer gleich Suchwert)
        type: string
        required: false
      datum_lt:
        description: Suche nach bestimmtem Datum (Datum kleiner Suchwert)
        type: string
        required: false
      datum_lte:
        description: Suche nach bestimmtem Datum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=artikelnummer,-menge`)

          Verfügbare Felder: `lagerplatzbezeichnung`, `artikelnummer`, `charge`, `mhddatum`, `datum` , `menge`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=artikel`)

          Verfügbare Includes: `artikel`, `lagerplatz`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
    responses:
      200:
        description: |
          Request erfolgreich

          Die Menge wird gruppiert über vier Felder: `artikel`, `lagerplatz`, `charge` und `mhddatum`.
        body:
          application/json:
            example: |
              {
                  "data": [
                      {
                          "artikel": 1,
                          "artikelnummer": "700001",
                          "lagerplatz": 1,
                          "lagerplatzbezeichnung": "HL001A",
                          "charge": "444444",
                          "mhddatum": "2019-12-24",
                          "datum": "2018-12-21",
                          "menge": "300.0000",
                          "internebemerkung": "Charge und / oder MHD angelegt"
                      },
                      {
                          "artikel": 1,
                          "artikelnummer": "700001",
                          "lagerplatz": 4,
                          "lagerplatzbezeichnung": "HL002",
                          "charge": "555555",
                          "mhddatum": "2019-12-23",
                          "datum": "2018-12-21",
                          "menge": "289.0000",
                          "internebemerkung": "Produktion 400003 Einlagern"
                      }
                  ],
                  "pagination": {
                      "items_per_page": 20,
                      "items_current": 2,
                      "items_total": 2,
                      "page_current": 1,
                      "page_last": 1
                  }
              }


/v1/lieferadressen:
  description: Lieferadressen anlegen, bearbeiten und abrufen
  get:
    displayName: Lieferadressen abrufen
    description: |
      Lieferadressen abrufen

      Permission: `list_delivery_addresses`
    queryParameters:
      adresse:
        description: Suche nach allen Lieferadressen einer bestimmten Hauptadresse
        type: integer
        required: false
      standardlieferadresse:
        description: Ist Standard-Lieferadresse? (0 = Keine Standard-Lieferadresse / 1 = Ist Standard-Lieferadresse)
        type: integer
        required: false
      typ:
        description: |
          Nach bestimmten Adresstyp filtern (genaue Übereinstimmung)

          Mögliche Werte: Siehe Adresstyp-Endpunkt: [GET /adresstyp](#adresstyp).
        type: string
        required: false
      name:
        description: Suche nach Name (ungefähre Übereinstimmung)
        type: string
        required: false
      name_equals:
        description: Suche nach Name  (genaue Übereinstimmung)
        type: string
        required: false
      name_startswith:
        description: Suche nach Name (Übereinstimmung am Anfang)
        type: string
        required: false
      name_endswith:
        description: Suche nach Name (Übereinstimmung am Ende)
        type: string
        required: false
      land:
        description: Suche nach Lieferadressen aus einem bestimmten Land (zweistelliger ISO-Code)
        type: string
        required: false
      id_ext:
        description: Lieferadresse mit externer ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=plz,-land`)

          Verfügbare Felder: `typ`, `name`, `plz`, `land`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Lieferadresse anlegen
    description: |
      Lieferadresse anlegen

      Permission: `create_delivery_address`
    body:
      application/json:
        properties:
          name:
            description: Name der Firma bzw. Person
            required: true
            type: string
          adresse:
            description: ID der Hauptadresse; Die angelegte Lieferadresse wird dieser Hauptadresse zugeordnet.
            required: false
            type: integer
          typ:
            description: Adresstyp; Siehe [Adresstyp-Endpunkt](#adresstyp) Feld `type`.
            required: false
            type: string
          abteilung:
            required: false
            type: string
          strasse:
            required: false
            type: string
          ort:
            required: false
            type: string
          plz:
            required: false
            type: string
          telefon:
            required: false
            type: string
          telefax:
            required: false
            type: string
          email:
            required: false
            type: string
          land:
            description: ISO-Code (ISO-3166 ALPHA 2)
            required: false
            type: string
          standardlieferadresse:
            description: |
              Als Standard-Lieferadresse markieren?

              (`0` = Keine Standard-Lieferadresse / `1` = Ist Standard-Lieferadresse)
            required: false
            type: integer
          ust_befreit:
            description: |
              Besteuerung

              (`0` = Inland / `1` = EU-Lieferung / `2` = Export / `3` = Steuerfrei Inland)
            required: false
            type: integer
        example: |
          {
              "adresse": 5,
              "typ": "herr",
              "name": "Max Mustermann",
              "abteilung": "Musterabteilung",
              "strasse": "Musterweg",
              "ort": "Musterort",
              "plz": "12345",
              "land": "DE",
              "telefon": "0123-456789-9",
              "telefax": "0123-456789-0",
              "email": "max@mustermann.de",
              "standardlieferadresse": 1,
              "ust_befreit": 0
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Lieferadresse wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 23,
                      "typ": "herr",
                      "name": "Max Mustermann",
                      "abteilung": "Musterabteilung",
                      "...": "Ausgabe gekürzt",
                      "standardlieferadresse": 1,
                      "ust_befreit": 0,
                      "id_ext": null
                  }
              }

  /{id}:
    description: Einzelne Lieferadresse abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Lieferadressen-ID
    get:
      displayName: Einzelne Lieferadresse abrufen
      description: |
        Einzelne Lieferadresse abrufen

        Permission: `view_delivery_address`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 1,
                        "typ": "herr",
                        "name": "Max Mustermann",
                        "abteilung": "Musterabteilung",
                        "...": "Ausgabe gekürzt",
                        "standardlieferadresse": 1,
                        "ust_befreit": 0,
                        "id_ext": null
                    }
                }
        404:
          description: Lieferadresse wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Lieferadresse bearbeiten
      description: |
        Lieferadresse bearbeiten

        Permission: `edit_delivery_address`
      body:
        application/json:
          example: |
            {
                "typ": "firma",
                "name": "Mustermann Gmbh"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Lieferadresse wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 1,
                        "typ": "firma",
                        "name": "Mustermann Gmbh",
                        "abteilung": "Musterabteilung",
                        "...": "Ausgabe gekürzt",
                        "standardlieferadresse": 1,
                        "ust_befreit": 0,
                        "id_ext": null
                    }
                }
    delete:
      displayName: Lieferadresse löschen
      description: |
        Lieferadresse löschen

        Permission: `delete_delivery_address`
      responses:
        200:
          description: Request erfolgreich; ID der gelöschten Lieferadresse wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 1
                    }
                }

/v1/reports:
  displayName: /v1/reports
  description: Berichte (neues Modul) abrufen

  /{id}/download:
    description: |
      Einzelnen Bericht per ID herunterladen

      Permission: `view_report`
    uriParameters:
      id:
        type: integer
        description: Bericht-ID
    get:
      displayName: Einzelnen Bericht herunterladen
      description: Einzelnen Bericht herunterladen
      queryParameters:
            parameter:
              description: Jeder Parameter, der in der Abfrage des Berichts vorkommt.
              type: any
              required: false
      responses:
        200:
          description: |
            Request erfolgreich

            Der Content-Type ist abhängig vom Mime-Type des Formats, das im Bericht hinterlegt ist.
        403:
          description: Der Bericht ist nicht für den Zugriff über diesen API Account freigegeben.
          body:
            application/json:
              example: |
                {
                    "error": {
                      "http_code": 403,
                      "message": "Access denied"
                    }
                }
        404:
          description: Bericht wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
        500:
          description: Der Bericht konnte nicht erstellt werden. Der Bericht ist eventuell fehlerhaft.
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7499,
                        "http_code": 500,
                        "message": "Unknown server error",
                        "href": "http://localhost/xentral/20.1/www/api/docs.html#error-7499"
                    }
                }
/v1/steuersaetze:
  description: Steuersätze anlegen, bearbeiten und abrufen
  get:
    displayName: Steuersätze abrufen
    description: |
      Steuersätze abrufen

      Permission: `list_tax_rates`
    queryParameters:
      bezeichnung:
        description: Steuersatz mit bestimmter Bezeichnung suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      satz:
        description: Nach Steuersatz filtern (genaue Übereinstimmung)
        type: string
        required: false
      aktiv:
        description: Aktive/Inaktive Steuersätze filtern (1 = aktiv / 0 = inaktiv)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=satz,-bezeichnung`)

          Verfügbare Felder: `bezeichnung`, `satz`, `aktiv`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Steuersatz anlegen
    description: |
      Steuersatz anlegen

      Permission: `create_tax_rate`
    body:
      application/json:
        properties:
          bezeichnung:
            description: Bezeichnung des Steuersatzes
            required: true
            type: string
          satz:
            description: Steuersatz in Prozent (ohne Prozentzeichen; Dezimaltrenner = Punkt)
            required: true
            type: string
          aktiv:
            description: Aktiv (1 = aktiv / 0 = inaktiv)
            required: false
            type: integer
        example: |
          {
              "bezeichnung": "Steuer DE ermäßigt",
              "satz": "7.00",
              "aktiv": 1
          }
    responses:
      201:
        description: Request erfolgreich; Angelegter Steuersatz wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": "14",
                      "bezeichnung": "Steuer DE ermäßigt",
                      "satz": "7.00",
                      "aktiv": "1"
                  }
              }

  /{id}:
    description: Einzelnen Steuersatz abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Steuersatz-ID
    get:
      displayName: Einzelnen Steuersatz abrufen
      description: |
        Einzelnen Steuersatz abrufen

        Permission: `view_tax_rate`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": "1",
                        "bezeichnung": "Steuersatz DE normal",
                        "country_code": "DE",
                        "satz": "19.00",
                        "aktiv": "1"
                    }
                }
        404:
          description: Steuersatz wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Steuersatz bearbeiten
      description: |
        Steuersatz bearbeiten

        Permission: `edit_tax_rates`
      body:
        application/json:
          properties:
            bezeichnung:
              description: Bezeichnung des Steuersatzes
              required: true
              type: string
            country_code:
              description: Ländercode des Steuersatzes
              required: false
              type: string
            satz:
              description: Steuersatz in Prozent (ohne Prozentzeichen; Dezimaltrenner = Punkt)
              required: true
              type: string
            aktiv:
              description: Aktiv (1 = aktiv / 0 = inaktiv)
              required: false
              type: integer
          example: |
            {
                "bezeichnung": "Steuer DE normal",
                "satz": "19.00"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierter Steuersatz wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": "1",
                        "bezeichnung": "Steuer DE normal",
                        "country_code": "DE",
                        "satz": "19.00",
                        "aktiv": "1"
                    }
                }


/v1/trackingnummern:
  get:
    displayName: Trackingnummern abrufen
    description: |
      Endpunkt zum Abrufen von Trackingnummern

      Permission: `list_tracking_numbers`
    queryParameters:
      tracking:
        description: Suche nach bestimmter Trackingnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      tracking_equals:
        description: Suche nach bestimmter Trackingnummer (genaue Übereinstimmung)
        type: string
        required: false
      tracking_startswith:
        description: Suche nach bestimmter Trackingnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      tracking_endswith:
        description: Suche nach bestimmter Trackingnummer (Übereinstimmung am Ende)
        type: string
        required: false
      lieferschein:
        description: Suche nach bestimmter Lieferscheinnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      lieferschein_equals:
        description: Suche nach bestimmter Lieferscheinnummer (genaue Übereinstimmung)
        type: string
        required: false
      lieferschein_startswith:
        description: Suche nach bestimmter Lieferscheinnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      lieferschein_endswith:
        description: Suche nach bestimmter Lieferscheinnummer (Übereinstimmung am Ende)
        type: string
        required: false
      auftrag:
        description: Suche nach bestimmter Auftragsnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      auftrag_equals:
        description: Suche nach bestimmter Auftragsnummer (genaue Übereinstimmung)
        type: string
        required: false
      auftrag_startswith:
        description: Suche nach bestimmter Auftragsnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      auftrag_endswith:
        description: Suche nach bestimmter Auftragsnummer (Übereinstimmung am Ende)
        type: string
        required: false
      internet:
        description: Suche nach bestimmter Internetnummer (ungefähre Übereinstimmung)
        type: string
        required: false
      internet_equals:
        description: Suche nach bestimmter Internetnummer (genaue Übereinstimmung)
        type: string
        required: false
      internet_startswith:
        description: Suche nach bestimmter Internetnummer (Übereinstimmung am Anfang)
        type: string
        required: false
      internet_endswith:
        description: Suche nach bestimmter Internetnummer (Übereinstimmung am Ende)
        type: string
        required: false
      versandart:
        description: Suche nach bestimmter Versandart (genaue Übereinstimmung)
        type: string
        required: false
      versendet_am:
        description: Suche nach bestimmtem Versanddatum (genaue Übereinstimmung)
        type: string
        required: false
      versendet_am_gt:
        description: Suche nach bestimmtem Versanddatum (Datum größer Suchwert)
        type: string
        required: false
      versendet_am_gte:
        description: Suche nach bestimmtem Versanddatum (Datum größer gleich Suchwert)
        type: string
        required: false
      versendet_am_lt:
        description: Suche nach bestimmtem Versanddatum (Datum kleiner Suchwert)
        type: string
        required: false
      versendet_am_lte:
        description: Suche nach bestimmtem Versanddatum (Datum kleiner gleich Suchwert)
        type: string
        required: false
      adresse:
        description: Suche nach bestimmter Adress-ID (genaue Übereinstimmung)
        type: integer
        required: false
      projekt:
        description: Suche nach bestimmter Projekt-ID (genaue Übereinstimmung)
        type: integer
        required: false
      land:
        description: Suche nach bestimmtem Ländercode (genaue Übereinstimmung)
        type: string
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=-versendet_am,lieferschein`)

          Verfügbare Felder: `tracking`, `auftrag`, `lieferschein`, `versandart`, `versendet_am` , `abgeschlossen`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

          Verfügbare Includes: `projekt`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Trackingnummer anlegen
    description: |
      Trackingnummer anlegen

      Eines der Felder `internet`, `auftrag` oder `lieferschein`  muss mindestens gefüllt sein!

      Permission: `create_tracking_number`
    body:
      application/json:
        properties:
          tracking:
            description: Trackingnummer
            required: true
            type: string
          internet:
            description: Internetnummer aus Auftrag (Pflichtfeld, wenn Auftragsnummer und Lieferscheinnummer leer)
            required: false
            type: string
          auftrag:
            description: Auftragsnummer (Pflichtfeld, wenn Internetnummer und Lieferscheinnummer leer)
            required: false
            type: string
          lieferschein:
            description: Lieferscheinnummer (Pflichtfeld, wenn Auftragsnummer und Internetnummer leer)
            required: false
            type: string
          anzahlpakete:
            description: Anzahl Pakete
            required: true
            type: integer
          gewicht:
            description: Gewicht
            required: true
            type: string
          versendet_am:
            description: Versanddatum im Format `YYYY-MM-DD`
            required: true
            type: string
        example: |
          {
              "tracking": "11223344556677889900",
              "internet": "111001",
              "auftrag": "200001",
              "lieferschein": "300001",
              "anzahlpakete": 1,
              "gewicht": "2 kg",
              "versendet_am": "2019-07-25"
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Trackingnummer wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 8,
                      "tracking": "11223344556677889900",
                      "adresse": 5,
                      "internet": "111001",
                      "auftrag": "200001",
                      "lieferschein": "300001",
                      "projekt": 1,
                      "versandart": "versandunternehmen",
                      "land": "DE",
                      "gewicht": "2 kg",
                      "abgeschlossen": 0,
                      "versendet_am": "2019-07-25",
                      "anzahlpakete": 1,
                      "retoure": 0,
                      "klaergrund": ""
                  }
              }

  /{id}:
    description: Einzelne Trackingnummer abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Trackingnummer-ID
    get:
      displayName: Einzelne Trackingnummer abrufen
      description: |
        Einzelne Trackingnummer abrufen

        Permission: `view_tracking_number`
    put:
      displayName: Trackingnummer bearbeiten
      description: |
        Trackingnummer bearbeiten (Felder siehe "Trackingnummer anlegen")

        Permission: `edit_tracking_number`
      body:
        application/json:
          example: |
            {
                "tracking": "11223344556677889900",
                "versendet_am": "2019-06-22",
                "anzahlpakete": 2
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierter Trackingnummern-Eintrag wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": 8,
                        "tracking": "11223344556677889900",
                        "adresse": 5,
                        "internet": "111001",
                        "auftrag": "200001",
                        "lieferschein": "300001",
                        "projekt": 1,
                        "versandart": "versandunternehmen",
                        "land": "DE",
                        "gewicht": "2 kg",
                        "abgeschlossen": 0,
                        "versendet_am": "2019-06-22",
                        "anzahlpakete": 2,
                        "retoure": 0,
                        "klaergrund": ""
                    }
                }


/v1/versandarten:
  description: Versandarten anlegen, bearbeiten und abrufen
  get:
    displayName: Versandarten abrufen
    description: |
      Versandarten abrufen

      Permission: `list_shipping_methods`
    queryParameters:
      bezeichnung:
        description: Versandart mit bestimmter Bezeichnung suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      bezeichnung_exakt:
        description: Versandart mit bestimmter Bezeichnung suchen (genaue Übereinstimmung)
        type: string
        required: false
      type:
        description: Versandart eines bestimmten Typs suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      type_exakt:
        description: Versandart eines bestimmten Typs suchen (genaue Übereinstimmung)
        type: string
        required: false
      projekt:
        description: Versandarten eines Projekts filtern (genaue Übereinstimmung)
        type: integer
        required: false
      modul:
        description: Versandarten mit bestimmtem Modul filtern (genaue Übereinstimmung)
        type: integer
        required: false
      aktiv:
        description: Aktive/Inaktive Versandarten filtern (1 = aktiv / 0 = inaktiv)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=type,-bezeichnung`)

          Verfügbare Felder: `bezeichnung`, `type`, `projekt`, `modul`, `aktiv`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

          Verfügbare Includes: `projekt`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Versandart anlegen
    description: |
      Versandart anlegen

      Permission: `create_shipping_method`
    body:
      application/json:
        properties:
          bezeichnung:
            description: Bezeichnung der Versandart
            required: true
            type: string
          type:
            description: Versandart-Typ (einmaliger Wert)
            required: true
            type: string
          projekt:
            description: Projekt
            required: false
            type: integer
          aktiv:
            description: Aktiv (1 = aktiv / 0 = inaktiv)
            required: false
            type: integer
        example: |
          {
              "type": "DHL",
              "bezeichnung": "DHL",
              "aktiv": 1,
              "projekt": 1
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Versandart wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": "15",
                      "type": "DHL",
                      "bezeichnung": "DHL",
                      "aktiv": "1",
                      "projekt": "1",
                      "modul": "",
                      "paketmarke_drucker": "0",
                      "export_drucker": "0",
                      "ausprojekt": "1",
                      "versandmail": "0",
                      "geschaeftsbrief_vorlage": "0"
                  }
              }

  /{id}:
    description: Einzelne Versandart abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Versandarten-ID
    get:
      displayName: Einzelnen Versandart abrufen
      description: |
        Einzelnen Versandart abrufen

        Permission: `view_shipping_method`
      queryParameters:
        include:
          description: |
            Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

            Verfügbare Includes: `projekt`
          type: string
          required: false
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": "15",
                        "type": "DHL",
                        "bezeichnung": "DHL",
                        "aktiv": "1",
                        "projekt": "1",
                        "modul": "",
                        "paketmarke_drucker": "0",
                        "export_drucker": "0",
                        "ausprojekt": "1",
                        "versandmail": "0",
                        "geschaeftsbrief_vorlage": "0"
                    }
                }
        404:
          description: Versandart wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Versandart bearbeiten
      description: |
        Versandart bearbeiten

        Permission: `edit_shipping_method`
      body:
        application/json:
          example: |
            {
                "type": "DHL_Paket",
                "bezeichnung": "DHL Paket",
                "aktiv": "1",
                "projekt": "1"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Versandart wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": "15",
                        "type": "DHL_Paket",
                        "bezeichnung": "DHL Paket",
                        "aktiv": "1",
                        "projekt": "1",
                        "modul": "",
                        "paketmarke_drucker": "0",
                        "export_drucker": "0",
                        "ausprojekt": "1",
                        "versandmail": "0",
                        "geschaeftsbrief_vorlage": "0"
                    }
                }


/v1/wiedervorlagen:
  description: Wiedervorlagen anlegen, bearbeiten und abrufen
  get:
    displayName: Wiedervorlagen abrufen
    description: |
      Wiedervorlagen abrufen

      Permission: `list_resubmissions`
    queryParameters:
      adresse:
        description: Wiedervorlagen mit bestimmter Address-ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      adresse_mitarbeiter:
        description: Wiedervorlagen filtern die einem bestimmten Mitarbeiter (Address-ID) zugewiesen sind (genaue Übereinstimmung)
        type: string
        required: false
      bearbeiter:
        description: Wiedervorlagen filtern die einem bestimmten Bearbeiter (Address-ID) zugewiesen sind (genaue Übereinstimmung)
        type: string
        required: false
      projekt:
        description: Wiedervorlagen mit bestimmter Projekt-ID filtern (genaue Übereinstimmung)
        type: string
        required: false
      stages:
        description: Wiedervorlagen mit bestimmter Stage-ID filtern (genaue Übereinstimmung)
        type: string
        required: false
      id_ext:
        description: Wiedervorlage mit externer ID filtern (genaue Übereinstimmung)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=iso,-bezeichnung`)

          Verfügbare Felder: `bezeichnung`, `datum_angelegt`, `zeit_angelegt`, `datum_erinnerung` , `zeit_erinnerung`,
          `stages`, `prio`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Wiedervorlage anlegen
    description: |
      Wiedervorlage anlegen

      Permission: `create_resubmission`
    body:
      application/json:
        properties:
          datum_erinnerung:
            description: Fälligkeits-Datum der Wiedervorlage (Format `2019-12-31`)
            required: true
            type: date-only
          zeit_erinnerung:
            description: Fälligkeits-Uhrzeit der Wiedervorlage (Format `23:59:59`)
            required: true
            type: time-only
          datum_angelegt:
            description: Anlage-Datum der Wiedervorlage (Format `2019-12-31`)
            required: false
            type: date-only
          zeit_angelegt:
            description: Anlage-Uhrzeit der Wiedervorlage (Format `23:59:59`)
            required: false
            type: time-only
          bezeichnung:
            description: Kurzbeschreibung
            required: true
            type: string
          beschreibung:
            description: Langbeschreibung
            required: false
            type: string
          bearbeiter:
            description: Address-ID des Bearbeiters
            required: false
            type: integer
          adresse_mitarbeiter:
            description: Address-ID des zuständigen Mitarbeiters
            required: false
            type: integer
          datum_abschluss:
            description: Abschlussdatum der Wiedervorlage (Format `2019-12-31`)
            required: false
            type: date-only
        example: |
          {
              "bearbeiter": 4,
              "bezeichnung": "Blumengießen",
              "beschreibung": "Alle Blumen im Büro gießen",
              "datum_erinnerung": "2019-12-31",
              "zeit_erinnerung": "23:59:59",
              "datum_abschluss": "2020-01-06",
              "adresse_mitarbeiter": 1
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Wiedervorlage wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": 49,
                      "adresse": 0,
                      "projekt": 0,
                      "bezeichnung": "Blumengießen",
                      "beschreibung": "Alle Blumen im Büro gießen",
                      "bearbeiter": 4,
                      "adresse_mitarbeiter": 1,
                      "datum_erinnerung": "2019-12-31",
                      "zeit_erinnerung": "23:59:59",
                      "datum_abschluss": "2020-01-06",
                      "oeffentlich": 0,
                      "abgeschlossen": 0,
                      "prio": 0,
                      "stages": 0,
                      "color": "",
                      "id_ext": null
                  }
              }

  /{id}:
    description: Einzelne Wiedervorlage abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Wiedervorlage-ID
    get:
      displayName: Einzelne Wiedervorlage abrufen
      description: |
        Einzelne Wiedervorlage abrufen

        Permission: `view_resubmission`
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 49,
                        "adresse": 1,
                        "projekt": 1,
                        "bezeichnung": "Blumengießen",
                        "beschreibung": "Alle Blumen im Büro gießen",
                        "ergebnis": "",
                        "betrag": "5.00",
                        "erinnerung_per_mail": 0,
                        "bearbeiter": 4,
                        "adresse_mitarbeiter": 1,
                        "datum_angelegt": null,
                        "zeit_angelegt": null,
                        "datum_erinnerung": "2019-12-31",
                        "zeit_erinnerung": "23:59:00",
                        "datum_abschluss": "2020-01-06",
                        "oeffentlich": 0,
                        "abgeschlossen": 1,
                        "chance": 100,
                        "prio": 0,
                        "stages": 2,
                        "color": "",
                        "id_ext": null
                    }
                }
        404:
          description: Wiedervorlage wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Wiedervorlage bearbeiten
      description: |
        Wiedervorlage bearbeiten

        Permission: `edit_resubmission`
      body:
        application/json:
          example: |
            {
                "bearbeiter": 1,
                "bezeichnung": "Blumengießen",
                "datum_erinnerung": "2019-12-31",
                "zeit_erinnerung": "23:59:59"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Wiedervorlage wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": 49,
                        "adresse": 1,
                        "projekt": 1,
                        "bezeichnung": "Blumengießen",
                        "beschreibung": "Alle Blumen im Büro gießen",
                        "ergebnis": "",
                        "betrag": "5.00",
                        "erinnerung_per_mail": 0,
                        "bearbeiter": 1,
                        "adresse_mitarbeiter": 1,
                        "datum_angelegt": null,
                        "zeit_angelegt": null,
                        "datum_erinnerung": "2019-12-31",
                        "zeit_erinnerung": "23:59:00",
                        "datum_abschluss": "2020-01-06",
                        "oeffentlich": 0,
                        "abgeschlossen": 1,
                        "chance": 100,
                        "prio": 0,
                        "stages": 2,
                        "color": "",
                        "id_ext": null
                    }
                }


/v1/zahlungsweisen:
  description: Zahlungsweisen anlegen, bearbeiten und abrufen
  get:
    displayName: Zahlungsweisen abrufen
    description: |
      Zahlungsweisen abrufen

      Permission: `list_payment_methods`
    queryParameters:
      bezeichnung:
        description: Zahlungsweise mit bestimmter Bezeichnung suchen (ungefähre Übereinstimmung)
        type: string
        required: false
      bezeichnung_exakt:
        description: Zahlungsweise mit bestimmter Bezeichnung suchen (genaue Übereinstimmung)
        type: string
        required: false
      type:
        description: Nach bestimmten Typ filtern (ungefähre Übereinstimmung)
        type: string
        required: false
      type_exakt:
        description: Nach bestimmten Typ filtern (genaue Übereinstimmung)
        type: string
        required: false
      projekt:
        description: Zahlungsweise eines Projekts filtern (genaue Übereinstimmung)
        type: integer
        required: false
      modul:
        description: Nach bestimmtem Modul filtern (genaue Übereinstimmung)
        type: integer
        required: false
      aktiv:
        description: Aktive/Inaktive Zahlungsweise filtern (1 = aktiv / 0 = inaktiv)
        type: integer
        required: false
      sort:
        description: |
          Sortierung (Beispiel: `sort=type,-bezeichnung`)

          Verfügbare Felder: `bezeichnung`, `type`, `projekt`, `modul`, `aktiv`
        type: string
        required: false
      include:
        description: |
          Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

          Verfügbare Includes: `projekt`
        type: string
        required: false
      page:
        description: Seitenzahl
        type: integer
        required: false
        default: 1
        maximum: 1000
      items:
        description: Anzahl der Ergebnisse pro Seite
        type: integer
        required: false
        default: 20
        maximum: 1000
  post:
    displayName: Zahlungsweisen anlegen
    description: |
      Zahlungsweisen anlegen

      Permission: `create_payment_method`
    body:
      application/json:
        properties:
          bezeichnung:
            description: Bezeichnung der Zahlungsweise
            required: true
            type: string
          type:
            description: Zahlungsweise-Typ (einmaliger Wert)
            required: true
            type: string
          verhalten:
            description: Verhalten; Zulässige Werte sind `vorkasse`, `rechnung`, `lastschrift`
            required: false
            type: string
          projekt:
            description: Projekt
            required: false
            type: integer
          aktiv:
            description: Aktiv (`1` = aktiv / `0` = inaktiv)
            required: false
            type: integer
        example: |
          {
              "type": "vorkasse",
              "bezeichnung": "Vorkasse",
              "verhalten": "vorkasse",
              "aktiv": 1,
              "projekt": 1
          }
    responses:
      201:
        description: Request erfolgreich; Angelegte Zahlungsweise wird zurückgeliefert
        body:
          application/json:
            example: |
              {
                  "success": true,
                  "data": {
                      "id": "10",
                      "type": "vorkasse",
                      "bezeichnung": "Vorkasse",
                      "freitext": "",
                      "aktiv": "1",
                      "automatischbezahlt": "0",
                      "automatischbezahltverbindlichkeit": "0",
                      "projekt": "1",
                      "vorkasse": "0",
                      "verhalten": "vorkasse",
                      "modul": ""
                  }
              }

  /{id}:
    description: Einzelne Zahlungsweise abrufen oder bearbeiten
    uriParameters:
      id:
        type: integer
        description: Zahlungsweisen-ID
    get:
      displayName: Einzelnen Zahlungsweise abrufen
      description: |
        Einzelnen Zahlungsweise abrufen

        Permission: `view_payment_method`
      queryParameters:
        include:
          description: |
            Unter-Resourcen in Resource einbinden (Beispiel: `include=projekt`)

            Verfügbare Includes: `projekt`
          type: string
          required: false
      responses:
        200:
          description: Request erfolgreich
          body:
            application/json:
              example: |
                {
                    "data": {
                        "id": "1",
                        "type": "vorkasse",
                        "bezeichnung": "Vorkasse",
                        "freitext": "",
                        "aktiv": "1",
                        "automatischbezahlt": "0",
                        "automatischbezahltverbindlichkeit": "0",
                        "projekt": "0",
                        "vorkasse": "0",
                        "verhalten": "vorkasse",
                        "modul": ""
                    }
                }
        404:
          description: Zahlungsweise wurde nicht gefunden
          body:
            application/json:
              example: |
                {
                    "error": {
                        "code": 7452,
                        "http_code": 404,
                        "message": "Resource not found",
                        "href": "http://www.example.com/api/docs.html#error-7452"
                    }
                }
    put:
      displayName: Zahlungsweise bearbeiten
      description: |
        Zahlungsweise bearbeiten

        Permission: `edit_payment_method`
      body:
        application/json:
          example: |
            {
                "type": "lastschrift",
                "bezeichnung": "Lastschrift",
                "aktiv": "1",
                "projekt": "1",
                "verhalten": "lastschrift"
            }
      responses:
        200:
          description: Request erfolgreich; Aktualisierte Zahlungsweise wird zurückgeliefert
          body:
            application/json:
              example: |
                {
                    "success": true,
                    "data": {
                        "id": "10",
                        "type": "lastschrift",
                        "bezeichnung": "Lastschrift",
                        "freitext": "",
                        "aktiv": "1",
                        "automatischbezahlt": "0",
                        "automatischbezahltverbindlichkeit": "0",
                        "projekt": "1",
                        "vorkasse": "0",
                        "verhalten": "lastschrift",
                        "modul": ""
                    }
                }


#types:
#  ZeroValue:
#    description: Zero-value numbers, accepting either 0 or 0.00
#    type: number
#    enum:
#      - 0
#      - 0.00
#  HundredthsValue:
#    description: Non-zero two-decimal place values (positive and negative)
#    type: number
#    multipleOf: 0.01
#  decimal:
#    description: this type describes any monetary value comprised between -9,999,999,999,999.99 and 9,999,999,999,999.99
#    type: ZeroValue | HundredthsValue
#    default: 0.00
#    minimum: -9999999999999.99
#    maximum: 9999999999999.99
#    examples:
#      zero: 0
#      zerozero: 0.00
#      tenten: 10.10
#      negative: -0.10