Kinellect
Integration guide · API v1 · Connector contract v1

Introduction

Kinellect is a coaching service for fitness and rehabilitation products. Your application keeps its users, content, subscriptions and user interface. Kinellect adds a coach on top: it holds conversations with your users, builds validated workout drafts from your exercise catalog, decides what a user should do today (workout, rest or mobility), reacts to completed workouts, and remembers coaching preferences.

Kinellect is generic. It contains no knowledge of any particular client. Everything specific to your product arrives through your configuration, the context you send about each user, and the connector endpoints you implement.

The two directions of integration

Integrating means building two things:

  1. Calls from your backend to the Kinellect API. You activate a configuration, register users, send their context, start conversations, and request workouts and daily plans.
  2. A connector that Kinellect calls. A small HTTPS service on your side that answers questions about your content and a user's current situation, and performs actions you allow, such as saving a workout.
flowchart LR
  subgraph You["Your platform"]
    App["Your app / backend"]
    Conn["Your connector (HTTPS)"]
    DB[("Your users, catalog,<br/>schedules, history")]
  end
  subgraph K["Kinellect"]
    API["Kinellect API /v1"]
    W["Durable workers"]
  end
  App -- "Bearer API token" --> API
  API --> W
  W -- "Bearer connector secret" --> Conn
  Conn --> DB

Your backend calls Kinellect with an API token that Kinellect issues to you. Kinellect calls your connector with a connector secret that you issue to Kinellect. The two credentials are independent.

Who owns what

Kinellect owns You own
Coaching conversations and their history User identity, accounts and authentication
Coach memory (coaching preferences) Subscriptions, entitlements and billing
Workout drafts it generates and daily decisions Your exercise and workout catalog
Safety validation of everything it proposes Accepted workouts, schedules and workout history
Durable processing, retries and usage accounting Your user interface and notifications

Kinellect never writes to your systems directly. When a user accepts a workout, Kinellect asks your connector to save it, and your connector decides.

Important properties

  • Asynchronous by design. Anything that involves a model or your connector runs as a durable Operation. You receive 202 Accepted with an Operation reference and poll it to a terminal state. There are no webhooks in v1.
  • Idempotent writes. Every write takes an Idempotency-Key. Retrying the same request with the same key is always safe and returns the original result.
  • Strict contracts. Unknown fields are rejected, and so are values outside documented limits. Connector responses must contain exactly the documented keys.
  • Tenant isolation. Each client works inside its own tenant environment. References that belong to another tenant behave exactly like references that do not exist.
  • Truthful output. Kinellect renders user-facing text from verified sources and recorded outcomes. It never tells a user that something happened unless your connector confirmed it.

What this documentation contains

  • Onboarding walks through the steps from zero to a working integration.
  • Core concepts and API conventions cover the ideas and rules every endpoint shares.
  • Quickstart is one complete request sequence you can run with curl.
  • The capability guides cover conversation, workout drafts, daily plans, workout acceptance and workout completion.
  • Build your connector specifies what your HTTPS service must implement.
  • Using these docs with an LLM explains how to hand this material to a coding assistant.
  • The API reference holds both OpenAPI 3.1 specifications: the Kinellect API you call, and the Connector API you implement.

Onboarding

These steps take you from nothing to a working integration. Steps 1 and 3 need the Kinellect team; the rest you do yourself.

1. Receive your environment and API token

The Kinellect team creates a tenant environment for you and issues an API token. You receive:

  • the base URL of the Kinellect API, https://api.kinellect.com, used as KINELLECT_BASE_URL throughout these docs;
  • an API token. It is shown once, so store it in your secret manager immediately;
  • the scopes attached to the token (see Authentication and scopes).

Tell the team which capabilities you will use, so the token carries matching scopes. A full integration needs all eight: configuration:write, context:write, conversation:write, conversation:read, workout:write, workout:read, coaching:write and coaching:read. Each :read scope is what lets you poll that capability's Operations.

Tokens stay valid until they are revoked, and each one can be revoked on its own. Ask for a new token rather than sharing one between systems. Kinellect cannot show a token again after issuing it; if you lose it, ask for a new one and have the old one revoked.

2. Build your connector

Build the HTTPS service described in Build your connector. Implement only the endpoints for the capabilities you plan to enable. For example, a conversation-only integration with exercise lookups needs capabilities, context/resolve, content/exercises/search and content/exercises/resolve.

Your connector must be reachable over public HTTPS before step 4, because activation calls it.

3. Register your connector with Kinellect

Send the Kinellect team:

  • your connector base URL (HTTPS);
  • a connector secret: a long random bearer token that Kinellect will send in Authorization: Bearer ... on every connector call. Share it through a secure channel, never by email.

Kinellect stores the secret in its managed secret store and returns a connector registration reference (connector_registration_ref, a UUID). You cannot change the URL or secret through the API; ask the Kinellect team to register a new one when they change.

4. Activate your first client configuration

Decide which capabilities to enable and which policies apply, then call:

PUT /v1/client-configurations/1/activate

Activation checks your choices, calls your connector's capabilities endpoint, and stores configuration version 1 as immutable. To change anything later, activate version 2, then 3, and so on. See Client configuration.

5. Register each user

Kinellect calls your users Subjects. You register a user by creating their first Conversation Thread with your own user identifier:

POST /v1/threads
{"external_subject_ref": "your-user-8841", "main": true}

The response contains subject_ref, Kinellect's UUID for that user. Store the mapping from your user id to subject_ref:

  • every other endpoint identifies the user by subject_ref;
  • your connector receives subject_ref, not your user id.

Repeating the call with the same external_subject_ref always yields the same subject_ref.

external_subject_ref is visible only to Kinellect and your integration. Use an opaque, stable identifier, not an email address or name.

6. Keep each user's context current

Send the facts Kinellect needs about the user (goal, experience, available days, equipment, safety constraints, recovery) as an immutable, versioned Subject context. Push it with PUT /v1/subjects/{subject_ref}/context/{context_version} whenever those facts change. You can also let Kinellect pull it from your connector's context/resolve endpoint. See Subject context.

7. Use the capabilities

With configuration and context in place you can:

