# App-Tools-API Referenz > Referenz für Katalogabruf, Tool-Metadaten, Ausführung, Antworten und Fehler der SynCore-App-Tools-API. Quelle: https://support.unitedsynergy.com/api/app-tools/ Die App-Tools-API hat einen zentralen Endpunkt. `GET` liefert den berechtigungsgefilterten Katalog, `POST` führt genau ein darin beschriebenes Tool aus. KI-Assistenten erreichen dieselben Tools über MCP: [MCP und KI-Assistenten im Überblick](https://support.unitedsynergy.com/mcp/uebersicht/). ## Basis und Authentifizierung - Basis-URL: die HTTPS-Adresse deiner SynCore-Instanz - Endpunkt: `/api/app-tools` - Authentifizierung: Header `X-API-KEY` - Content-Type bei `POST`: `application/json` ## GET /api/app-tools Liefert alle für den Actor-User sichtbaren Tools. ### Query-Parameter | Parameter | Typ | Standard | Bedeutung | | --- | --- | --- | --- | | `includeStructure` | Boolean | `false` | Bei `1`, `true` oder `yes` zusätzlich App-Struktur, effektive Rechte und Laufzeitregeln liefern. | | `stufe` | Text | keine | `name`, `beschreibung`, `schema` oder `typescript`, siehe [Katalog in Stufen](#katalog-in-stufen). Ohne Angabe kommt die volle Form wie bisher. | | `app` | Text | alle | Nur Tools dieser Apps, mehrere durch Komma getrennt, zum Beispiel `crm,projektsyn`. | | `suche` | Text | keine | Suchbegriffe durch Leerzeichen getrennt. Jeder Begriff muss in Name, App-Bezeichnung oder Beschreibung vorkommen. | Empfohlener Aufruf: ```http GET /api/app-tools?includeStructure=1 HTTP/1.1 Host: syncore.example.com X-API-KEY: syn_... Accept: application/json ``` ### Katalog in Stufen Bei vollen Rechten liefert der Katalog über 1.000 Tools, rund 700 KB. Für das Finden reicht meist weniger: | Stufe | Inhalt je Tool | Größe des vollen Katalogs | | --- | --- | --- | | `name` | `name`, `module`, `sideEffect` | rund 80 KB | | `beschreibung` | dazu `appId`, `label`, `description`, `confirmationRequired`, `dataClasses` | rund 270 KB | | `schema` | alle Felder aus [Tool-Metadaten](#tool-metadaten) | rund 700 KB | | `typescript` | die Tools als TypeScript-Deklaration, Antwort als Text statt JSON | rund 550 KB | Mit Stufe enthält die Antwort zusätzlich `stufe` und `anzahl`. Sinnvoll ist ein Ablauf in zwei Schritten: erst `?stufe=name&suche=konto` zum Finden, dann `?stufe=schema&suche=crm.konto.list` für die Eingaben. `?stufe=typescript&app=crm` liefert die Tools der App als Deklaration, die ein Programm oder ein KI-Agent direkt verwenden kann: ```ts declare const syncore: { crm: { /** Liste/Suche: Konten (CRM) … */ konto_list(input: CrmKontoListInput): Promise>; }; }; ``` Die Typen beschreiben nur die Eingaben. Geprüft wird bei jedem `POST` weiter im Server: Schema, Rechte und Datenbereich. Jede Antwort trägt einen `ETag`. Schickst du ihn beim nächsten Abruf im Header `If-None-Match` mit und hat sich nichts geändert, antwortet SynCore mit `304` ohne Inhalt. Eine unbekannte Stufe oder eine ungültige App-Kennung beantwortet SynCore mit `400`. ### Tool-Metadaten | Feld | Bedeutung | | --- | --- | | `name` | Stabiler Name, der bei `POST` unverändert verwendet wird. | | `module` / `appId` | Zugehörige SynCore-App und stabile App-ID. | | `label` / `description` | Anzeigename und fachliche Beschreibung. | | `inputSchema` | Zulässige Eingabe als JSON-Schema. | | `outputSchema` | Beschreibung der Ausgabe, sofern für das Tool hinterlegt. | | `requires` | Erforderliche fachliche Berechtigungen. | | `dataClasses` | Betroffene Datenklassen. Tools für besonders geschützte Klasse-D-Daten werden nicht über diese Fläche angeboten. | | `sideEffect` | Kennzeichnet, ob das Tool Daten liest oder einen Seiteneffekt auslöst. | | `confirmationRequired` | Eine aufrufende Anwendung muss vor der Ausführung eine ausdrückliche Bestätigung einholen. | | `dsgvoNote` | Datenschutzhinweis zum Umfang der verarbeiteten oder übertragenen Daten. | > **Der Katalog ist die Vertragsgrundlage** > > Verwende keine fest eingebaute globale Tool-Liste. Apps, Rechte, Datenscopes und Tool-Schemas können sich je Mandant und Version unterscheiden. Maßgeblich ist immer die aktuelle GET-Antwort der Zielinstanz. Hat dein Mandant externe Dienste angebunden, können deren Tools ebenfalls im Katalog stehen. `dsgvoNote` nennt dann, welche Daten an den Dienst gehen. Alle Tools, die SynCore mitbringt, stehen mit Eingabefeldern und nötigen Rechten in der [Referenz nach App](https://support.unitedsynergy.com/api/referenz/). Welche davon du tatsächlich aufrufen darfst, zeigt dein Katalog. ## POST /api/app-tools Führt ein Tool im Kontext des Mandanten und des Actor-Users aus. ### Request Body ```json { "name": "textbausteine.list_templates", "input": { "typ": "PDF", "limit": 20 } } ``` | Feld | Pflicht | Bedeutung | | --- | --- | --- | | `name` | ja | Exakter Tool-Name aus dem aktuellen Katalog. | | `input` | nein | JSON-Objekt entsprechend `inputSchema`; ohne Eingabe `{}` verwenden. | Vor der Ausführung prüft SynCore den Tool-Namen, das Eingabeschema, die App-Aktivierung, alle benötigten Berechtigungen und den effektiven Datenscope. ### Erfolgreiche Antwort ```json { "ok": true, "tool": "textbausteine.list_templates", "module": "textbausteine", "data": [] } ``` Je nach Tool können zusätzlich unter anderem `summary`, `entityType`, `entityId`, `needsSelection` oder `candidates` vorkommen. Beachte das gelieferte `outputSchema` und behandle unbekannte zusätzliche Felder tolerant. Wenn `needsSelection: true` zurückkommt, darfst du nicht automatisch weiterschreiben. Zeige die Kandidaten an und lasse den Benutzer auswählen. ### Listen blättern Jedes lesende Listen-Tool nimmt `limit` und `offset` an. Liefert ein Tool höchstens 200 Einträge auf einmal (Standard und Höchstwert, bei den Datenobjekt-Listen `…list` Standard 50), steht in der Antwort zusätzlich `seite`: ```json { "ok": true, "tool": "textbausteine.list_documents", "data": [ … ], "seite": { "offset": 0, "limit": 200, "gesamt": 312, "weitere": true } } ``` Bei `weitere: true` holst du die nächste Seite mit `offset` plus `limit`, hier `"offset": 200`. Ein `limit` über 200 beantwortet SynCore mit `400`. Einige Listen-Tools liefern statt einer Liste ein kleines Objekt, etwa die Stufen einer Pipeline oder die Freigaben eines Datensatzes. Dort gibt es kein `limit`, das Eingabeschema im Katalog zeigt es. ## Verbindlicher Ablauf bei Änderungen 1. Katalog und Struktur abrufen. 2. Zielentität über ein Lese- oder Such-Tool eindeutig bestimmen. 3. Eingabe gegen `inputSchema` aufbauen. 4. Bei `confirmationRequired: true` die konkrete Aktion bestätigen lassen. 5. Mutation ausführen. 6. Ergebnis mit einem Lese- oder Listen-Tool verifizieren. Die Bestätigung ist eine Prozesspflicht der aufrufenden Anwendung. Es gibt dafür kein pauschales `confirmed`-Feld im Transportformat. ## Dateien an einen Datensatz hängen Mit `files.upload` legst du eine Datei an einem Datensatz ab, zum Beispiel ein Angebot an einem Projekt oder ein Foto an einer Aufgabe. `files.list` zeigt danach, was dort hängt. ```json { "name": "files.upload", "input": { "filename": "Angebot.pdf", "mimeType": "application/pdf", "contentBase64": "JVBERi0xLjcK...", "ownerType": "projektsyn.projekt", "ownerId": "prj_123" } } ``` | Feld | Pflicht | Bedeutung | | --- | --- | --- | | `filename` | ja | Dateiname mit Endung, höchstens 255 Zeichen. | | `mimeType` | ja | Dateityp, zum Beispiel `application/pdf` oder `image/png`. Er muss zum Inhalt passen. | | `contentBase64` | ja | Dateiinhalt als Base64, auch als `data:`-URL. | | `ownerType` | ja | Art des Datensatzes: `projektsyn.projekt`, `projektsyn.ticket`, `crm.konto`, `crm.kontakt`, `crm.potenzial`, `vertraege.vertrag`, `auftraege.auftrag`, `produkte.artikel`, `seminar.katalog` oder `seminar.veranstaltung`. | | `ownerId` | ja | ID des Datensatzes aus dem passenden Lese-Tool. | | `tags` | nein | Schlagworte. | | `folderId` | nein | Ordner im Dateispeicher deines Mandanten. | Es gelten dieselben Regeln wie beim Hochladen im Browser: - Du brauchst das Recht, den Datensatz zu bearbeiten, und er muss in deinem Datenbereich liegen. Für `files.list` reicht das Leserecht. - Ein Datensatz, den es in deinem Mandanten nicht gibt oder den du nicht sehen darfst, ergibt `404`. - Erlaubt sind PDF, Word, Excel, PowerPoint, Bilder (PNG, JPEG, GIF, WebP, HEIC), Text, CSV, JSON, XML und ZIP. SynCore prüft den Inhalt gegen den angegebenen Typ, HTML und SVG werden abgelehnt. - Eine vorhandene Datei wird nicht ersetzt, jeder Aufruf legt eine neue an. - Die größte Datei bestimmt deine Instanz (Standard 100 MB). Base64 macht die Anfrage etwa ein Drittel größer als die Datei, plane große Dateien entsprechend ein oder lade sie im Browser hoch. Personal-, Bewerber-, Bildungs- und Belegakten nimmt das Tool bewusst nicht an. Lade Dokumente dort über die jeweilige Seite in SynCore hoch. ## Große Dateien ohne Base64: Upload- und Download-Link Base64 im Aufruf kostet Tokens: jedes Byte der Datei läuft durch das Sprachmodell, grob 400.000 Tokens je Megabyte. Von außen (MCP, API) nimmt `files.upload` deshalb nur kleine Dateien an (Standard 1 MB). Für alles, was als Datei vorliegt, gibt es den Link-Weg: das Werkzeug meldet die Datei an und liefert eine Adresse samt fertigem Befehl, die Bytes gehen direkt von der Platte zum Server. 1. `files.upload_link` mit Name, Typ und Datensatz aufrufen. Die Antwort enthält `url`, `expiresAt` und `befehle.bash` beziehungsweise `befehle.powershell`. 2. Den Befehl im Ordner der Datei ausführen, zum Beispiel: ```bash curl -sS -f -T "foto.png" -H "Content-Type: image/png" "https://deine-instanz/api/files/direkt/" ``` 3. Die Antwort des PUT ist die angelegte Datei (`id`, `url`). Mit `files.list` prüfen. Für den Weg zurück liefert `files.download_link` mit der `id` aus `files.list` eine Adresse für `GET`, zum Beispiel `curl -sS -f -o "foto.png" ""`. Die Datei kommt als Anhang. Regeln: - Ein Upload-Link gilt 15 Minuten und genau einmal, ein Download-Link 10 Minuten und bis dahin mehrfach. - Der Link ist an deinen Mandanten, deine Person, deinen API-Key und den Datensatz gebunden. Ein widerrufener Key macht den Link ungültig. Beim Abruf prüft SynCore das Recht am Datensatz noch einmal. - Der `Content-Type` im Befehl muss zum angemeldeten Typ passen, sonst antwortet der Server mit `415`. Ohne `Content-Type` gilt der angemeldete Typ. - Beim Empfang gelten dieselben Prüfungen wie beim Hochladen im Browser (Typ-Allowlist, Inhalt, Größe, Virenscan). Wird die Datei abgelehnt, bleibt der Link bis zum Ablauf für einen korrigierten Versuch offen. - Je Person sind höchstens 20 offene Links gleichzeitig möglich. - Das Protokoll enthält Name, Typ und Größe, nie den Inhalt. Der Befehl braucht eine Shell. Claude Code, Cursor und Skripte können ihn ausführen, ein Chat-Client ohne Shell nicht; dort bleibt `files.upload` für kleine Dateien. ## HTTP-Statuscodes | Status | Bedeutung | | --- | --- | | `200` | Katalog geliefert oder Tool erfolgreich ausgeführt. | | `400` | Tool-Name fehlt, JSON ist ungültig oder `input` verletzt das Schema. | | `401` | Session beziehungsweise API-Key fehlt oder ist ungültig. | | `403` | Scope, Actor-User, App-Aktivierung oder fachliche Berechtigung fehlt. | | `404` | Der angegebene Tool-Name existiert nicht, oder das Tool findet den angegebenen Datensatz nicht. | | `413` | Die Datei ist größer, als die Instanz annimmt (`files.upload`, `/api/files/direkt/`), oder der Base64-Aufruf von außen liegt über der kleinen Grenze (dann `files.upload_link` nehmen). | | `410` | Der Direktlink ist abgelaufen oder schon benutzt (`/api/files/direkt/`). | | `415` | Der `Content-Type` des PUT passt nicht zum angemeldeten Typ (`/api/files/direkt/`). | | `422` | Das Tool wurde gefunden, konnte die fachliche Aktion aber nicht ausführen. | | `429` | Zu viele Anfragen. Warte die Sekunden aus dem Header `Retry-After` ab. | | `501` | Für ein registriertes Tool fehlt serverseitig ein Handler; bitte den Support informieren. | ## Fehlerantworten Bei `400`, `401`, `403`, `404`, `413` und `501` steht die Ursache im Feld `message`: ```json { "message": "Tool nicht gefunden: crm.konto_lsit" } ``` Bei einem fachlichen Fehler liefert `422` stattdessen `ok`, `tool` und `error`: ```json { "ok": false, "tool": "beispiel.tool", "error": "Fachliche Ursache" } ``` `429` antwortet mit einem kurzen Klartext statt JSON und dem Header `Retry-After`. Welche Meldung was bedeutet, steht unter [Wenn eine API-Anfrage scheitert](https://support.unitedsynergy.com/api/fehlerbehebung/). Wiederhole `400`, `403` oder `422` nicht blind. Korrigiere zuerst Eingabe, Rechte oder fachlichen Zustand. ## Anfragelimits SynCore zählt Anfragen mit API-Key je Schlüssel, Methode und Endpunkt in einem Zeitfenster von einer Minute. | Limit | Standardwert | Folge | | --- | --- | --- | | Anfragen je API-Key | 1.200 pro Minute, getrennt für `GET` und `POST` | `429 Zu viele Anfragen` bis zum Ende des Zeitfensters | Jede Antwort trägt `X-RateLimit-Limit` (Limit im Zeitfenster) und `X-RateLimit-Remaining` (verbleibende Anfragen). Bei `429` nennt `Retry-After` die Wartezeit in Sekunden. Die Werte sind Standardwerte und können je Instanz abweichen. > **Sauber mit Limits umgehen** > > Verteile Massenläufe über die Zeit, wiederhole nach `429` erst nach `Retry-After` und nur einmal. Bei `401` prüfst du zuerst den Schlüssel, statt die Anfrage in einer Schleife zu wiederholen. ## OpenAPI-Datei Die Transport-API kannst du als [OpenAPI 3.1 herunterladen](https://support.unitedsynergy.com/openapi/syncore-app-tools.openapi.json) und in Postman, Bruno oder Insomnia importieren. Da die verfügbaren Tools dynamisch sind, ersetzt die OpenAPI-Datei nicht den Katalogabruf.