Start a coaching period

POST/api/public/escorts

Start a new coaching period (escort) for a trainee. The plan ids required depend on escortType: "Training" needs trainingPlanId, "Nutrition" needs nutritionMenuId, "Nutrition and training" needs both, and "Other" needs neither. Create the plan or menu first (POST /training-plans, POST /nutrition-menus) and pass its id here. A trainee may only have one active escort at a time.

Authentication

Requires an API key, sent as Authorization: Bearer cp_live_....

API keys carry scopes. Get the catalog of scopes and webhook events lists every scope.

Header parameters

Header parameters
NameTypeDescription
Idempotency-Keystring

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

application/json, required

Request body fields
NameTypeDescription
traineeIdrequiredstring
escortTyperequiredstring

Determines which plan ids are required: Training -> trainingPlanId, Nutrition -> nutritionMenuId, Nutrition and training -> both, Other -> none.

Allowed values: Nutrition Training Nutrition and training Other

startDaterequiredstring

ISO date.

endDatestring

ISO date. Provide this or months.

monthsnumber

Duration in months. Provide this or endDate.

goalstring
pricenumber
paymentDatestring
paymentMethodstring

Allowed values: Cash Credit card Bank transfer Other

paymentNumbernumber
escortMeetingTypestring

Allowed values: Online In person

onlineEscortstring
inPersonEscortstring
notesstring

Optional first note on the coaching period.

cardioDaysnumber
cardioTimenumber
trainingDaysnumber
dailyStepsTargetnumber
trainingPlanIdstring

Assign an existing training plan. Required when escortType is "Training" or "Nutrition and training".

nutritionMenuIdstring

Assign an existing nutrition menu. Required when escortType is "Nutrition" or "Nutrition and training".

skipRegistrationFormsboolean

true: the trainee is not asked to fill registration forms in the app during this coaching period. false: the app asks the trainee to fill every active registration form aimed at them that they have not filled yet. Defaults to true when omitted on create. This is the same switch as the registration-forms toggle on the trainee profile. It belongs to this coaching period only, and a link to a specific form sent to the trainee keeps working either way.

Request examples

cURL
curl --request POST \
  --url 'https://api.coach-platform.com/api/public/escorts' \
  --header 'Authorization: Bearer cp_live_...' \
  --header 'Content-Type: application/json' \
  --data '{
  "traineeId": "<string>",
  "escortType": "Nutrition",
  "startDate": "<string>"
}'
JavaScript (fetch)
const response = await fetch('https://api.coach-platform.com/api/public/escorts', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer cp_live_...',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "traineeId": "<string>",
    "escortType": "Nutrition",
    "startDate": "<string>"
  }),
});

const data = await response.json();

Responses

201 Created

Example body (application/json)
{
  "data": {
    "id": "<string>",
    "coach": "<string>",
    "trainee": {
      "id": "<string>",
      "name": "<string>",
      "email": "<string>",
      "phoneNumber": "<string>"
    },
    "status": "pending",
    "escortType": "<string>",
    "startDate": "<date-time>",
    "endDate": "<date-time>",
    "months": 123,
    "isUnlimited": true,
    "training": {
      "activeTrainingPlan": {
        "id": "<string>",
        "title": "<string>",
        "level": "<string>"
      },
      "trainingDays": null
    },
    "nutrition": {
      "activeNutritionPlan": {
        "id": "<string>",
        "title": "<string>",
        "level": "<string>"
      }
    },
    "skipRegistrationForms": true,
    "createdAt": "<date-time>"
  },
  "warnings": [
    {
      "field": "<string>",
      "message": "<string>"
    }
  ]
}
Response fields (30)
Response fields
NameTypeDescription
dataobject
data.idstring
data.coachstring
data.traineeobject

The escorted trainee. email and phoneNumber are returned only when the key also has the trainees:read scope.

data.trainee.idstring
data.trainee.namestring
data.trainee.emailstring
data.trainee.phoneNumberstring
data.statusstring

Allowed values: pending active canceled completed suspended

data.escortTypestring
data.startDatestring<date-time>
data.endDatestring<date-time> | null

When the coaching period ends. null when the escort runs with no time limit, in which case isUnlimited is true.

data.monthsinteger | null

Duration in months. null when the escort runs with no time limit.

data.isUnlimitedboolean

True when the escort has no end date.

data.trainingobject
data.training.activeTrainingPlanobject | null
data.training.activeTrainingPlan.idstring
data.training.activeTrainingPlan.titlestring
data.training.activeTrainingPlan.levelstring
data.training.trainingDaysany
data.nutritionobject
data.nutrition.activeNutritionPlanobject | null
data.nutrition.activeNutritionPlan.idstring
data.nutrition.activeNutritionPlan.titlestring
data.nutrition.activeNutritionPlan.levelstring
data.skipRegistrationFormsboolean

true when the trainee is not asked to fill registration forms in the app during this coaching period. Change it with PATCH /escorts/{escortId}.

data.createdAtstring<date-time>
warningsobject[]

Non-fatal problems with follow-up writes. The resource was created, but each listed field was not applied.

warnings[].fieldstring
warnings[].messagestring

Error responses

  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not Found
  • 409 Conflict
  • 429 Too Many Requests
  • 500 Internal Server Error

These statuses share the same response body.

Example body (application/json)
{
  "error": {
    "code": "<string>",
    "message": "<string>",
    "fix": "<string>",
    "details": {},
    "retryAfterMs": 123
  }
}
Error fields (6)
Error fields
NameTypeDescription
errorobject
error.codestring
error.messagestring
error.fixstring | null
error.detailsobject | null
error.retryAfterMsnumber | null

This page is also available as Markdown. Browse it in the interactive explorer or download the OpenAPI spec.