Skip to main content

Instructors API

Auto-generated from the OpenAPI spec. Run node docs-site/scripts/fetch-openapi.js to regenerate.

GET /api/v1/instructors/me​

Get Own Instructor Profile

Responses

  • 200 — Successful Response

GET /api/v1/instructors​

List Instructors

Parameters

NameInRequiredTypeDescription
searchqueryNo
include_inactivequeryNoboolean
statusqueryNo"active" | "inactive" | "all". Takes precedence over include_inactive when provided — "inactive" is evaluated fully server-side, so the response's total/pagination reflect the filtered count rather than the broad set. Omit to keep today's include_inactive-only behavior.
removedqueryNobooleanDefault false excludes removed instructors. true shows only removed instructors (the "Removed" tab), regardless of include_inactive.
pagequeryNointeger
page_sizequeryNointeger

Responses

  • 200 — Successful Response
  • 422 — Validation Error

POST /api/v1/instructors​

Create Instructor

Request body

FieldRequiredTypeDescription
emailYesstring
passwordYesstring
full_nameYesstring
bioNostring

Responses

  • 201 — Successful Response
  • 422 — Validation Error

PATCH /api/v1/instructors/{instructor_id}/reactivate​

Reactivate Instructor

Parameters

NameInRequiredTypeDescription
instructor_idpathYesinteger

Responses

  • 200 — Successful Response
  • 422 — Validation Error

GET /api/v1/instructors/public​

List Instructors Public

Minimal instructor picker for ANY authenticated role (client or instructor, not just staff) — e.g. the mobile app's classes/bookings/ appointments teacher filter. Deliberately separate from the staff-only GET /api/v1/instructors above (gated by get_current_user, which rejects a client token with 403 — see that dependency's docstring in app/auth.py) rather than widening that endpoint's auth: this route is intentionally narrow — active, non-removed instructors only, id+ full_name only, no search/pagination/include_inactive params.

Route-ordering: this MUST be registered before GET /{instructor_id} below (mirrors the /me routes' "MUST come before /{instructor_id}" comment above). That route's path parameter has no explicit :int path converter in the path string itself ("/{instructor_id}"), so Starlette compiles it with the generic any-segment string converter and only validates the int type via the function signature afterward — meaning the literal segment "public" would match /{instructor_id}'s pattern first (then fail int coercion with a 422, never reaching this route) if that route were registered earlier in the file. Confirmed empirically with a standalone FastAPI app reproducing this exact /{item_id} + /public route shape in both orderings: dynamic-first returns 422 on GET /public, public-first returns 200 — so this is a real shadowing hazard here, not just theoretical.

Responses

  • 200 — Successful Response

GET /api/v1/instructors/{instructor_id}​

Get Instructor

Parameters

NameInRequiredTypeDescription
instructor_idpathYesinteger

Responses

  • 200 — Successful Response
  • 422 — Validation Error

PUT /api/v1/instructors/{instructor_id}​

Update Instructor

Parameters

NameInRequiredTypeDescription
instructor_idpathYesinteger

Request body

FieldRequiredTypeDescription
full_nameNostring
bioNostring
emailNostringChanges the instructor's login email (the underlying User row). Omit to leave it unchanged.

If email is already used by another account, this returns 409 INSTRUCTOR_EMAIL_ALREADY_EXISTS instead of updating anything — same error-shape convention as STAFF_EMAIL_ALREADY_EXISTS.

Responses

  • 200 — Successful Response
  • 409 INSTRUCTOR_EMAIL_ALREADY_EXISTS — email already belongs to another account.
  • 422 — Validation Error

DELETE /api/v1/instructors/{instructor_id}​

Deactivate Instructor

Parameters

NameInRequiredTypeDescription
instructor_idpathYesinteger

Responses

  • 204 — Successful Response
  • 422 — Validation Error

POST /api/v1/instructors/{instructor_id}/photo​

Upload Instructor Photo

Parameters

NameInRequiredTypeDescription
instructor_idpathYesinteger

Responses

  • 200 — Successful Response
  • 422 — Validation Error

DELETE /api/v1/instructors/{instructor_id}/photo​

Remove Instructor Photo

Clear an instructor's profile photo without uploading a replacement.

Idempotent: calling this when no photo is set is a no-op success, not a 404 — the end state (no photo) is what the caller asked for either way.

Parameters

NameInRequiredTypeDescription
instructor_idpathYesinteger

Responses

  • 200 — Successful Response
  • 422 — Validation Error

DELETE /api/v1/instructors/{instructor_id}/remove​

Remove Instructor

Soft-delete an instructor. Never blocked by historical references.

Removed instructors are hidden from the default/active list but remain in the DB (visible via GET /instructors?removed=true) and can be restored via PATCH /restore — every scheduled class / historical record that references this instructor keeps resolving correctly either way. Neither the Instructor row nor its underlying User account is deleted; the User's own is_active flag (a separate axis, toggled via DELETE /{id} / PATCH /reactivate) is left untouched.

Parameters

NameInRequiredTypeDescription
instructor_idpathYesinteger

Responses

  • 204 — Successful Response
  • 409 INSTRUCTOR_ALREADY_REMOVED — This instructor has already been removed.
  • 422 — Validation Error

PATCH /api/v1/instructors/{instructor_id}/restore​

Restore Instructor

Clears removed_at, moving the instructor back out of the "Removed" tab and into the normal active/inactive lists.

Parameters

NameInRequiredTypeDescription
instructor_idpathYesinteger

Responses

  • 200 — Successful Response
  • 409 INSTRUCTOR_NOT_REMOVED — This instructor has not been removed.
  • 422 — Validation Error