Go-live checklist

  • The API token lives in a secret manager and is never shipped to mobile or web clients. All Kinellect calls come from your backend.
  • Every write sends a fresh Idempotency-Key, and retries reuse the original key.
  • Your code handles every Operation state: completed, failed, cancelled and expired.
  • You honour 429 and its Retry-After header.
  • Your connector returns exactly the documented keys and answers within 2 seconds.
  • Your connector verifies the bearer secret and the X-Kinellect-Tenant header on every call.
  • You store the mapping between your user ids and subject_ref.
  • Context is pushed, or resolvable through the connector, before you request daily plans or workout drafts.

Core concepts

Tenant environment

A tenant environment is your isolated space in Kinellect. Your API token, connector registration, configurations, users, conversations and Operations all belong to it. Nothing crosses between tenant environments. A reference from another tenant behaves exactly like one that does not exist, so it returns 404.

Client configuration

A client configuration describes how Kinellect coaches for your product: who you are, which capabilities are on, which actions are allowed, and the limits that apply. Each configuration version is immutable. You activate version 1, then 2, and so on. The newest activated version is current.

Each Operation records the configuration version it was admitted under, and results report the versions they used. For example, a daily plan decision includes configuration_version and context_version. Some work rechecks currentness before acting: workout acceptance, for instance, verifies again that the configuration and context still allow the action before your connector is called.

Field Purpose
client_description, product_description Plain-language description of your company and product, used to frame coaching (up to 2000 bytes each).
coaching_domain Short domain label, for example fitness coaching or knee rehabilitation.
tone supportive, direct or neutral.
terminology Up to 20 terms your product uses, for example session instead of workout.
enabled_capabilities What Kinellect may do (see the table below).
safety_policy Currently always fitness_coach_safety_v1.
action_policy Whether Kinellect may execute actions (see Action policy).
connector_registration_ref The registration you received during onboarding.
workout_generation_policy Structural limits for generated workouts. Required when workout.generate is enabled.
daily_decision_policy Rules for daily plans. Required exactly when daily.decide is enabled.
operation_admission_policies Request-rate and concurrency limits per capability.
operation_usage_policies Token and estimated-cost ceilings per capability.

Capabilities

Capabilities switch features on. Some need your connector, and those must also appear in your connector's capabilities response or activation fails.

Capability What it enables Needs your connector
conversation.respond Coaching conversations. No
context.resolve Kinellect may pull a user's context from you when none is current. Yes
exercise.search Search your exercise catalog. Yes
exercise.resolve Look up exercises by reference and verify them. Yes
workout.search Find existing workouts in your catalog. Yes
workout.resolve Load and verify an existing workout. Yes
workout.prescription.count Repetition-based prescriptions (for example 3 sets of 10). Yes
workout.prescription.time Time-based prescriptions (for example 3 sets of 30 seconds). Yes
workout.generate Generate workout drafts. No, but requires the bundle below
workout.warmup.generate Add warm-up sections to generated workouts. No, requires workout.generate
workout.cooldown.generate Add cool-down sections to generated workouts. No, requires workout.generate
daily.decide Daily plans: workout, rest or mobility. Depends on the daily policy
workout.save Save an accepted workout to the user's library. Yes
workout.save_and_schedule Save and schedule an accepted workout atomically. Yes
preference.propose The coach may propose a preference change. No
preference.update The coach may update a preference in your system. Yes
memory.preference.write The coach may remember a preference the user stated explicitly. No

Activation rejects incomplete combinations with 422:

  • Existing workouts: workout.search or workout.resolve requires workout.search, workout.resolve, exercise.resolve and at least one prescription type.
  • Generated workouts: workout.generate requires exercise.search, exercise.resolve, at least one prescription type and a workout_generation_policy. The policy's maximum_total_count_repetitions must be set exactly when count prescriptions are enabled, and maximum_total_timed_work_seconds exactly when time prescriptions are enabled.
  • Warm-up and cool-down sections require workout.generate.

Action policy

action_policy controls whether Kinellect may carry out actions on your side, such as updating a preference or saving a workout:

Value Behaviour
auto_execute Actions run when requested. Workout acceptance still needs your explicit acceptance request.
confirmation_required Actions run only with explicit user approval, for example approval: "explicit_user_approval" on a workout acceptance.
professional_review_required Kinellect does not execute actions. Use this when a professional must review first.
proposal_only Kinellect may propose but never executes.
rejected No actions.

Subjects

A Subject is one of your users as Kinellect sees them. Kinellect knows only the opaque external_subject_ref you chose and the subject_ref UUID it assigned. You create a Subject implicitly with your first POST /v1/threads for that external_subject_ref.

Deleting and reactivating a Subject

Call DELETE /v1/subjects/{subject_ref} with an Idempotency-Key when a user leaves your product. It needs the context:write scope and returns 200. Deleting:

  • places a tombstone on the Subject, which blocks accidental re-registration;
  • cancels the Subject's queued and running Operations;
  • erases the Subject's coaching data in the same request: conversations, coach memory, context, workout drafts, daily plans, workout acceptances and completions, and Operations with their results. Only the minimal tombstone and the records needed to answer retried delete requests remain;
  • makes every new request about that Subject fail with 409 and detail subject_deleted. This includes new Threads for the same external_subject_ref, Turns, context updates, workout requests and completion events. Check detail rather than the status alone, because other conflicts also return 409.

Deleting an already deleted Subject also returns 200. Retrying with the same Idempotency-Key returns the original outcome. After deletion, polling one of the Subject's Operations returns 404, and retrying any earlier request for that Subject returns 409 subject_deleted.

To bring a returning user back, call POST /v1/subjects/{subject_ref}/reactivate with an Idempotency-Key. It also needs context:write and returns 200. Reactivating a Subject that is not deleted returns 422.

Erased data can remain in Kinellect's encrypted database backups until those backups expire. The backup retention period will be confirmed when the production environment is provisioned. Reactivating a Subject does not restore erased data.

Subject context

Subject context is your authoritative description of a user at a point in time: goal, experience level, available days, equipment, safety constraints, recovery and, optionally, recent activity for daily plans. Each version is immutable and has a validity window:

  • a version is current while effective_at <= now < valid_through;
  • versions for one Subject must increase, and later versions must not move backwards in time;
  • when no version is current, Kinellect asks your connector (context/resolve) if context.resolve is enabled. Otherwise, work that needs context fails with subject_context_unavailable.

Keep valid_through realistic. A window that is too long lets Kinellect coach from stale facts. A window that is too short causes avoidable connector calls or failures.

