> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ochy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Exercises

> Search exercise content by lookup keys aligned with analysis search_key values.

Use **`POST /exercises`** to retrieve recommended **exercises** from Ochy's catalog. Each exercise is matched when its **`lookup_keys`** contain at least one of the strings you pass in **`search_keys`**.

The values you send in **`search_keys`** are the same stable identifiers as **`search_key`** in analysis results (`texts.search_key`). See the full catalog of keys and meanings in **[Search key mapping](/guides/search-key-mapping)**.

<Tip>
  Map analysis items by **`search_key`**, then call this endpoint with those keys to fetch titles, media, difficulty, series, and duration or repetition ranges—without relying on localized labels from the analysis response.
</Tip>

## Authentication

Same as the rest of the Partner API: pass your **`apiKey`** as a **query parameter** on every request. See [Authentication](/authentication).

## Request

| Item   | Value                   |
| ------ | ----------------------- |
| Method | `POST`                  |
| Path   | `/exercises`            |
| Query  | `apiKey` (required)     |
| Body   | JSON `application/json` |

### Body schema

| Field         | Type       | Description                                                                                        |
| ------------- | ---------- | -------------------------------------------------------------------------------------------------- |
| `search_keys` | `string[]` | At least one lookup key (e.g. values from [Search key mapping](/guides/search-key-mapping)).       |
| `language`    | `string`   | Locale for the exercise `title` (e.g. `en`, `fr`). Falls back to English if the locale is missing. |

### Example body

```json theme={null}
{
  "language": "en",
  "search_keys": [
    "HeadG",
    "PelvicB"
  ]
}
```

## Response

* **200 OK** — JSON **array** of exercise objects. Each object includes **`id`** (UUID), **`lookup_keys`**, and a localized **`title`**.
* **`lookup_keys`** lists the stable identifiers used to match this exercise (same values as **`search_keys`** in the request and **`search_key`** in analysis results).
* **`media`** may include `image`, `video`, and optionally **`video_portrait`**.

### Example response (200)

```json theme={null}
[
  {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "lookup_keys": ["PelvicB", "HeadG"],
    "difficulty": "easy",
    "effort_per_rep": {
      "max_ms": 15000,
      "min_ms": 10000
    },
    "exercise_format": "duration",
    "kind": "exercise",
    "media": {
      "image": "https://firebasestorage.googleapis.com/v0/b/ochy-7871a.appspot.com/o/assets%2Fexercises%2Fbackview%2Fthumbnails%2FWall%20Assist%20Stork%20Balance.png?alt=media",
      "video": "https://firebasestorage.googleapis.com/v0/b/ochy-7871a.appspot.com/o/assets%2Fexercises%2Fbackview%2Fvideos%2FWall-Assisted-Stork-Balance.mp4?alt=media&token=1c016167-d868-429d-9afb-1d2af1373a1a"
    },
    "number_of_series": 4,
    "title": "Wall Assist Stork Balance"
  },
  {
    "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "lookup_keys": ["PelvicB"],
    "difficulty": "medium",
    "exercise_format": "repetitions",
    "kind": "exercise",
    "media": {
      "image": "https://firebasestorage.googleapis.com/v0/b/ochy-7871a.appspot.com/o/assets%2Fexercises%2Fbackview%2Fthumbnails%2FStep%20Up%20to%20Balance.png?alt=media&token=c6de01b3-f5f7-4fec-95f2-41f50283b718",
      "video": "https://firebasestorage.googleapis.com/v0/b/ochy-7871a.appspot.com/o/assets%2Fexercises%2Fbackview%2Fvideos%2FStep%20Up%20to%20Balance.mp4?alt=media&token=cb8972bf-c8b3-4fcb-89e9-b591c4b4cd5d"
    },
    "number_of_series": 4,
    "repetitions": {
      "max": 10,
      "min": 6
    },
    "title": "Step Up to Balance"
  }
]
```

A larger catalog match can return many items in one array; the shape is always the same.

## Errors

| HTTP | `code`               | When                                       |
| ---- | -------------------- | ------------------------------------------ |
| 400  | `invalid_body`       | Malformed JSON or missing required fields. |
| 400  | `language_required`  | `language` is empty.                       |
| 400  | `search_keys_empty`  | No usable values in `search_keys`.         |
| 404  | `no_exercises_found` | No exercises matched the given keys.       |

### Example — nothing matched (404)

```json theme={null}
{
  "code": "no_exercises_found",
  "detail": "No exercises found for the given search keys"
}
```

Other errors (e.g. invalid API key, internal failure) follow the same **`detail`** / **`code`** pattern as the rest of the Partner API.

## Example request (cURL)

```bash theme={null}
curl -sS -X POST 'https://partner-api.ochy-prod.com/exercises?apiKey=YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"language":"en","search_keys":["HeadG","PelvicB"]}'
```

Replace the base URL with your environment (e.g. staging) if needed.
