hermine desk Handbuch
Konzepte

API und MCP

hermine.ai desk von außen: GraphQL-API mit JWT und X-Tenant-Header, MCP-Server pro Desk für Claude Code und Cursor, E-Mail-Webhook und Widget-Embed.

Authentifizierung

Alle API-Aufrufe sprechen mit dem Backend von hermine.ai desk (in den Beispielen https://api.hermine-desk.example.com, lokal http://localhost:4100). Zwei Header brauchen Sie fast immer:

X-Tenant ist die Subdomain Ihres Workspace (z. B. acme): hermine.ai desk trennt Workspaces strikt auf Datenbankebene, der Header wählt Ihren aus. Authorization: Bearer trägt ein JWT aus der signIn-Mutation. Access-Tokens laufen nach 15 Minuten ab, Refresh-Tokens nach 30 Tagen; mit refreshSession tauschen Sie einen gültigen Refresh-Token gegen ein frisches Paar.

Token holen (Login)bash
curl -s https://api.hermine-desk.example.com/graphql \
  -H "Content-Type: application/json" \
  -H "X-Tenant: acme" \
  -d '{
    "query": "mutation($email: String!, $password: String!) { signIn(input: { email: $email, password: $password }) { accessToken refreshToken user { id email } errors } }",
    "variables": { "email": "simon@example.com", "password": "geheim" }
  }'

Hinweis: Bei erzwungenem SSO (Microsoft Entra ID) ist der Passwort-Login für das Team deaktiviert; signIn liefert dann einen erklärenden Fehler.

GraphQL-Endpunkt

Die gesamte App läuft über POST /graphql (JSON-Body mit query und optional variables). Rechte werden pro Feld geprüft: ohne Anmeldung antwortet die API mit UNAUTHENTICATED, ohne ausreichende Rechte mit NOT_AUTHORIZED. In der Entwicklungsumgebung ist GraphiQL unter /graphiql erreichbar.

Daneben gibt es zwei REST-Nebenrouten mit derselben Auth: POST /uploads nimmt Dateien als Multipart entgegen und liefert eine signedId für Mutationen wie createCrmDocument, und GET /events/desks/:desk_key ist der SSE-Änderungsfeed eines Desks.

Wer bin ich (currentUser)bash
curl -s https://api.hermine-desk.example.com/graphql \
  -H "Content-Type: application/json" \
  -H "X-Tenant: acme" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{ "query": "{ currentUser { id email fullName role } }" }'
Query mit Argumenten (Konversationen eines Desks)bash
curl -s https://api.hermine-desk.example.com/graphql \
  -H "Content-Type: application/json" \
  -H "X-Tenant: acme" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "query": "query($deskKey: String!) { conversations(deskKey: $deskKey, limit: 10) { id subject status company { name } } }",
    "variables": { "deskKey": "support" }
  }'
Mutation (CRM-Unternehmen anlegen)bash
curl -s https://api.hermine-desk.example.com/graphql \
  -H "Content-Type: application/json" \
  -H "X-Tenant: acme" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "query": "mutation($name: String!, $domain: String) { createCompany(input: { name: $name, domain: $domain }) { company { id name } errors } }",
    "variables": { "name": "Nordwind Logistik GmbH", "domain": "nordwind.example" }
  }'

MCP für externe KI-Agenten

hermine.ai desk stellt pro Desk einen MCP-Server bereit (POST /mcp, eine JSON-RPC-Nachricht pro Request). Externe Agenten wie Claude Code oder Cursor bekommen damit genau die Werkzeuge, die der eingebaute Assistent auf diesem Desk hat, nie mehr: die Lese-Tools (knowledge.search, conversations.search, conversations.get, dazu Lookups aktiver Konnektoren) plus die nutzerautorisierten Aktions-Tools (Antworten, Status, Deals, Wiedervorlagen und weitere).

Zusätzlich zu Authorization und X-Tenant wählt der Header X-Desk-Key den Desk; Ihre Desk-Mitgliedschaft wird geprüft und jeder Tool-Aufruf landet als mcp.tool_called-Event im Audit-Log (nur Metadaten, nie Inhalte).

Claude Code (CLI)bash
claude mcp add --transport http hermine.ai https://api.hermine-desk.example.com/mcp \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --header "X-Tenant: acme" \
  --header "X-Desk-Key: support"
