# Create a trainee

`POST https://api.coach-platform.com/api/public/trainees`

Create a new trainee for the coach. Requires name, email, and phoneNumber.

- Resource: Trainees
- Authentication: API key in the `Authorization: Bearer cp_live_...` header
- HTML version: https://www.coach-platform.com/docs/api/reference/post-trainees
- OpenAPI spec: https://www.coach-platform.com/openapi.json

## Header parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `Idempotency-Key` | string | No | Optional. Send a unique key (e.g. a UUID) to make this POST safe to retry. The same key within 24h returns the original result instead of creating a duplicate. |

## Request body

Content type: `application/json`. Required.

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | Yes | Trainee full name |
| `email` | string | Yes | Trainee email |
| `phoneNumber` | string | Yes | Trainee phone number |
| `goal` | string | No | Optional coaching goal |
| `passwordAsPhoneNumber` | boolean | No | Set the trainee login password to their phone number instead of a random one. Israeli numbers are normalized to their local 0-prefixed form, so "+972501234567", "972-50-123-4567" and "050 123 4567" all become the password "0501234567", and the trainee can log in by typing any of those forms. Numbers from every other country are supported too and keep their international form, so "+1 415 555 2671" becomes "+14155552671"; a trainee with a non-Israeli number must include the country code when logging in, because the national form ("415-555-2671") cannot be mapped back. Send a clean number: any extra digits, such as an extension, become part of the password. The resulting password is always returned in the password field of this response and is not retrievable afterwards. Changing the phone number later with PATCH /trainees/{traineeId} does not change the password. Rejected with 400 only when phoneNumber has no digits at all, or fewer than 6 digits; error.details.reason says which. If the email belongs to an existing trainee account that is merely attached to the coach, that account keeps its current password and a warning is returned. |
| `labels` | string[] | No | Optional ids of existing labels to attach. Each item must be the label id (24-character MongoDB ObjectId) as returned in the id field of GET /labels — not the label text. Label text is not accepted here and no new label is created; to attach a label by text, or to create one, use POST /trainees/{traineeId}/labels instead. Requires the labels:write scope: without it the trainee is still created and a warning is returned in the warnings array. Maximum items: `100`. |
| `sendCredentials` | object | No | Deliver the new trainee their app access details as part of creating them, instead of calling POST /trainees/{traineeId}/send-credentials afterwards (which would reset the password again). Only applies to a newly created account: if the email belongs to an existing trainee that is merely attached to this coach, that account keeps its current password, nothing is sent, and a warning is returned. |
| `sendCredentials.email` | boolean | No | Email the trainee their app access details right after creation. |
| `sendCredentials.whatsapp` | boolean | No | Also send the access details over WhatsApp, followed by the password in a separate message. Requires a connected WhatsApp account and a phone number on the trainee. |
| `whatsappTemplate` | string | No | Optional message wording used when sendCredentials.whatsapp is true, with the {firstName}, {email}, {password} and {appLink} placeholders. When omitted, the template saved in the dashboard is used, then a built-in default. The password is always sent in a separate follow-up message, so the template normally does not need {password}. |

## Responses

| Status | Description |
|---|---|
| `201` Created |  |
| `400` Bad Request |  |
| `401` Unauthorized |  |
| `403` Forbidden |  |
| `404` Not Found |  |
| `409` Conflict |  |
| `429` Too Many Requests |  |
| `500` Internal Server Error |  |

### 201 Created

Content type: `application/json`

| Field | Type | Description |
|---|---|---|
| `data` | object |   |
| `data.id` | string |   |
| `data.name` | string |   |
| `data.email` | string |   |
| `data.phoneNumber` | string |   |
| `data.goal` | string |   |
| `data.profileImageUrl` | string |   |
| `data.personalDetails` | object |   |
| `data.labels` | object[] |   |
| `data.labels[].id` | string |   |
| `data.labels[].text` | string |   |
| `data.labels[].color` | string |   |
| `data.labels[].coachId` | string |   |
| `data.assignedEmployees` | object[] |   |
| `data.assignedEmployees[].id` | string |   |
| `data.assignedEmployees[].name` | string |   |
| `data.activeCoachDetails` | object |   |
| `data.activeCoachDetails.activeEscort` | string \| null | Id of the escort currently in use for this trainee. Fetch the full escort with GET /escorts/{escortId}. |
| `data.activeCoachDetails.pendingCoach` | string \| null | Coach id this trainee is pending approval for. Set when the trainee was invited but has not been approved yet; null once approved. Use ?status=pending on GET /trainees to list only these. |
| `data.activeCoachDetails.pendingCoachDate` | string<date-time> \| null | When the trainee entered the pending state. Use it to measure how long approval has been waiting. |
| `data.createdAt` | string<date-time> |   |
| `data.password` | string | Login password, returned only in this create response and never retrievable again. Randomly generated, or the normalized phone number when passwordAsPhoneNumber was sent as true. Present only when a brand-new trainee account was created; absent when an existing trainee was attached to the coach. Calling POST /trainees/{traineeId}/send-credentials resets it. |
| `data.credentialsSent` | object | Present only when sendCredentials was supplied. Reports which channels the access details were handed off to for delivery. A false value is always explained by an entry in warnings. WhatsApp delivery happens in the background and is spaced out to protect the account, so true means the message was queued, not that it has already arrived. |
| `data.credentialsSent.email` | boolean |   |
| `data.credentialsSent.whatsapp` | boolean |   |
| `warnings` | object[] | Non-fatal problems with follow-up writes. The resource was created, but each listed field was not applied. |
| `warnings[].field` | string |   |
| `warnings[].message` | string |   |