Safety constraints are free-text identifiers (for example avoid-overhead-loading) matched against the safety_identifiers your connector returns for each exercise. Exercise constraints are typed: a hard_exclusion never appears in a proposal, a soft_avoidance is avoided when an alternative exists, and a lifted constraint no longer applies.

Conversation Threads and Turns

A Thread is one conversation with one Subject. Mark a user's primary conversation with main: true. You send a user message as a Turn. Kinellect answers asynchronously, and the answer arrives as the result of an Operation.

Operations

Every request that involves a model or your connector creates a durable Operation. The request returns 202 Accepted at once with an operation_ref. You poll the Operation until it reaches a terminal state.

stateDiagram-v2
  [*] --> queued
  queued --> running: a worker claims it
  queued --> cancelled: deadline passed before it ran
  running --> completed: result stored
  running --> failed: safe failure (error_code)
  completed --> expired: retention period ended
  failed --> expired
  cancelled --> expired
State Meaning What to do
queued Accepted and waiting for a worker. Keep polling.
running A worker is processing it. Keep polling.
completed Finished. result holds the outcome. Use the result.
failed Finished without a result. error_code says why. Show a safe message. Some endpoints also return fallback_text.
cancelled Stopped before it produced a result. Treat as failed.
expired The Operation outlived its retention period, so the result is gone. Do not rely on old Operations; store what you need when it completes.

Terminal results never change. Polling a completed Operation again returns the same document.

Admission and usage limits

Each capability can carry two kinds of limit, set in the client configuration:

  • Admission policies (operation_admission_policies) limit how many Operations of a capability start within a rolling window (request_window_seconds, request maximums) and how many run at once (active maximums). A soft maximum is recorded for monitoring. A hard maximum rejects new requests with 429 when hard_enforcement_enabled is true.
  • Usage policies (operation_usage_policies) cap estimated tokens and cost, per Operation and per UTC day. Kinellect reserves the worst-case usage before each model call. When a hard ceiling would be exceeded, Kinellect makes no model call and the Operation ends in a failed state. The exact error_code depends on the capability.

With hard_enforcement_enabled: false a policy only observes. A capability without a usage policy is observed but never capped. Ask the Kinellect team for recommended starting values.

API conventions

These rules apply to every endpoint of the Kinellect API.

Base URL and versioning

All paths start with /v1. The base URL for your environment is issued during onboarding. The v1 contract changes only in backward-compatible ways, such as new optional fields or new endpoints. A breaking change would ship as a new major version with a new path prefix.

Because requests reject unknown fields (see below), a new optional request field is something you opt into. Build response parsing to ignore fields you do not recognise, so that new response fields never break you.

Authentication and scopes

Send your API token on every request:

Authorization: Bearer <your API token>

A missing or invalid token returns 401. A valid token without the required scope returns 403.

Scope Endpoints
configuration:write PUT /v1/client-configurations/{configuration_version}/activate
context:write PUT /v1/subjects/{subject_ref}/context/{context_version}, DELETE /v1/subjects/{subject_ref}, POST /v1/subjects/{subject_ref}/reactivate
conversation:write POST /v1/threads, POST /v1/threads/{thread_ref}/turns
conversation:read GET /v1/operations/{operation_ref}
workout:write POST /v1/workout-drafts, POST /v1/workout-acceptances, POST /v1/events
workout:read GET /v1/subjects/{subject_ref}/workout-draft-operations/{operation_ref}, .../workout-acceptance-operations/{operation_ref}, .../workout-completion-operations/{operation_ref}
coaching:write POST /v1/daily-plans
coaching:read GET /v1/subjects/{subject_ref}/daily-plan-operations/{operation_ref}

Call Kinellect only from your backend. Never ship the API token to a browser or mobile app.

Requests and responses

  • Bodies are JSON (Content-Type: application/json) with snake_case field names.
  • Unknown fields are rejected with 422. Send only documented fields.
  • String limits are UTF-8 byte lengths, not character counts. A 200-byte limit fits fewer than 200 characters of non-Latin text. NUL characters are never allowed.
  • References issued by Kinellect (subject_ref, thread_ref, operation_ref and so on) are UUIDs. Treat them as opaque strings.

Idempotency

Every POST and PUT requires an Idempotency-Key header of 1 to 200 characters. A missing key returns 400.

  • Generate a new key, such as a UUID, for each distinct request.
  • Reuse the same key only to retry that exact request, for example after a timeout.
  • Same key, same request: Kinellect returns the original result and creates nothing new. Configuration activation and context writes answer 201 when new and 200 with "replayed": true on replay. Thread creation answers 201 either way. Endpoints that start an Operation answer 202 with the original Operation.
  • Same key, different request: 409 Conflict. The original is never overwritten.

Persist the key with your outgoing request before sending it, so a retry after a crash reuses it.

Asynchronous Operations

Endpoints that involve a model or your connector return 202 Accepted with an Operation document. Subject-scoped endpoints also return a Location header pointing at the Operation to poll.

Created by Poll with
POST /v1/threads/{thread_ref}/turns GET /v1/operations/{operation_ref}
POST /v1/workout-drafts GET /v1/subjects/{subject_ref}/workout-draft-operations/{operation_ref}
POST /v1/daily-plans GET /v1/subjects/{subject_ref}/daily-plan-operations/{operation_ref}
POST /v1/workout-acceptances GET /v1/subjects/{subject_ref}/workout-acceptance-operations/{operation_ref}
POST /v1/events GET /v1/subjects/{subject_ref}/workout-completion-operations/{operation_ref}

Poll with backoff: start after about 1 second, increase the delay, cap it at a few seconds, and stop at a terminal state (completed, failed, cancelled or expired). Poll responses carry Cache-Control: no-store. Polling is read-only and never re-runs work.

Some endpoints refuse to start work while related work is still active. For example, a Thread accepts a new Turn only after its previous Turn has finished. Turns, workout drafts and daily plans answer 409 in that situation. Wait for the active Operation to finish, then send a new request with a new key.

Errors

Error bodies use RFC 9457 Problem Details (application/problem+json):

