Restore an archived trainee

POST/api/public/trainees/{traineeId}/restore

Bring a trainee back from the archive, exactly as the dashboard does it. Their last coaching period with you is revived (status Active when its end date is still ahead, Finished when it has passed) and its training plan and nutrition menu are re-linked, so the trainee keeps the history they had before being removed. A trainee with no previous coaching period is simply moved back to the active list.

A training plan or nutrition menu that was deleted while the trainee was archived is not re-linked: the coaching period comes back without an active plan or menu, the deleted training plan stays in the trainee's plan history, and data.detachedDeletedPlans reports it (training / nutrition set to true). When either flag is true, tell the coach and assign a new plan or menu.

Use this instead of POST /trainees for a returning trainee: re-creating them by email does attach the same account rather than a duplicate, but it leaves them without a coaching period, plan or menu, which looks like a brand-new empty trainee.

Fires the trainee.restored webhook. Returns 404 when the trainee is not in the archive (list it with GET /trainees?status=archived), 422 when restoring would exceed your trainee limit, and 422 when the trainee has since been taken on by another coach.

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.

Path parameters

Path parameters
NameTypeDescription
traineeIdrequiredstring

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 examples

cURL
curl --request POST \
  --url 'https://api.coach-platform.com/api/public/trainees/<traineeId>/restore' \
  --header 'Authorization: Bearer cp_live_...'
JavaScript (fetch)
const response = await fetch('https://api.coach-platform.com/api/public/trainees/<traineeId>/restore', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer cp_live_...',
  },
});

const data = await response.json();

Responses

200 OK

Successful response

Example body (application/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>",
    "detachedDeletedPlans": {
      "training": true,
      "nutrition": true
    }
  }
}
Response fields (24)
Response fields
NameTypeDescription
dataobject
data.idstring
data.namestring
data.emailstring
data.phoneNumberstring
data.goalstring
data.profileImageUrlstring
data.personalDetailsobject
data.labelsobject[]
data.labels[].idstring
data.labels[].textstring
data.labels[].colorstring
data.labels[].coachIdstring
data.assignedEmployeesobject[]
data.assignedEmployees[].idstring
data.assignedEmployees[].namestring
data.activeCoachDetailsobject
data.activeCoachDetails.activeEscortstring | null

Id of the escort currently in use for this trainee. Fetch the full escort with GET /escorts/{escortId}.

data.activeCoachDetails.pendingCoachstring | 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.pendingCoachDatestring<date-time> | null

When the trainee entered the pending state. Use it to measure how long approval has been waiting.

data.createdAtstring<date-time>
data.detachedDeletedPlansobject

Which of the restored coaching period's previous assignments were left out because they were deleted while the trainee was archived. training is true when the training plan was deleted, nutrition is true when the nutrition menu was deleted. A deleted plan or menu is never re-linked: the coaching period is left without an active plan or menu, and the deleted training plan stays visible in the trainee's plan history. When either is true, assign a new one (POST /training-plans or POST /nutrition-menus with the traineeId).

data.detachedDeletedPlans.trainingboolean
data.detachedDeletedPlans.nutritionboolean

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.