tokyntraildocs

API-Referenz: Grundlagen

Die tokyn.trail-API besteht aus zwei Oberflächen: der Core-API (REST, Holds, Reports, Verify) und dem MCP-Proxy-Endpoint (streamable HTTP für MCP-Clients). Beide authentifizieren mit denselben API-Keys.

Base-URLs#

OberflächeURLLokal (Dev)
Core-APIhttps://trail.tokyn.studiohttp://localhost:3000
MCP-Proxysiehe Serverseitehttp://localhost:3001

Authentifizierung#

Alle Requests tragen einen API-Key als Bearer-Token. Keys erstellen Sie unter Einstellungen → API-Keys; der Klartext wird genau einmal angezeigt, gespeichert wird nur ein SHA-256-Hash.

Authorization: Bearer tt_live_...   # Produktion
Authorization: Bearer tt_test_...   # Test/Entwicklung

Fachlich: Ein Key gehört zum Arbeitsbereich, nicht zu einer Person - Entscheidungen über die API werden deshalb nie einem menschlichen Approver zugeschrieben. Menschen entscheiden über Inbox, E-Mail-Link, SMS, Slack oder Widget; die API legt Holds an und fragt sie ab.

Zum Wort: Was die Oberfläche Arbeitsbereich nennt, heißt in der API und in den Belegen weiterhin org bzw. orgId - Server, Regeln, Freigaben und die Hash-Chain hängen daran. Organisation ist seit der Einführung der Vertragsebene die Klammer darüber (Plan, Rechnung, Kontingent) und taucht in der API nicht auf. Die alten Feldnamen bleiben, damit bestehende Integrationen und bereits ausgestellte Nachweise gültig bleiben.

Konventionen#

  • Alle Bodies sind JSON (Content-Type: application/json).
  • Zeitstempel sind UTC, ISO 8601 (2026-07-20T08:21:45.000Z).
  • Öffentliche Referenzen für Aktionen beginnen mit tt_pa_ - sie sind die IDs der Hold-API und der Statusseiten.
  • Idempotenz: POST /v1/holds verlangt einen idempotency_key; Wiederholungen liefern den ursprünglichen Hold statt Duplikate.
  • Versionierung: Alle Endpoints tragen den Pfad-Prefix /v1. Breaking Changes erscheinen nur unter einer neuen Version - /v1 bleibt stabil.

Rate Limits#

120 Anfragen pro Minute, gezählt pro Arbeitsbereich und nicht pro API-Key - sonst umginge man das Limit, indem man sich weitere Schlüssel ausstellt. Teure Pfade haben eigene Töpfe, damit ein PDF-Export nicht das Kontingent Ihrer normalen Aufrufe frisst:

TopfGilt für
v1Hold-API (anlegen, abfragen)
v1-waitPOST /v1/holds/:id/wait (Long-Poll)
v1-reportsOversight- und Activity-Report (CSV/PDF)
v1-verifyLauf durch die Hash-Chain

Über dem Kontingent antwortet die API mit 429 und { "error": "rate_limited" }, dazu Retry-After und die RateLimit-*-Header mit Limit, Rest und Sekunden bis zum nächsten Fenster. Aufrufe ohne Anmeldung sind deutlich enger begrenzt: 20 pro Minute und IP.

Das Fenster ist fest, nicht gleitend - an der Fenstergrenze sind kurzzeitig bis zu zwei Kontingente möglich. Das ist bekannt und hinnehmbar: Es geht um Missbrauchsabwehr, nicht um exakte Zuteilung. Fällt die Zählung selbst aus, wird durchgelassen; ein Schutz, der bei einem Datenbankwackler die ganze API abschaltet, richtet mehr Schaden an als er verhindert.