{
  "type": "about:blank",
  "title": "Too Many Requests",
  "status": 429,
  "detail": "operation_request_limit_exceeded"
}
Status Meaning What to do
400 Missing or invalid Idempotency-Key. Fix the request.
401 Missing or invalid API token. Check the token. Do not retry blindly.
403 The token lacks the required scope. Request the scope from Kinellect.
404 Unknown reference, or one that belongs to another tenant. The two cases are indistinguishable by design. Check the reference.
409 The user (Subject) was deleted, when detail is subject_deleted. Otherwise an idempotency conflict, version conflict, or an Operation already active. For subject_deleted, stop sending requests for this user, or reactivate the user first. Otherwise do not retry with the same key; resolve the conflict.
422 Invalid or unknown field, value out of range, or a configuration or policy that does not allow the request. Fix the request.
429 An admission limit was reached. detail is operation_request_limit_exceeded or operation_concurrency_limit_exceeded. Wait Retry-After seconds (1 to 300), then retry with the same Idempotency-Key.
503 A dependency was unavailable. For example, your connector did not answer during configuration activation. Retry later with the same key.

Failures that happen after 202 never become HTTP errors. The Operation ends in failed with a machine-readable error_code, documented per capability in the reference.

Time and dates

  • Timestamps are ISO 8601 / RFC 3339. Send UTC (Z), and expect UTC back.
  • local_date is a calendar date (YYYY-MM-DD) in the user's time zone. Impossible dates are rejected.
  • time_zone is an IANA name such as Europe/Oslo or UTC. Numeric offsets and abbreviations like CET are rejected.

Quickstart

This walkthrough activates a configuration, registers one user, stores their context, sends a message and reads the coach's reply. It assumes you finished onboarding steps 1 to 3 and have these values:

export KINELLECT_BASE_URL="https://api.kinellect.com"
export KINELLECT_TOKEN="<your API token>"                      # needs configuration:write, context:write, conversation:write, conversation:read
export CONNECTOR_REGISTRATION_REF="<connector registration UUID>"

Every write below uses uuidgen for a fresh Idempotency-Key. In your code, generate the key once per logical request and keep it for retries.

1. Activate configuration version 1

Save this as activate.json. It enables conversation, context resolution, exercise lookups and repetition-based workout generation. It also sets a request-rate limit and a daily usage ceiling for conversations.

{
  "client_description": "Northwind Physio runs outpatient physiotherapy clinics and a home-exercise app for its patients.",
  "product_description": "Patients follow home exercise programmes prescribed by their physiotherapist and log each session in the app.",
  "coaching_domain": "musculoskeletal rehabilitation",
  "tone": "supportive",
  "terminology": ["session", "programme"],
  "enabled_capabilities": [
    "conversation.respond",
    "context.resolve",
    "exercise.search",
    "exercise.resolve",
    "workout.prescription.count",
    "workout.generate",
    "memory.preference.write"
  ],
  "safety_policy": "fitness_coach_safety_v1",
  "action_policy": "confirmation_required",
  "connector_registration_ref": "3b7e1c52-9a0d-4e1f-8b6a-2f4c9d1e7a30",
  "workout_generation_policy": {
    "maximum_supersets": 4,
    "maximum_exercises_per_superset": 3,
    "maximum_total_exercises": 8,
    "minimum_rest_before_seconds": 0,
    "maximum_rest_before_seconds": 120,
    "minimum_rest_between_cycles_seconds": 30,
    "maximum_rest_between_cycles_seconds": 180,
    "maximum_total_sets": 24,
    "maximum_total_count_repetitions": 300,
    "maximum_total_timed_work_seconds": null,
    "minimum_estimated_duration_seconds": 600,
    "maximum_estimated_duration_seconds": 2700
  },
  "daily_decision_policy": null,
  "operation_admission_policies": [
    {
      "policy_version": 1,
      "capability": "conversation.respond",
      "request_window_seconds": 60,
      "soft_request_maximum": 20,
      "hard_request_maximum": 30,
      "soft_active_maximum": 5,
      "hard_active_maximum": 10,
      "hard_enforcement_enabled": true
    }
  ],
  "operation_usage_policies": [
    {
      "policy_version": 1,
      "capability": "conversation.respond",
      "operation_token_maximum": 60000,
      "operation_estimated_cost_microunits_maximum": 150000,
      "daily_token_maximum": 5000000,
      "daily_estimated_cost_microunits_maximum": 15000000,
      "hard_enforcement_enabled": true
    }
  ]
}

Replace connector_registration_ref with your own value, then send it:

curl -sS -X PUT "$KINELLECT_BASE_URL/v1/client-configurations/1/activate" \
  -H "Authorization: Bearer $KINELLECT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data @activate.json

201 Created:

{
  "configuration_ref": "f0a1b2c3-d4e5-4f60-8172-8394a5b6c7d8",
  "configuration_version": 1,
  "enabled_capabilities": [
    "conversation.respond",
    "context.resolve",
    "exercise.search",
    "exercise.resolve",
    "workout.prescription.count",
    "workout.generate",
    "memory.preference.write"
  ],
  "action_policy": "confirmation_required",
  "activated_at": "2026-09-25T09:00:00Z",
  "replayed": false
}

The usage ceilings above are illustrative. Estimated cost is in microunits (millionths of the price currency), so 15000000 means 15.00. Agree real values with the Kinellect team.

2. Register a user by creating their main Thread

curl -sS -X POST "$KINELLECT_BASE_URL/v1/threads" \
  -H "Authorization: Bearer $KINELLECT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data '{"external_subject_ref": "patient-8841", "main": true}'

201 Created. Store subject_ref against your user patient-8841:

{
  "thread_ref": "0d9c8b7a-6f5e-4d3c-9b2a-1f0e9d8c7b6a",
  "subject_ref": "7c1f2a4e-2b8d-4f3a-9a51-0d6e4b3c2a10",
  "main": true,
  "created_at": "2026-09-25T09:01:00Z"
}

3. Store the user's context (version 1)

Save as context.json:

