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

# Add, List, and Remove Students in Your Academy API

> List, add, retrieve, and remove students in your academy. Supports bulk course enrollment on creation and detailed progress tracking per student.

The students endpoints let you manage the people who learn in your academy. You can list all students with pagination, add new students and optionally enroll them in courses at the same time, retrieve a single student's profile and detailed progress, and remove a student from your academy. All endpoints require your API key in the `Authorization` header. See [Authentication](/docs/api-reference/authentication).

***

## List students

Returns a paginated list of active students in your academy.

```text theme={null}
GET /api/v1/students
```

### Query parameters

<ParamField query="limit" default="50" type="number">
  Number of students to return. Minimum `1`, maximum `100`.
</ParamField>

<ParamField query="offset" default="0" type="number">
  Number of students to skip before returning results. Use with `limit` for pagination.
</ParamField>

### Response fields

<ResponseField name="data" type="object" required>
  <Expandable title="properties" defaultOpen>
    <ResponseField name="students" type="object[]" required>
      Array of student objects, ordered by `joined_at` descending.

      <Expandable title="student properties" defaultOpen>
        <ResponseField name="id" type="string" required>
          UUID of the student's user account.
        </ResponseField>

        <ResponseField name="email" type="string" required>
          Student's email address.
        </ResponseField>

        <ResponseField name="name" type="string">
          Student's display name. May be `null` if not set.
        </ResponseField>

        <ResponseField name="avatar_url" type="string">
          URL of the student's avatar image. May be `null`.
        </ResponseField>

        <ResponseField name="joined_at" type="string" required>
          ISO 8601 timestamp of when the student joined the academy.
        </ResponseField>

        <ResponseField name="access" type="object" required>
          Summary of what the student holds through your academy's offers and purchases.

          <Expandable title="access properties">
            <ResponseField name="holds_pass" type="boolean" required>
              `true` when the student holds your Academy Pass (access to every course).
            </ResponseField>

            <ResponseField name="offer_count" type="number" required>
              Number of active offers the student currently holds, the Pass included.
            </ResponseField>

            <ResponseField name="has_purchase" type="boolean" required>
              `true` when the student has at least one paid, non-refunded payment in your academy.
            </ResponseField>
          </Expandable>
        </ResponseField>

        <ResponseField name="courses_enrolled" type="number" required>
          Number of active course enrollments.
        </ResponseField>

        <ResponseField name="enrollments" type="object[]" required>
          Array of active enrollment summaries. An enrollment means the student started the course (it appears in their My Learning); it is not the full picture of what they can open. A student can have access to courses they have not started yet, through free courses, offers they hold, or purchases.

          <Expandable title="enrollment properties">
            <ResponseField name="id" type="string" required>
              UUID of the enrollment record.
            </ResponseField>

            <ResponseField name="course_id" type="string" required>
              UUID of the enrolled course.
            </ResponseField>

            <ResponseField name="enrolled_at" type="string" required>
              ISO 8601 timestamp of enrollment.
            </ResponseField>

            <ResponseField name="completed_at" type="string">
              ISO 8601 timestamp of completion. `null` if not yet completed.
            </ResponseField>
          </Expandable>
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="pagination" type="object" required>
      <Expandable title="properties" defaultOpen>
        <ResponseField name="total" type="number" required>
          Total number of students in the academy.
        </ResponseField>

        <ResponseField name="limit" type="number" required>
          The `limit` value used for this request.
        </ResponseField>

        <ResponseField name="offset" type="number" required>
          The `offset` value used for this request.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

### Example request