Davon unabhängig gelten Ihre eigenen Frequenz-Regeln (z. B. „mehr als 20 Calls/Stunde → halten"). Für die Statusabfrage empfehlen wir POST /holds/:id/wait (Long-Poll) oder Webhooks statt engem Polling.

Fehlerformat#

Fehler enthalten nie Payload-Inhalte - nur einen Code, bei Validierungsfehlern die betroffenen Felder und bei internen Fehlern eine referenceId für den Support:

{ "error": "invalid_json" }
{ "error": "validation_failed", "detail": "tool_name: String must contain at least 1 character(s)",
  "issues": [{ "field": "tool_name", "message": "String must contain at least 1 character(s)" }],
  "docs": "https://trail.tokyn.studio/docs/api/holds" }
{ "error": "internal", "referenceId": "b3f6…" }

Alle Statuscodes: Fehlercodes.

Endpoint-Übersicht#

Methode & PfadZweck
POST /api/v1/holdsAktion zur Freigabe einreichen (Regeln entscheiden: allowed / pending / denied)
GET /api/v1/holds/:idStatus einer Aktion abfragen (Polling)
POST /api/v1/holds/:id/waitLong-Poll auf die Entscheidung (max. 60 s pro Runde)
GET /api/v1/reports/oversightOversight-Report als CSV/PDF
GET /api/v1/reports/activityActivity-Report als CSV/PDF
GET /api/v1/audit/verifyHash-Chain des Arbeitsbereichs verifizieren

Das ist die vollständige /v1-Oberfläche. MCP-Server, Regeln, Approver und Webhook-Konfiguration verwalten Sie derzeit in der App - es gibt bewusst noch keine Management-API, keine Hold-Liste und kein programmatisches Storno. Wenn Ihnen davon etwas fehlt, sagen Sie es uns.

MCP-Proxy-Endpoint#

Pro MCP-Server existiert ein Endpoint (streamable HTTP, kein stdio):

URL:    <MCP-Server-URL aus der App>
Header: Authorization: Bearer tt_live_...
        X-TokynTrail-Agent: <agent-id>        # optional, erscheint in der Evidenz
        X-TokynTrail-Session: <session-id>    # optional, Bezugsrahmen der Idempotenz
  • tools/list wird durchgereicht und löst die Tool-Discovery aus; zusätzlich injiziert der Proxy das Tool tokyn_trail_check_status.
  • tools/call wird je nach Regel durchgereicht, gehalten (sofortige Antwort mit tt_pa_…-Referenz - die Verbindung blockiert nie) oder mit MCP-Error -32003 abgelehnt.
  • Nach einer Freigabe führt der Proxy den Upstream-Call selbst aus.

Antwort auf einen gehaltenen Aufruf#

Die Antwort besteht aus zwei Textblöcken: einem Satz für den Menschen und demselben Stand als JSON. Sie trägt die Aktion mit sich - ein Agent, der nur diese Antwort hat, kann dem Nutzer sagen, was wartet:

{
  "tokyn_trail": {
    "status": "held",
    "reference": "tt_pa_0198…",
    "status_url": "https://trail.tokyn.studio/a/tt_pa_0198…",
    "terminal": false,
    "retryable": false,
    "retry": "poll",
    "message": "Action held for human approval: create_quote: customer=ACME GmbH, amount=1.295,00 €. …",
    "action": {
      "tool": "create_quote",
      "arguments": { "customer": "ACME GmbH", "amount_cents": 129500 },
      "summary": "create_quote: customer=ACME GmbH, amount=1.295,00 €"
    },
    "expires_at": "2026-09-03T16:00:00.000Z"
  }
}

Denselben Umschlag liefert tokyn_trail_check_status. status ist eines von held, approved, executed, denied, expired, error oder unknown_reference; retry sagt, was zu tun ist: poll (noch offen), none (fertig), never (abgelehnt - nicht erneut versuchen) oder new_request (abgelaufen oder fehlgeschlagen - eine neue Anfrage ist erlaubt). Bei executed folgt das Ergebnis des Upstream-Calls als weitere Inhaltsblöcke.

Idempotenz#

Ein identischer Aufruf - gleiches Werkzeug, gleiche Argumente, gleiche Sitzung - erzeugt genau einen Vorgang. Während der Hold offen ist, liefert jeder Wiederholungsaufruf denselben Hold zurück (gekennzeichnet mit "deduplicated": true); nach einer Freigabe das Ergebnis der bereits ausgeführten Aktion, ohne sie erneut auszuführen; nach einer Ablehnung dieselbe Ablehnung. Läuft ein Hold ab oder schlägt die Ausführung fehl, ist der nächste identische Aufruf wieder eine echte Anfrage. Ohne X-TokynTrail-Session gilt die Agent-Identität als Sitzung.