Schnittstelle · v1

API und Webhooks

Alles, was dein Sprachmodell über MCP kann, geht auch per HTTP. Ein Trainingsplaner, ein Vereinsportal oder eine eigene Automation ruft dieselben Werkzeuge auf und hält sich dabei an dieselben Regeln. Webhooks melden, wenn sich etwas geändert hat, die Daten holt sich das andere System dann über die API.

Überblick

Die Schnittstelle hat drei Teile. Die Tool-API und die Webhooks gehören zusammen, die Ingest-API ist ein eigener Eingang für Messwerte.

TeilPfadRecht des TokensWofür
Tool-API/api/v1/toolsapi:read · api:writeJedes Werkzeug des MCP-Servers, lesend und schreibend.
Webhooks/api/v1/webhooksapi:read · api:writeAbos anlegen, Zustellungen einsehen, Test-Ping schicken.
Ingest-API/api/ingest/v1ingestKörperwerte von Waagen und Automationen einliefern. Zur Doku der Ingest-API
Ohne Token antwortet keine dieser Adressen mit Daten. Öffentlich ist nur die Beschreibung als OpenAPI, und die enthält keine Daten.

Token anlegen

Für die Tool-API und die Webhooks brauchst du ein API-Token. Es erreicht nur /api/v1, kein MCP und keine Seiten des Webs. Ein MCP-Token oder ein Ingest-Token funktioniert hier nicht.

  1. Öffne im Kontobereich „Verbindungen“.
  2. Lege unter „API und Webhooks“ ein Token an und gib ihm den Namen des Systems, das es nutzt. Der Name steht später im Protokoll jedes Aufrufs.
  3. Entscheide, ob es nur lesen oder auch schreiben darf. Lesen reicht für alle lesenden Werkzeuge und zum Einsehen der Webhooks. Schreibende Werkzeuge und das Anlegen von Webhooks brauchen das Schreibrecht.
  4. Kopier das Token. Es steht nur einmal im Klartext da.
Zu den Verbindungen

Werkzeuge aufrufen

Ein Werkzeug ruft man mit POST auf seine Adresse auf. Der Körper ist das Objekt der Argumente, genau wie im MCP. Ohne Körper gelten die Vorgaben des Werkzeugs, bei Zeiträumen etwa die letzten sieben Tage. Die Antwort enthält unter result dasselbe, was ein Sprachmodell bekommt.

Anfrage
curl -X POST https://api.training-mcp.app/api/v1/tools/activities \
  -H "Authorization: Bearer DEIN_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"from": "2026-10-01", "to": "2026-10-07", "sport": "run"}'
Antwort
{
  "tool": "activities",
  "result": {
    "items": [
      { "id": 18231, "sport": "run", "start": { "utc": "2026-10-06T05:31:00Z", "local": "6. Oktober 2026 07:31" },
        "duration_min": 52.4, "distance_km": 10.02, "hr_avg_bpm": 141, "source": "garmin" }
    ],
    "attribution": "Enthält Daten von Garmin-Geräten. Nenne Garmin als Quelle, wenn du diese Werte wiedergibst."
  }
}

HTTP-Status

200
Erfolg. Das Ergebnis steht in result.
401
Kein oder ein widerrufenes Token.
403
Das Token hat das nötige Recht nicht, etwa ein Lese-Token an einem schreibenden Werkzeug, oder die Einwilligung zur Weitergabe ist widerrufen.
404
Ein Werkzeug dieses Namens gibt es nicht.
409
Schreibkonflikt: Unter dem Schlüssel steht schon etwas anderes. Beide Fassungen stehen in result, siehe „Schreiben“.
422
Die Argumente passen nicht, etwa ein falsches Datumsformat oder eine unbekannte Kennung. Der Grund steht in message.
429
Mehr als 120 Aufrufe in der Minute je Token.

Für jeden Aufruf gilt, was im MCP gilt: Du siehst nur die Daten deines Kontos, Jugendkonten bekommen dieselben Einschränkungen, und wo Garmin-Daten drinstecken, steht der Hinweis auf Garmin in attribution. Jeder Aufruf steht im Protokoll deines Kontos, mit dem Namen des Tokens.

Alle Werkzeuge

Die Liste kommt direkt vom Server, aus derselben Beschreibung, die ein MCP-Client bekommt. Was hier steht, geht auch.

Die Liste wird geladen …

Schreiben

Schreiben geht nur über die schreibenden Werkzeuge. Einen zweiten Weg an ihnen vorbei gibt es nicht, auch nicht für die API. Damit gelten dieselben Regeln wie im Gespräch mit dem Sprachmodell.

  • Versioniert: Regeln, Profil und Status bekommen bei jeder Änderung eine neue Fassung, die alte bleibt lesbar.
  • Kein stilles Überschreiben: Steht unter demselben Schlüssel (Tag, Einheit, Titel) schon etwas anderes, kommt 409 mit beiden Fassungen zurück. Mit mode replace überschreibst du, mit mode append ergänzt du.
  • Dasselbe zweimal geschrieben bleibt ein Eintrag. Ein Aufruf lässt sich also gefahrlos wiederholen.
  • Quelle: Jeder Eintrag nennt, woher er kommt. Ohne Angabe steht „api“ da, mit dem Argument source ein eigener Name, etwa der deines Systems.
  • Nichts wird gelöscht. Mit discard wird ein Eintrag als verworfen markiert.
  • Messwerte schreibst du hier nicht. Strecke, Puls oder Gewicht kommen aus den Quellen, für eigene Messwerte gibt es die Ingest-API.