```bash theme={null}
curl "https://yourname.fayneos.com/api/v1/students?limit=10&offset=0" \
  -H "Authorization: Bearer fa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

### Example response

```json theme={null}
{
  "data": {
    "students": [
      {
        "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
        "email": "alex@example.com",
        "name": "Alex Rivera",
        "avatar_url": "https://cdn.example.com/avatars/alex.jpg",
        "joined_at": "2025-03-15T09:22:00Z",
        "access": {
          "holds_pass": false,
          "offer_count": 1,
          "has_purchase": true
        },
        "courses_enrolled": 2,
        "enrollments": [
          {
            "id": "e1f2a3b4-c5d6-7890-efab-123456789abc",
            "course_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
            "enrolled_at": "2025-03-15T09:22:00Z",
            "completed_at": null
          }

        ]
      }
    ],
    "pagination": {
      "total": 42,
      "limit": 10,
      "offset": 0
    }
  }
}
```

***

## Add a student

Adds a new student to your academy and optionally enrolls them in one or more courses in a single request.

```text theme={null}
POST /api/v1/students
```

### Body parameters

<ParamField body="email" type="string" required>
  Email address of the student. Must be a valid email format.
</ParamField>

<ParamField body="name" type="string">
  Display name for the student. Maximum 200 characters. Optional.
</ParamField>

<ParamField body="course_ids" type="string[]">
  Array of course UUIDs to enroll the student in. Maximum 50 course IDs per request. Each course must be published. Optional. Creates a permanent enrollment per course.
</ParamField>

<ParamField body="list_ids" type="string[]">
  Array of [list](/docs/api-reference/lists) UUIDs to add the student to. Maximum 50 per request. Each list must exist in this academy, or the request returns `400 invalid_lists`. Offer-managed lists return `400 list_managed_by_offer`; grant the offer instead. All ids are validated before the student account is created, so a rejected request creates nothing. Use `list_ids` for cohort or tier access you may want to revoke later, and `course_ids` for an individual course assignment. Optional.
</ParamField>

<ParamField body="send_welcome_email" default="true" type="boolean">
  Whether to send the magic-link welcome email to the new student. Set to `false` for silent imports. Optional.
</ParamField>

### Response fields

Returns the newly created student with a `201` status code. The response contains `id`, `email`, `name`, a `membershipStatus` field (`created` or `reactivated`), and an `enrollments` array whose items have `id`, `course_id`, and `course_title`. This is a smaller object than the list endpoint's student: it does not include `avatar_url`, `joined_at`, or `courses_enrolled`. Adding a student who is already an active member of the academy returns `409 already_exists`.

### Example request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://yourname.fayneos.com/api/v1/students \
    -H "Authorization: Bearer fa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "email": "jamie@example.com",
      "name": "Jamie Chen",
      "course_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://yourname.fayneos.com/api/v1/students', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer fa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      email: 'jamie@example.com',
      name: 'Jamie Chen',
      course_ids: ['a1b2c3d4-e5f6-7890-abcd-ef1234567890']
    })
  });
  const { data } = await response.json();
  ```
</CodeGroup>

***

## Get a student

Returns the full profile and enrollment detail for a single student, including per-course progress.

```text theme={null}
GET /api/v1/students/:studentId
```

### Path parameters

<ParamField path="studentId" type="string" required>
  UUID of the student. Must be a valid UUID or the request returns a `400`.
</ParamField>

### Response fields