Claude Code (.mcp.json im Projekt)json
{
  "mcpServers": {
    "hermine.ai": {
      "type": "http",
      "url": "https://api.hermine-desk.example.com/mcp",
      "headers": {
        "Authorization": "Bearer <ACCESS_TOKEN>",
        "X-Tenant": "acme",
        "X-Desk-Key": "support"
      }
    }
  }
}
Cursor (.cursor/mcp.json)json
{
  "mcpServers": {
    "hermine.ai": {
      "url": "https://api.hermine-desk.example.com/mcp",
      "headers": {
        "Authorization": "Bearer <ACCESS_TOKEN>",
        "X-Tenant": "acme",
        "X-Desk-Key": "support"
      }
    }
  }
}

Achtung: Access-Tokens aus signIn laufen nach 15 Minuten ab und MCP-Clients erneuern eingetragene Header nicht selbst. Für dauerhafte Agent-Setups nehmen Sie deshalb besser ein persönliches API-Token (PAT, siehe unten): Es läuft nicht ab, Sie tragen es einmal als Authorization: Bearer hermine_pat_… ein und müssen nichts per refreshSession nachziehen.

Persönliche API-Tokens (PAT)

Für dauerhafte Integrationen und Skripte gibt es persönliche API-Tokens, kurz PAT. Ein PAT ist an Sie als Person gebunden und läuft nicht nach 15 Minuten ab, er löst also genau das Problem der kurzlebigen JWT-Access-Tokens.

Sie legen ihn unter Persönlich, API-Zugang an. Der Token wird genau einmal angezeigt, im Format hermine_pat_…; kopieren Sie ihn sofort und bewahren Sie ihn sicher auf, danach zeigt hermine.ai desk ihn nie wieder. Beim Anlegen wählen Sie die Scopes (Lesen oder Schreiben) und optional ein Ablaufdatum. Einen Token, den Sie nicht mehr brauchen oder der abhandengekommen ist, können Sie jederzeit widerrufen.

Der PAT ersetzt das JWT im Authorization-Header und funktioniert sowohl auf GraphQL als auch auf MCP: Authorization: Bearer hermine_pat_…. Für Agent-Setups und Skripte ist der PAT gegenüber dem kurzlebigen JWT die klar empfohlene Wahl.

GraphQL mit PAT (currentUser)bash
curl -s https://api.hermine-desk.example.com/graphql \
  -H "Content-Type: application/json" \
  -H "X-Tenant: acme" \
  -H "Authorization: Bearer hermine_pat_xxxxxxxxxxxx" \
  -d '{ "query": "{ currentUser { id email } }" }'
Claude Code mit PAT statt JWTbash
claude mcp add --transport http hermine.ai https://api.hermine-desk.example.com/mcp \
  --header "Authorization: Bearer hermine_pat_xxxxxxxxxxxx" \
  --header "X-Tenant: acme" \
  --header "X-Desk-Key: support"

Tipp: Für MCP-Clients und Skripte nehmen Sie am besten einen PAT statt eines JWT: Er läuft nicht nach 15 Minuten ab, Sie müssen also nichts per refreshSession erneuern und keinen Header nachtragen. Vergeben Sie nur den Scope, den die Integration wirklich braucht (oft reicht Lesen), und setzen Sie im Zweifel ein Ablaufdatum.

Achtung: Der Token erscheint nur ein einziges Mal. Verpassen Sie das Kopieren, legen Sie einen neuen an; der alte lässt sich nicht erneut anzeigen. Behandeln Sie den PAT wie ein Passwort und legen Sie ihn nie im Code-Repository ab.

REST-API v1

Neben GraphQL gibt es eine schlanke REST-API unter /api/v1, gedacht für einfache Integrationen, die keinen GraphQL-Client mitbringen wollen. Sie authentifiziert sich per PAT (Authorization: Bearer hermine_pat_…) plus dem X-Tenant-Header, genau wie GraphQL.

Listen liefern Cursor-Pagination (ein cursor zeigt auf die nächste Seite), und Fehler kommen in einem einheitlichen Fehler-Envelope: { error: { code, message } }. Abgedeckt sind die Kernressourcen conversations, companies, contacts, deals, quotes und projects, jeweils als Liste und Detail plus die wichtigsten Kernverben. Alles Darüberhinausgehende bleibt bewusst GraphQL und MCP vorbehalten, die REST-API deckt die häufigen, einfachen Fälle ab.

Liste abrufen (Konversationen)bash
curl -s "https://api.hermine-desk.example.com/api/v1/conversations?limit=20" \
  -H "X-Tenant: acme" \
  -H "Authorization: Bearer hermine_pat_xxxxxxxxxxxx"