{
  "effective_at": "2026-09-25T00:00:00Z",
  "valid_through": "2026-10-02T00:00:00Z",
  "time_zone": "Europe/Oslo",
  "local_date": "2026-09-25",
  "primary_goal": "Return to pain-free running after a left knee injury",
  "experience": "beginner",
  "desired_sessions_per_week": 3,
  "available_days": ["monday", "wednesday", "friday"],
  "unit_system": "metric",
  "equipment_refs": ["resistance-band", "step"],
  "safety_constraints": ["avoid-deep-knee-flexion"],
  "exercise_constraints": [
    {
      "constraint_ref": "pt-note-2026-09-20",
      "target": {"type": "exercise_ref", "value": "jump-squat"},
      "effect": "hard_exclusion",
      "state": "active"
    }
  ],
  "completed_workouts": 6,
  "mobility_summary": "Knee flexion limited to about 100 degrees",
  "recovery_summary": "Mild swelling after long walks, otherwise recovering well",
  "blocker": null
}
SUBJECT_REF="7c1f2a4e-2b8d-4f3a-9a51-0d6e4b3c2a10"
curl -sS -X PUT "$KINELLECT_BASE_URL/v1/subjects/$SUBJECT_REF/context/1" \
  -H "Authorization: Bearer $KINELLECT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data @context.json

201 Created:

{
  "subject_ref": "7c1f2a4e-2b8d-4f3a-9a51-0d6e4b3c2a10",
  "context_ref": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "context_version": 1,
  "effective_at": "2026-09-25T00:00:00Z",
  "created_at": "2026-09-25T09:02:00Z",
  "replayed": false
}

4. Send a message

THREAD_REF="0d9c8b7a-6f5e-4d3c-9b2a-1f0e9d8c7b6a"
curl -sS -X POST "$KINELLECT_BASE_URL/v1/threads/$THREAD_REF/turns" \
  -H "Authorization: Bearer $KINELLECT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data '{"message": "My knee felt stiff after yesterday. Should I still do my session today?"}'

202 Accepted with a queued Operation:

{
  "operation_ref": "e4d3c2b1-a09f-4e8d-9c7b-6a5f4e3d2c1b",
  "state": "queued",
  "result": null,
  "error_code": null,
  "error_message": null,
  "fallback_text": null,
  "created_at": "2026-09-25T09:03:00Z",
  "finished_at": null,
  "action_receipts": []
}

5. Poll for the reply

OPERATION_REF="e4d3c2b1-a09f-4e8d-9c7b-6a5f4e3d2c1b"
curl -sS "$KINELLECT_BASE_URL/v1/operations/$OPERATION_REF" \
  -H "Authorization: Bearer $KINELLECT_TOKEN"

Repeat with backoff until state is terminal. A completed Operation carries the coach's Turn in result:

{
  "operation_ref": "e4d3c2b1-a09f-4e8d-9c7b-6a5f4e3d2c1b",
  "state": "completed",
  "result": {
    "turn_ref": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "sequence": 2,
    "role": "assistant",
    "message": "Some stiffness the day after is common while the knee is recovering. ...",
    "created_at": "2026-09-25T09:03:07Z",
    "assistant_schema_version": "conversation_grounding_v1"
  },
  "error_code": null,
  "error_message": null,
  "fallback_text": null,
  "created_at": "2026-09-25T09:03:00Z",
  "finished_at": "2026-09-25T09:03:07Z",
  "action_receipts": []
}

Show result.message to the user. If the Operation failed, show fallback_text when present, otherwise your own safe message.

Next steps

Conversation

Requires conversation.respond. A conversation is a Thread of Turns between one user and the coach.