Example:

```json
{
  "data": {
    "id": "<string>",
    "name": "<string>",
    "email": "<string>",
    "phoneNumber": "<string>",
    "goal": "<string>",
    "profileImageUrl": "<string>",
    "personalDetails": {},
    "labels": [
      {
        "id": "<string>",
        "text": "<string>",
        "color": "<string>",
        "coachId": "<string>"
      }
    ],
    "assignedEmployees": [
      {
        "id": "<string>",
        "name": "<string>"
      }
    ],
    "activeCoachDetails": {
      "activeEscort": "<string>",
      "pendingCoach": "<string>",
      "pendingCoachDate": "<date-time>"
    },
    "createdAt": "<date-time>",
    "password": "<string>",
    "credentialsSent": {
      "email": true,
      "whatsapp": true
    }
  },
  "warnings": [
    {
      "field": "<string>",
      "message": "<string>"
    }
  ]
}
```

### Error responses 400, 401, 403, 404, 409, 429, 500

Content type: `application/json`

| Field | Type | Description |
|---|---|---|
| `error` | object |   |
| `error.code` | string |   |
| `error.message` | string |   |
| `error.fix` | string \| null |   |
| `error.details` | object \| null |   |
| `error.retryAfterMs` | number \| null |   |

Example:

```json
{
  "error": {
    "code": "<string>",
    "message": "<string>",
    "fix": "<string>",
    "details": {},
    "retryAfterMs": 123
  }
}
```

## Examples

### cURL

```bash
curl --request POST \
  --url 'https://api.coach-platform.com/api/public/trainees' \
  --header 'Authorization: Bearer cp_live_...' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "<string>",
  "email": "<string>",
  "phoneNumber": "<string>"
}'
```

### JavaScript (fetch)

```js
const response = await fetch('https://api.coach-platform.com/api/public/trainees', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer cp_live_...',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "<string>",
    "email": "<string>",
    "phoneNumber": "<string>"
  }),
});

const data = await response.json();
```

## Related endpoints

- [List trainees](https://www.coach-platform.com/docs/api/reference/get-trainees/index.md): `GET /api/public/trainees`. List trainees of the coach, filterable by label/search.
- [Approve or reject pending trainees](https://www.coach-platform.com/docs/api/reference/post-trainees-pending/index.md): `POST /api/public/trainees/pending`. Approve or reject trainees from the coach's approval queue, which GET /trainees?status=pending lists.
- [Get a trainee](https://www.coach-platform.com/docs/api/reference/get-trainees-trainee-id/index.md): `GET /api/public/trainees/{traineeId}`. Get a single trainee by id.
- [Update a trainee](https://www.coach-platform.com/docs/api/reference/patch-trainees-trainee-id/index.md): `PATCH /api/public/trainees/{traineeId}`. Update a trainee's personal details.
- [Remove a trainee](https://www.coach-platform.com/docs/api/reference/delete-trainees-trainee-id/index.md): `DELETE /api/public/trainees/{traineeId}`. Remove a trainee from the coach account.
- [Restore an archived trainee](https://www.coach-platform.com/docs/api/reference/post-trainees-trainee-id-restore/index.md): `POST /api/public/trainees/{traineeId}/restore`. Bring a trainee back from the archive, exactly as the dashboard does it.
- [Send access details to a trainee](https://www.coach-platform.com/docs/api/reference/post-trainees-trainee-id-send-credentials/index.md): `POST /api/public/trainees/{traineeId}/send-credentials`. Send the trainee their app access details by email, and optionally by WhatsApp.
- [Get a trainee's weekly activity](https://www.coach-platform.com/docs/api/reference/get-trainees-trainee-id-weekly-activity/index.md): `GET /api/public/trainees/{traineeId}/weekly-activity`. Day-by-day activity for the week containing the given date (workouts, cardio, nutrition logging, water, measurements, form submissions).
- [Get a trainee's body measurements](https://www.coach-platform.com/docs/api/reference/get-trainees-trainee-id-measurements/index.md): `GET /api/public/trainees/{traineeId}/measurements`. A trainee's body measurements: weight history, body-fat history, circumference history, and custom measurement types.
- [Record a weigh-in](https://www.coach-platform.com/docs/api/reference/post-trainees-trainee-id-body-metrics/index.md): `POST /api/public/trainees/{traineeId}/body-metrics`. Record a weigh-in for a trainee: weight, body fat, and/or body measurements.
- [List a trainee's progress photos](https://www.coach-platform.com/docs/api/reference/get-trainees-trainee-id-photos/index.md): `GET /api/public/trainees/{traineeId}/photos`. A trainee's progress photos as temporary viewable image URLs (valid a few minutes).
- [List a trainee's personal records](https://www.coach-platform.com/docs/api/reference/get-trainees-trainee-id-personal-records/index.md): `GET /api/public/trainees/{traineeId}/personal-records`. A trainee's personal records per exercise: best weight, estimated 1RM, top-set reps, max reps, set and total volume, and max duration, each with the value achieved, the previous record and when it was set.
- Previous: [List trainees](https://www.coach-platform.com/docs/api/reference/get-trainees/index.md): `GET /api/public/trainees`. List trainees of the coach, filterable by label/search.
- Next: [Approve or reject pending trainees](https://www.coach-platform.com/docs/api/reference/post-trainees-pending/index.md): `POST /api/public/trainees/pending`. Approve or reject trainees from the coach's approval queue, which GET /trainees?status=pending lists.