Beispiel: Notiz zu einem Tag
curl -X POST https://api.training-mcp.app/api/v1/tools/note-day \
  -H "Authorization: Bearer DEIN_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"date": "2026-10-07", "kind": "illness", "note": "Erkältet, Training fällt aus.", "source": "vereinsportal"}'
Derselbe Tag mit anderem Text
HTTP/1.1 409 Conflict

{
  "tool": "note-day",
  "result": {
    "status": "conflict",
    "message": "Unter diesem Schlüssel steht schon etwas anderes. … Zum Überschreiben erneut mit mode replace aufrufen, zum Ergänzen mit mode append.",
    "stored": { "id": 1, "date": "2026-10-07", "kind": "illness", "note": "Erkältet, Training fällt aus.", "source": "vereinsportal" },
    "differences": {
      "note": { "stored": "Erkältet, Training fällt aus.", "new": "Nur leicht erkältet, locker laufen." }
    }
  }
}

Webhooks

Ein Webhook ist ein Ping. training mcp meldet an eine Adresse deiner Wahl, dass sich etwas geändert hat, und nennt Kennungen und das Werkzeug, das die Daten liefert. Inhalte stehen nicht darin. Dein System holt sie sich mit seinem Token über die API.

activity.created
Neue Einheiten sind da, aus jeder Quelle. data.activity_ids
activity.updated
Eine Einheit hat eine Datei oder eine zweite Quelle bekommen. data.activity_ids
daily.updated
Tageswerte wie Schlaf, HRV oder Ruhepuls sind neu oder geändert. data.dates
body.updated
Körperwerte sind neu oder geändert. data.measured_at
record.written
Ein schreibendes Werkzeug hat etwas gespeichert, aus MCP, API oder Web. data.records mit Typ, Kennung, Aktion, Werkzeug und Client
ping
Test, ausgelöst im Web oder per API.
Abo anlegen
curl -X POST https://api.training-mcp.app/api/v1/webhooks \
  -H "Authorization: Bearer DEIN_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.org/hooks/training", "events": ["activity.created", "record.written"]}'
Eine Zustellung
POST https://example.org/hooks/training
Content-Type: application/json
X-Training-MCP-Event: activity.created
X-Training-MCP-Delivery: 9f1c2b7e-…
X-Training-MCP-Signature: t=1791370000,v1=5d2f…

{
  "id": "9f1c2b7e-…",
  "event": "activity.created",
  "created_at": "2026-10-07T06:12:00Z",
  "data": { "activity_ids": [18231, 18232], "more": false },
  "fetch": { "tool": "activity-detail", "url": "https://api.training-mcp.app/api/v1/tools/activity-detail" }
}
  • Das Secret steht nur in der Antwort auf das Anlegen. Mit POST /api/v1/webhooks/{id}/secret erzeugst du ein neues, das alte gilt dann nicht mehr.
  • Gesammelt: Was innerhalb von 30 Sekunden anfällt, kommt als eine Zustellung mit bis zu 100 Kennungen, darüber steht more: true. Ein großer Import erzeugt so einige Pings statt Tausender.
  • Eigene Änderungen erkennen: record.written nennt den Client. Was dein System selbst über die API geschrieben hat, steht dort als api: mit dem Namen deines Tokens.
  • Zustellung: Erfolg ist jeder Status 2xx binnen zehn Sekunden. Sonst folgen Versuche nach 1, 5 und 30 Minuten, 2 und 6 Stunden. Weiterleitungen werden nicht verfolgt.
  • Nach zehn fehlgeschlagenen Zustellungen in Folge wird das Abo pausiert, und du bekommst eine Mail. Fortsetzen geht unter „Verbindungen“ oder mit PATCH und paused: false.
  • Nur öffentliche HTTPS-Adressen. Ziele im privaten oder internen Netz lehnt der Server ab, beim Anlegen und vor jeder Zustellung.
  • Höchstens zehn Abos je Konto. Die letzten Zustellungen mit Status und Antwortcode stehen unter GET /api/v1/webhooks/{id}/deliveries, 30 Tage lang.

Signatur prüfen

Jede Zustellung trägt im Header X-Training-MCP-Signature einen Zeitstempel t und die Signatur v1. Die Signatur ist HMAC-SHA256 mit deinem Secret über den Zeitstempel, einen Punkt und den rohen Körper. Prüf sie, bevor du etwas tust, vergleich in konstanter Zeit und verwirf Zustellungen, die älter als fünf Minuten sind. Gezählt wird der rohe Körper, wie er ankommt, nicht ein neu serialisiertes JSON.

Python
import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, sig = parts["t"], parts["v1"]
    if abs(time.time() - int(t)) > 300:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)
Node.js
import { createHmac, timingSafeEqual } from 'node:crypto'

export function verify(secret, header, rawBody) {
  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')))
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false
  const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')
  return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}

Maschinenlesbar

Tool-API und Webhooks beschreiben sich selbst als OpenAPI 3.1, erzeugt aus den Schemas der Werkzeuge. Wer eine Anbindung bauen lässt, auch von einem Sprachmodell, gibt am besten diese Datei mit.

OpenAPI 3.1
https://api.training-mcp.app/api/v1/openapi.json

Datenschutz

Über die API gehen deine Trainings- und Gesundheitsdaten an das System, dem du ein Token gibst. Das entscheidest du, und du nimmst es mit dem Widerruf des Tokens zurück. Es gilt dieselbe Einwilligung wie für dein Sprachmodell. Widerrufst du sie, antworten die Werkzeuge nicht mehr, nur account-status sagt noch, warum. Webhooks enthalten keine Inhalte, nur Kennungen.

Datenschutzerklärung