Flow

  1. POST /v1/threads with external_subject_ref (and main: true for the user's primary conversation). This also registers the user the first time.
  2. POST /v1/threads/{thread_ref}/turns with the user's message (up to 16000 bytes). You receive 202 and an Operation.
  3. Poll GET /v1/operations/{operation_ref} until the state is terminal.
  4. Show result.message from a completed Operation.

A Thread processes one Turn at a time. Sending another Turn while the previous one is still running returns 409.

What the coach uses

For each Turn the coach uses your current configuration, the user's current context (resolved through your connector when none is current), the user's remembered coaching preferences, recent Turns in the Thread, and only the capabilities you enabled. With exercise.search and exercise.resolve it can look up exercises in your catalog. It cannot reach anything else: no arbitrary web access, no database access, no other users.

Action receipts

When the coach takes or proposes an action during a Turn, the Operation lists it in action_receipts:

tool Meaning
propose_preference_update The coach suggested a preference change for the user to confirm.
update_preferences The coach asked your connector to update a preference (preference.update).
remember_explicit_preference The coach remembered a preference the user stated explicitly (memory.preference.write).

Each receipt has an outcome (succeeded, failed, proposed or unconfirmed), a safe_code, and an outcome_text that you may show to the user. The text is written by Kinellect code, never by the model, so it only claims what actually happened. unconfirmed means the result is uncertain: the action may or may not have taken effect on your side.

Remembered preferences are limited to four kinds: preferred_session_length, training_days, equipment_preference and coaching_tone.

Failures

A failed conversation Operation has one of these error_code values: provider_unavailable, provider_invalid_response, connector_unavailable, client_configuration_missing, subject_context_unavailable, execution_deadline_exceeded or execution_attempts_exhausted. error_message is a fixed safe sentence. When present, fallback_text is a safe reply you can show instead of a coach answer.

Workout drafts

Requires workout.generate and its bundle: exercise.search, exercise.resolve, at least one prescription type, and a workout_generation_policy. Add workout.warmup.generate and workout.cooldown.generate to get warm-up and cool-down sections.

A workout draft is a structured workout built only from exercises in your catalog and validated against the user's context, safety constraints and your generation policy. A draft is a proposal. Nothing reaches your system until the user accepts it (see Workout acceptance).

Request

curl -sS -X POST "$KINELLECT_BASE_URL/v1/workout-drafts" \
  -H "Authorization: Bearer $KINELLECT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data '{"subject_ref": "7c1f2a4e-2b8d-4f3a-9a51-0d6e4b3c2a10"}'

The body contains only subject_ref. Kinellect uses the current configuration and context and decides how to execute. You cannot choose a model or prompt. Poll the Location URL, GET /v1/subjects/{subject_ref}/workout-draft-operations/{operation_ref}.

Result

A completed Operation contains draft_ref and draft:

{
  "title": "Knee-friendly strength",
  "warmup_supersets": [],
  "supersets": [
    {
      "order": 1,
      "rest_between_cycles_seconds": 60,
      "workout_exercises": [
        {
          "exercise_ref": "glute-bridge",
          "exercise_content_version": "v3",
          "order": 1,
          "sets": 3,
          "rest_before_seconds": 0,
          "prescription": {"type": "count", "repetitions": 12}
        },
        {
          "exercise_ref": "banded-side-step",
          "exercise_content_version": "v2",
          "order": 2,
          "sets": 3,
          "rest_before_seconds": 30,
          "prescription": {"type": "count", "repetitions": 10}
        }
      ]
    }
  ],
  "cooldown_supersets": []
}

The Operation also reports catalog_version, the totals (total_sets, total_count_repetitions, total_timed_work_seconds, estimated_duration_seconds) and validation_codes. validated means the draft passed every check. Codes such as regression_substitution or constraint_conflict explain adjustments the validator made, for example swapping in an easier exercise to respect a constraint.

Every exercise carries the exercise_content_version your connector reported, so you can detect catalog changes before showing or saving the draft.

Failures

Failed drafts carry an error_code, for example subject_context_unavailable, exercise_catalog_unavailable, empty_candidate_set (no usable exercises for this user), draft_validation_failed or execution_deadline_exceeded. error_message is always the fixed sentence "The workout draft could not be completed safely." The API reference lists every code.

Daily plans

Requires daily.decide and a daily_decision_policy. A daily plan answers "what should this user do today?" with one of three outcomes: workout, rest or mobility. Rules decide the outcome deterministically from your policy and the user's context. A model is used only when the policy allows generating a new workout.

Policy

daily_decision_policy defines:

  • enabled_outcomes: any non-empty subset of workout, rest and mobility;
  • workout_source_policy (when workout is enabled): existing_only picks a workout from your catalog, generation_only generates one, and existing_preferred tries your catalog first and falls back to generation;
  • non_workout_preference: whether rest or mobility wins when both are possible;
  • rest_fallback_codes: when to fall back to rest (recovery_unavailable, workout_content_unavailable);
  • recovery_max_age_seconds and activity_max_age_seconds: how fresh recovery and activity data must be.

Conditional fields must be omitted when they do not apply. An explicit null is invalid. The workout source you pick needs its capability bundle: existing workouts need workout.search, workout.resolve, exercise.resolve and a prescription type, and generation needs the workout generation bundle.

Daily context

Daily plans need daily_context in the user's current Subject context:

{
  "week_start": "2026-09-21",
  "history_through": "2026-09-25T07:00:00Z",
  "completed_workout_dates": ["2026-09-22", "2026-09-24"],
  "completed_mobility_dates": ["2026-09-23"],
  "preferred_days": [1, 3, 5],
  "recovery_state": "ready",
  "recovery_observed_at": "2026-09-25T06:30:00Z",
  "recovery_valid_through": "2026-09-25T20:00:00Z"
}
  • week_start is the Monday of the week that contains local_date, in the user's time zone.
  • Completion lists cover the period from week_start minus 7 days through history_through. A date repeated twice means two sessions that day. Each list holds at most 28 entries.
  • preferred_days are ISO weekdays (1 = Monday) and must be a subset of available_days.
  • recovery_state is ready, mobility_only, rest_only or unknown.

Kinellect decides only when the context's local_date is today in the user's time zone and the activity and recovery data are fresh under your policy. Otherwise the plan fails, with codes such as local_date_changed, activity_history_unavailable or recovery_unavailable.

Request and result

curl -sS -X POST "$KINELLECT_BASE_URL/v1/daily-plans" \
  -H "Authorization: Bearer $KINELLECT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data '{"subject_ref": "7c1f2a4e-2b8d-4f3a-9a51-0d6e4b3c2a10"}'

Poll GET /v1/subjects/{subject_ref}/daily-plan-operations/{operation_ref}. A completed Operation's result is an immutable decision with:

  • outcome and machine-readable reason_codes (for example preferred_workout_day, weekly_target_met or recovery_rest_only);
  • reason_text, a safe explanation you can show;
  • existing_workout or generated_workout, when the outcome is workout;
  • the pinned configuration_version, context_version, local_date and time_zone.

Each poll also returns currentness: current, or why the decision no longer matches the user's situation (context_changed, local_date_changed, configuration_changed, activity_expired and others). The decision itself never changes. When it is no longer current, request a new plan.

Workout acceptance

Requires workout.save and/or workout.save_and_schedule, and your connector's actions/workouts/accept endpoint. Acceptance turns a proposed workout (a workout draft or a daily plan's workout) into a real workout in your system. It is always an explicit request from you, and Kinellect never infers approval.

Request