Detail abrufen (ein Unternehmen)bash
curl -s https://api.hermine-desk.example.com/api/v1/companies/123 \
  -H "X-Tenant: acme" \
  -H "Authorization: Bearer hermine_pat_xxxxxxxxxxxx"

Hinweis: Brauchen Sie Felder, Beziehungen oder Verben, die die REST-API nicht bietet, greifen Sie für dieselbe Ressource einfach zu GraphQL oder MCP. Beide sprechen dasselbe Backend mit derselben PAT-Anmeldung.

Inbound-E-Mail-Webhook

Eingehende E-Mails (Brevo Inbound Parse oder Postmark Inbound JSON) erreichen hermine.ai desk über eine eigene URL pro E-Mail-Kanal: POST /webhooks/email/:channel_token. Die fertige URL finden Sie in den Kanal-Einstellungen des Desks.

Hier gibt es keinen Login und keinen X-Tenant-Header: der Token in der URL löst den Workspace auf. Authentifiziert wird stattdessen per HMAC-Signatur: der Header X-Webhook-Signature trägt HMAC-SHA256(signing_secret, raw_body) als Hex-Wert; das Signing-Secret hinterlegen Sie am Kanal (es bleibt write-only). Antworten: 200 (angenommen, Verarbeitung asynchron), 401 (Signatur ungültig), 404 (Token unbekannt oder Desk archiviert).

Signatur erzeugen und sendenbash
BODY='{"From":"kunde@example.org","Subject":"Hilfe","TextBody":"Hallo"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SIGNING_SECRET" -hex | sed 's/^.* //')
curl -s https://api.hermine-desk.example.com/webhooks/email/$CHANNEL_TOKEN \
  -H "Content-Type: application/json" \
  -H "X-Webhook-Signature: $SIG" \
  -d "$BODY"

Outbound-Webhooks

In die andere Richtung kann hermine.ai desk Ihr System aktiv benachrichtigen: Outbound-Webhooks schicken bei bestimmten Ereignissen eine HTTP-Nachricht an eine URL Ihrer Wahl. So halten Sie ein CRM, ein Data-Warehouse oder eine eigene Automatik auf dem Laufenden, ohne ständig zu pollen.

Sie richten sie unter Einstellungen, Webhooks ein (eine Admin-Aufgabe). Dort tragen Sie Ihre Ziel-URL ein und abonnieren die Events, die Sie interessieren. Jede Auslieferung ist HMAC-SHA256-signiert: Der Header X-Hermine-Signature trägt die Signatur über den rohen Body, sodass Sie auf Ihrer Seite prüfen können, dass die Nachricht wirklich von hermine.ai desk stammt. Das Signing-Secret wird beim Anlegen genau einmal angezeigt. Schlägt eine Zustellung fehl, versucht hermine.ai desk es mit Retry erneut.

Signatur auf Ihrer Seite prüfen (Node.js)bash
const crypto = require("crypto");
const expected = crypto
  .createHmac("sha256", SIGNING_SECRET)
  .update(rawBody)
  .digest("hex");
// vergleichen Sie expected mit dem Header X-Hermine-Signature
const ok = crypto.timingSafeEqual(
  Buffer.from(expected),
  Buffer.from(req.headers["x-hermine-signature"]),
);

Achtung: Verifizieren Sie jede eingehende Auslieferung: Bilden Sie HMAC-SHA256(signing_secret, raw_body) und vergleichen Sie das Ergebnis mit dem Header X-Hermine-Signature, am besten zeitkonstant. Nehmen Sie den rohen Body vor jeglichem JSON-Parsen, sonst stimmt die Signatur nicht. Das Signing-Secret sehen Sie nur einmal, notieren Sie es sich beim Anlegen.

Widget einbinden

Das Chat-Widget kommt mit zwei Script-Tags auf jede Website. Den fertigen Schnipsel kopieren Sie aus den Kanal-Einstellungen (Widget-Kanal des Desks); er sieht so aus:

Embed-Schnipselhtml
<script>
  window.hermineWidgetSettings = { token: "<WIDGET_TOKEN>", baseUrl: "https://api.hermine-desk.example.com" };
</script>
<script src="https://api.hermine-desk.example.com/widget.js" async></script>

Hinweis: /widget.js ist öffentlich und cachebar; das Script injiziert Launcher und iframe. Die Widget-API-Routen unter /widget/:channel_token/… sind die einzigen mit offenem CORS und authentifizieren über den öffentlichen Channel-Token plus, ab der ersten Nachricht, einen signierten Conversation-Token.

Auf dieser Seite