<ResponseField name="data" type="object" required>
  <Expandable title="properties" defaultOpen>
    <ResponseField name="id" type="string" required>
      UUID of the student's user account.
    </ResponseField>

    <ResponseField name="email" type="string" required>
      Student's email address.
    </ResponseField>

    <ResponseField name="name" type="string">
      Student's display name. May be `null`.
    </ResponseField>

    <ResponseField name="avatar_url" type="string">
      URL of the student's avatar image. May be `null`.
    </ResponseField>

    <ResponseField name="joined_at" type="string" required>
      ISO 8601 timestamp of when the student joined the academy.
    </ResponseField>

    <ResponseField name="access" type="object" required>
      What the student holds through offers, purchases, and course assignments.

      <Expandable title="access properties" defaultOpen>
        <ResponseField name="holds_pass" type="boolean" required>
          `true` when the student holds your Academy Pass (access to every course).
        </ResponseField>

        <ResponseField name="offer_count" type="number" required>
          Number of active offers the student currently holds, the Pass included.
        </ResponseField>

        <ResponseField name="has_purchase" type="boolean" required>
          `true` when the student has at least one paid, non-refunded payment in your academy.
        </ResponseField>

        <ResponseField name="grants" type="object[]" required>
          The student's live course assignments (given through this API or the dashboard). A grant can exist before the student has opened the course, so it may not have a matching enrollment yet.

          <Expandable title="grant properties">
            <ResponseField name="course_id" type="string" required>
              UUID of the assigned course.
            </ResponseField>

            <ResponseField name="granted_at" type="string" required>
              ISO 8601 timestamp of when the course was assigned.
            </ResponseField>
          </Expandable>
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="enrollments" type="object[]" required>
      Array of active enrollments with full progress detail, ordered by `enrolled_at` descending. An enrollment means the student started the course; access itself can also come from free courses, offers, or purchases that have no enrollment yet.

      <Expandable title="enrollment properties" defaultOpen>
        <ResponseField name="id" type="string" required>
          UUID of the enrollment record.
        </ResponseField>

        <ResponseField name="course_id" type="string" required>
          UUID of the enrolled course.
        </ResponseField>

        <ResponseField name="course_title" type="string" required>
          Display title of the course.
        </ResponseField>

        <ResponseField name="course_slug" type="string" required>
          URL-safe slug of the course.
        </ResponseField>

        <ResponseField name="enrolled_at" type="string" required>
          ISO 8601 timestamp of enrollment.
        </ResponseField>

        <ResponseField name="completed_at" type="string">
          ISO 8601 timestamp of course completion. `null` if not yet completed.
        </ResponseField>

        <ResponseField name="total_lessons" type="number" required>
          Total number of published lessons in the course.
        </ResponseField>

        <ResponseField name="completed_lessons" type="number" required>
          Number of lessons the student has completed.
        </ResponseField>

        <ResponseField name="progress" type="number" required>
          Completion percentage from `0` to `100`, rounded to the nearest integer.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

### Example request

```bash theme={null}
curl https://yourname.fayneos.com/api/v1/students/c3d4e5f6-a7b8-9012-cdef-123456789012 \
  -H "Authorization: Bearer fa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

### Example response

```json theme={null}
{
  "data": {
    "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "email": "alex@example.com",
    "name": "Alex Rivera",
    "avatar_url": "https://cdn.example.com/avatars/alex.jpg",
    "joined_at": "2025-03-15T09:22:00Z",
    "access": {
      "holds_pass": false,
      "offer_count": 1,
      "has_purchase": true,
      "grants": [
        {
          "course_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          "granted_at": "2025-03-15T09:22:00Z"
        }
      ]
    },
    "enrollments": [
      {
        "id": "e1f2a3b4-c5d6-7890-efab-123456789abc",
        "course_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "course_title": "Cold Outreach Mastery",
        "course_slug": "cold-outreach-mastery",
        "enrolled_at": "2025-03-15T09:22:00Z",
        "completed_at": null,
        "total_lessons": 12,
        "completed_lessons": 5,
        "progress": 42
      }
    ]
  }
}
```

***

## Remove a student

Removes a student from your academy. This revokes all of their course enrollments and deletes all of their lesson progress, and cannot be undone. The student's Fayne account itself is not deleted; they are only removed from this academy.

```text theme={null}
DELETE /api/v1/students/:studentId
```

### Path parameters

<ParamField path="studentId" type="string" required>
  UUID of the student to remove.
</ParamField>

<Warning>
  Removing a student deletes all of their progress data in this academy and revokes access to every course. This cannot be reversed. Their Fayne account is not deleted.
</Warning>

### Response fields

<ResponseField name="data" type="object" required>
  <Expandable title="properties" defaultOpen>
    <ResponseField name="removed" type="boolean" required>
      Always `true` when the operation succeeds.
    </ResponseField>
  </Expandable>
</ResponseField>

### Example request

```bash theme={null}
curl -X DELETE \
  https://yourname.fayneos.com/api/v1/students/c3d4e5f6-a7b8-9012-cdef-123456789012 \
  -H "Authorization: Bearer fa_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

### Example response

```json theme={null}
{
  "data": {
    "removed": true
  }
}
```
