# Getting Started

Everything on this page applies to all six endpoints.

**Authentication**

Send one of the two credentials. If an `Authorization` header is present it wins and the API key is ignored.

| Header | Use when |
|--------|----------|
| `x-api-key: YOUR_API_KEY` | Server to server, or SDK calls made on behalf of your company |
| `Authorization: Bearer YOUR_JWT` | A signed-in end user (see [obtaining a JWT](/docs/trainer-api/trainer-api-auth)) |
| `x-user-id: END_USER_ID` | Optional, alongside `x-api-key`, to resolve a specific end user |

`x-user-id` only matters for plan progress: with it, `GET /api/plans/client/{id}` returns that user's completion flags. For pure catalog reads you can leave it out.

> Keep your company API key on your server. A client app should send a **user JWT** instead. These endpoints do not accept a raw session ID.

Two ways to get that JWT, both starting on your backend:

- Call [verify-api-key](/docs/trainer-api/trainer-api-auth) with your API key and the user's ID, then hand the returned `token` to the client.
- Mint a short-lived session with `POST /api/sessions`, ship the session ID to the client, and have the client exchange it for a JWT at `POST /api/auth/session-verify` with an `x-session-id` header. The `token` it returns expires with the session, so the client can never outlive it. Full request and response shapes are in [Session tokens](/docs/trainer-api/trainer-api-auth).

Either way the client then sends `Authorization: Bearer <token>` on these requests.

**Language**

One value controls the language of every title, description, tip, and step in the response. Resolution order, highest first:

1. `?lang=es` query parameter
2. `Language: es` header
3. `Accept-Language: es-MX,es;q=0.9` header (the first entry wins)
4. English

All sources are normalized to the ISO 639-1 base code, so `es`, `ES`, `es-MX`, and `pt_BR` resolve the way you expect in whichever form you send them. `en-GB` and `EN` both resolve to `en`.

Where `?lang=` is honored:

| Endpoint | `?lang=` | Missing translation falls back to English |
|----------|-----------|-------------------------------------------|
| `GET /api/exercises/client` | Yes | Yes |
| `GET /api/exercises/client/{id}` | Yes | Yes |
| `GET /api/workouts/client` | Yes | No, see below |
| `GET /api/workouts/client/{id}` | Yes | Yes |
| `GET /api/plans/client` | Yes | Yes |
| `GET /api/plans/client/{id}` | No, headers only | Yes |

Two exceptions worth coding around:

- **The single-plan endpoint ignores the lang parameter.** `GET /api/plans/client/{id}` reads the `Language` or `Accept-Language` header only.
- **The workout list does not fall back to English.** If you request `?lang=es` and a workout has no Spanish row, that workout's `translation` is `null` while `translation_languages` still lists what exists. Handle the null, narrow the list with `translation_languages=es`, or pass `include_exercises=true` (that path does fall back to English).

> **Recommended:** send the `Language` header on every request **and** `?lang=` on list requests. The header covers the endpoints that only read headers; the parameter makes the language explicit in the cache key and in your logs.

**Supported language codes**

Any ISO 639-1 code is accepted; what you get back is whatever translations exist. The platform languages KinesteX ships today are listed in [Language & Localization](/docs/customization-parameters/language-localization), and more can be added on request.

Coverage is **per item**, not global. Read `translation_languages` on a list item to see what that item actually has, or filter the list with `translation_languages=<code>` to return only items that have it. An unknown or untranslated code is never an error: you get English (or, on the workout list, a `null` `translation`).

**Media URLs**

Image, video, and audio URLs are returned as Firebase Storage download URLs (`https://firebasestorage.googleapis.com/v0/b/.../o/<path>?alt=media`). Treat them as opaque: fetch them as-is, and do not rebuild or parse the path. They are stable for the lifetime of the asset but the host and encoding are an implementation detail.

---
Source: https://www.kinestex.com/docs/content-api-v2/content-api-v2-getting-started · Index: https://www.kinestex.com/llms.txt