{
  "subject_ref": "7c1f2a4e-2b8d-4f3a-9a51-0d6e4b3c2a10",
  "selection": {
    "source_kind": "standalone_generated",
    "source_operation_ref": "22222222-2222-4222-8222-222222222222",
    "source_ref": "33333333-3333-4333-8333-333333333333",
    "action": "save_and_schedule",
    "local_date": "2026-09-26",
    "time_zone": "Europe/Oslo",
    "approval": "explicit_user_approval"
  }
}
  • source_kind is standalone_generated (a workout draft), daily_generated or daily_existing (a daily plan's workout). source_operation_ref and source_ref identify it. For a draft, send the draft Operation's operation_ref and its draft_ref. For a daily plan, send the daily-plan Operation's operation_ref and the decision's decision_ref.
  • action is save or save_and_schedule. For save_and_schedule, local_date and time_zone are required, and time_zone must equal the user's context. For save, send both as null.
  • approval: "explicit_user_approval" attests that the user approved this exact workout, action, date and time zone. Under confirmation_required it is mandatory. Under auto_execute it may be null. Under professional_review_required, proposal_only and rejected the action is never executed.

Send it to POST /v1/workout-acceptances and poll GET /v1/subjects/{subject_ref}/workout-acceptance-operations/{operation_ref}.

Result

A completed Operation holds exactly one business outcome:

result.status Meaning
confirmed Your connector saved (and scheduled) the workout. Includes your receipt_ref, workout_ref, workout_content_version, confirmed_at, and for scheduling your schedule_ref and schedule_content_version.
conflict Your connector refused because of a conflict, for example the date is already taken. Contains only a safe_code.
rejected Your connector refused for a business reason. Contains only a safe_code.

A failed Operation's error_code tells you why nothing was confirmed. source_noncurrent, approval_required and action_denied mean Kinellect never called your connector. connector_unconfirmed means Kinellect sent the command but never received a valid answer, so the workout may exist on your side. Check your own records for the command's action_ref before asking the user to accept again. Kinellect retries only within the original Operation, always with the same action_ref and Idempotency-Key, so an idempotent connector never creates duplicates (see Build your connector).

Acceptance never moves or cancels schedules.

Workout completion

Report completed workouts so the coach can react and learn. This endpoint only records a snapshot of your history and derives a reaction. It never changes your workout records.

Request

POST /v1/events with a workout.completed event (requires workout:write):

{
  "event_ref": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c",
  "event_type": "workout.completed",
  "schema_version": 1,
  "subject_ref": "7c1f2a4e-2b8d-4f3a-9a51-0d6e4b3c2a10",
  "activity_ref": "session-99102",
  "activity_revision": 1,
  "occurred_at": "2026-09-25T17:40:00Z",
  "workout_ref": "knee-programme-week-2",
  "duration_seconds": 1860,
  "exercise_results": [
    {
      "exercise_ref": "glute-bridge",
      "exercise_content_version": "v3",
      "status": "performed",
      "prescription_type": "count",
      "prescribed_value": 12,
      "completed_value": 12
    },
    {
      "exercise_ref": "banded-side-step",
      "exercise_content_version": "v2",
      "status": "skipped",
      "prescription_type": "count",
      "prescribed_value": 10,
      "completed_value": null
    }
  ],
  "feedback": {"rating": "tough", "note": "Side steps hurt a little on the outside of the knee"}
}
  • event_ref is a UUID you generate once per event.
  • activity_ref is your identifier for the session. To correct a session, send a new event with the same activity_ref and a higher activity_revision. Older revisions become superseded, and a stale revision is refused with 422.
  • feedback.rating is positive, neutral or tough. note is free text or null.

Result

Poll GET /v1/subjects/{subject_ref}/workout-completion-operations/{operation_ref}. For a completed, current Operation:

  • reaction is a short coach message you can show;
  • notification_suggested tells you whether the reaction is worth a push notification. You own notifications and decide whether to send one.

Superseded results never expose reaction or notification_suggested. A failed Operation reports model_failed, operation_cancelled or operation_expired.

Pain or difficulty reported in feedback can shape later coaching, for example by temporarily avoiding an exercise.

Build your connector

Your connector is an HTTPS service that Kinellect calls to read your content and a user's context, and to carry out actions on your side. The full contract is the Connector API specification in the reference. This page covers what matters most when building it.

Endpoints by capability

All paths are fixed and relative to the base URL you registered.

Endpoint Needed for
GET /ai-coach-connector/v1/capabilities Always. It is called when you activate a configuration.
POST /ai-coach-connector/v1/context/resolve context.resolve
POST /ai-coach-connector/v1/content/exercises/search exercise.search
POST /ai-coach-connector/v1/content/exercises/resolve exercise.resolve
POST /ai-coach-connector/v1/content/workouts/search workout.search
POST /ai-coach-connector/v1/content/workouts/resolve workout.resolve
POST /ai-coach-connector/v1/actions/preferences/update preference.update
POST /ai-coach-connector/v1/actions/workouts/accept workout.save, workout.save_and_schedule

The two prescription capabilities, workout.prescription.count and workout.prescription.time, have no endpoint of their own. Advertise them in capabilities when your catalog supports repetition-based or time-based prescriptions.

Every request

Kinellect sends:

Authorization: Bearer <your connector secret>
Accept: application/json
Accept-Encoding: identity
Content-Type: application/json
X-Kinellect-Tenant: <your tenant environment UUID>
Idempotency-Key: <key>            # action endpoints only

On every call, verify the bearer secret with a constant-time comparison, and check that X-Kinellect-Tenant is the tenant environment you expect.

subject_ref in request bodies is Kinellect's user reference (a UUID), not your user id. Look up your user through the mapping you stored when you created the user's first Thread.

Every response

Kinellect validates connector responses strictly, because they feed safety decisions:

  • Exact keys. Each object must contain exactly the documented keys: no more, no fewer. An extra field such as "debug": true makes the whole response invalid.
  • Optional means omit. Keys documented as optional (for example verification_facts, relationships, daily_context, warmup_supersets) are either present with a valid value or absent. Do not send null for them.
  • Status. Answer business outcomes with HTTP 200 and a JSON object. Any status outside 2xx counts as a failure.
  • Limits. String limits are UTF-8 bytes. Lists have maximum sizes. The body is at most 131072 bytes, uncompressed, with no NUL characters. Timestamps are UTC ending in Z or +00:00.
  • No redirects. Kinellect does not follow them.

A response that breaks these rules is treated as unavailable. The Operation that needed it fails safely, with codes such as connector_invalid_response, exercise_catalog_invalid or connector_unavailable, depending on the capability.

Timeouts and retries

  • Kinellect allows 2 seconds to connect and between bytes, and 5 seconds per attempt, always within the deadline of the Operation that needs the answer.
  • After HTTP 408, 429, 502, 503, 504 or a network error, Kinellect retries once, waiting 0.1 to 1 second. It honours a Retry-After header within that range. Other failures are not retried.
  • Capability discovery during activation has a 10-second budget. If it fails, activation returns 503.

Design every endpoint to answer well within 2 seconds, and keep them idempotent so that a retry is harmless.

Content endpoints

Exercises. Return at most 20 exercises per response. For each exercise you want Kinellect to use in generated or verified workouts, include verification_facts:

  • active and available: Kinellect uses only exercises that are both.
  • prescription_types: count, time or both.
  • safety_identifiers: identifiers that are matched against the user's safety_constraints and exercise constraints. Use the same vocabulary in both places.
  • generation_facts: allowed repetition and duration ranges. A range is either fully null or fully set, with 1 <= minimum <= maximum.

Add relationships with progression_refs, regression_refs and related_refs so Kinellect can substitute a safer regression when a constraint rules an exercise out.

Versions. content_version, catalog_version, item_content_version and exercise_content_version are your own version labels. Change them when content changes. Kinellect pins them in results, so you can tell whether a proposal still matches your catalog.

Workouts. workouts/resolve answers resolved with the full workout, or missing, inactive or changed with "workout": null. Superset and exercise order values start at 1 and have no gaps. Resolved supersets have no rest_between_cycles_seconds key.

Action endpoints

Action endpoints change data on your side, so they must be idempotent:

  • Store the Idempotency-Key together with your result.
  • The same key with the same command returns the stored result without acting again.
  • The same key with a different command is a conflict. For workout acceptance, answer with a conflict outcome whose safe_code is command_conflict, and never overwrite the original.

Preference update. Apply the change and return succeeded: true with your receipt_ref. If you decline, return succeeded: false with a safe_code and HTTP 200.

Workout acceptance. Kinellect sends an immutable command containing the complete workout (for a generated workout) or your existing_workout_ref, the action, and for scheduling the local_date and time_zone. save_and_schedule must be atomic: when the date conflicts, create neither the workout nor the schedule, and answer conflict with safe_code schedule_conflict. Answer confirmed, conflict or rejected with HTTP 200. The accept operation in the Connector API reference defines the exact command and outcome shapes.

Testing your connector

  • Validate each response against the Connector API schemas, with additionalProperties: false enforced.
  • Test the empty cases: an unknown user in context/resolve returns {"available": false}, unknown exercise references are simply left out, and an unknown workout returns missing.
  • Replay each action with the same Idempotency-Key and confirm nothing is applied twice.
  • Measure latency under load. Keep p99 well below 2 seconds.

Using these docs with an LLM

These docs are published in forms that coding assistants and agents can read directly:

File Contents Use it when
llms.txt A short index of every document, following the llms.txt convention. An agent should discover what exists.
llms-full.txt Every guide on this page plus both complete OpenAPI specifications, in one Markdown file. You want to give an assistant the whole contract in one go.
openapi/kinellect-api-v1.json OpenAPI 3.1 for the Kinellect API you call. Generating a client, or validating requests.
openapi/kinellect-connector-v1.json OpenAPI 3.1 for the connector you implement. Generating server stubs, or validating responses.

Paste llms-full.txt into your assistant's context, or point an agent at it. It is self-contained.

Suggested instructions for a coding assistant

You are implementing an integration with Kinellect. The attached llms-full.txt is the complete contract.
Rules:
- Never invent endpoints, fields, enum values or status codes. Use only what the OpenAPI specs define.
- Kinellect API requests reject unknown fields. Send only documented fields.
- Every POST/PUT needs an Idempotency-Key. Reuse the key only to retry the identical request.
- 202 responses start an Operation. Poll it with backoff until queued/running ends.
- Handle 429 by waiting Retry-After, then retrying with the same Idempotency-Key.
- Connector responses must contain exactly the documented keys. Optional keys are omitted, never null.
- subject_ref is Kinellect's UUID for a user. Keep a mapping from our user id to subject_ref.
- The Kinellect API token is a backend secret. Never put it in client-side code.

Invariants checklist

Use this list to review generated code:

  1. Each write sends an Idempotency-Key that is persisted before the request and reused on retry.
  2. No request body contains a field that is missing from the specification.
  3. Every Operation state is handled: queued, running, completed, failed, cancelled and expired.
  4. Byte limits are checked in UTF-8 bytes, not characters.
  5. Timestamps are sent as UTC. time_zone is an IANA name.
  6. Connector responses are built from explicit field lists, never by serialising internal objects that may carry extra fields.
  7. Connector action endpoints store and replay results by Idempotency-Key.
  8. The connector verifies the bearer secret and the X-Kinellect-Tenant header.

Limits of v1

Plan your integration around these current limits. Ask the Kinellect team about timelines.

  • No self-service provisioning. API tokens, scopes and connector registrations are issued by the Kinellect team.
  • No webhooks. Results are delivered by polling Operations.
  • Registering a user means creating a Thread. There is no separate "create subject" endpoint. POST /v1/threads both creates the conversation and registers the user.
  • Backups keep erased data until they expire. DELETE /v1/subjects/{subject_ref} erases the user's coaching data immediately (see Deleting and reactivating a Subject), but encrypted backups keep it until they expire. The retention period is confirmed at production provisioning.
  • No listing endpoints. The API does not list users, Threads or past Operations. Store the references you need when you receive them.
  • One safety policy. safety_policy currently accepts only fitness_coach_safety_v1.
  • English. Coaching output is currently English.

Endpoint index

Kinellect API (you call)

MethodPathPurpose
DELETE/v1/subjects/{subject_ref}Delete or replay deletion of one Subject
POST/v1/subjects/{subject_ref}/reactivateReactivate or replay reactivation of one deleted Subject
PUT/v1/client-configurations/{configuration_version}/activateActivate or replay one immutable tenant coaching configuration version
PUT/v1/subjects/{subject_ref}/context/{context_version}Store or replay one immutable authoritative subject-context version
POST/v1/threadsCreate or replay a tenant-scoped Conversation Thread
POST/v1/threads/{thread_ref}/turnsAccept one immutable user Turn
GET/v1/operations/{operation_ref}Poll a Conversation Operation
POST/v1/workout-draftsRequest or replay one validated workout draft
GET/v1/subjects/{subject_ref}/workout-draft-operations/{operation_ref}Poll a subject-scoped workout-generation Operation
POST/v1/daily-plansRequest or replay one daily coaching decision
GET/v1/subjects/{subject_ref}/daily-plan-operations/{operation_ref}Poll a subject-scoped daily-coaching Operation
POST/v1/workout-acceptancesRequest or replay explicit workout acceptance
GET/v1/subjects/{subject_ref}/workout-acceptance-operations/{operation_ref}Poll a subject-scoped workout acceptance Operation
POST/v1/eventsReport one completed workout
GET/v1/subjects/{subject_ref}/workout-completion-operations/{operation_ref}Poll a subject-scoped workout-completion Operation

Connector API (you implement)

MethodPathPurpose
GET/ai-coach-connector/v1/capabilitiesDeclare the connector contract version and supported capabilities
POST/ai-coach-connector/v1/context/resolveReturn the Subject's current authoritative context
POST/ai-coach-connector/v1/content/exercises/searchSearch the exercise catalog for one Subject
POST/ai-coach-connector/v1/content/exercises/resolveResolve exercises by reference
POST/ai-coach-connector/v1/content/workouts/searchSearch existing workouts
POST/ai-coach-connector/v1/content/workouts/resolveResolve one existing workout
POST/ai-coach-connector/v1/actions/preferences/updateUpdate one Subject preference
POST/ai-coach-connector/v1/actions/workouts/acceptAccept the immutable workout command

Full request and response schemas, limits and error codes are in the API reference.