AerScheduler

Training

Courses, syllabi, enrollments and training records. A course is trained under Part 61 or Part 141; the shape is identical and only the enforcement differs. A **published syllabus version is immutable** — revising it makes a new version, and an enrollment stays pinned to the one it started under. A student's standing against each requirement is a **ledger**: entries are only ever appended, and a correction is a reversing entry rather than an edit, so hours flown are always traceable to the lesson that earned them.

40 endpoints · base URL https://api.aerscheduler.com

get/training/candidates

Which lesson is this booking?

The lessons a booking could be closing out, unfinished ones first, filtered to what the booking type can be — a dual booking offers flight lessons, ground offers ground. A rental or a guest flight offers nothing.

Query parameters

orgUserIdintegerThe student.
typestringThe booking type: dual, solo, ground or sim. Omit for every lesson.
limitintegerRows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row — total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKSuccess.{ data: object[] }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/candidates \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/training/courses

List courses

The courses your school teaches. Requires the admin role — a syllabus is not students' business.

Query parameters

includeArchivedbooleanInclude retired courses.
limitintegerRows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row — total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKSuccess.{ data: object[] }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/courses \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/courses

Create a course

Creates the course and its first editable draft version, Rev A. Requires the admin role.

Request body

The course.

namerequiredstring
descriptionstring
enrollmentFeeCentsintegerWhat the school charges to enroll, in cents. Omit for a free course.
enrollmentFeeLabelstringHow the fee reads on the invoice line.
regulatoryPart"part61" | "part141"Which regime this course is trained under. Defaults to part61. Cannot be changed later — a school moving to Part 141 creates a new course.
certificateSoughtstringprivate | instrument | commercial | cfi | atp | endorsement | other.
ratingIdintegerAn instruction rate to price this course from. Pricing only — a rating is a rate card, not the course.

Responses

200OKSuccess.{ data: object }
400Bad RequestValidation failed.
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/courses \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"…"}'
post/training/credits

Post credit by hand

For transferred training and backfills. Measured in hours or a count, never both, and never negative — to take credit back, reverse the entry that granted it. A manual credit must carry a note. Requires the admin role.

Request body

The entry.

enrollmentIdrequiredinteger
requirementIdrequiredinteger
deciHoursintegerTenths.
countinteger
sourcerequired"lesson" | "transfer_141" | "transfer_61" | "simulator" | "manual"
notesstringRequired for manual.

Responses

200OKSuccess.{ data: object }
400Bad RequestThe entry would be meaningless or unexplained.
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/credits \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enrollmentId":1,"requirementId":1,"source":"lesson"}'
get/training/endorsements

List endorsements

A pilot's signed endorsements. Readable by the person they belong to and by instructors and admins — a member always sees only their own, whatever they ask for. Superseded ones are hidden unless asked for: a renewed 90-day solo replaces the earlier one, and listing both invites signing against the wrong row.

Query parameters

orgUserIdintegerWhose. Ignored for callers who are not staff.
includeSupersededbooleanInclude replaced endorsements.
limitintegerRows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row — total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKSuccess.{ data: object[] }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/endorsements \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/endorsements

Sign an endorsement

The renderedText you send is stored verbatim and never regenerated. AC 61-65K replaced AC 61-65H and will itself be replaced; an endorsement has to keep saying what was signed on the day it was signed. Pass supersedesId to replace an earlier one — a renewed 90-day solo is a new endorsement, not an edit. Requires the instructor or admin role.

Request body

The endorsement.

orgUserIdrequiredintegerWho it is for.
templateCodestringAC 61-65K paragraph, e.g. A.3. Optional; recorded for reference.
titlestring
renderedTextrequiredstringThe endorsement exactly as signed, with every blank filled in.
expiresAtstringDefaults from the template — 90 days for a solo endorsement. Omit for one that does not expire.
enrollmentIdintegerOptional. Plenty of endorsements belong to a person rather than a course.
signerCertificateNumberstring
signerCertificateExpirystring
supersedesIdinteger

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409That endorsement has already been replaced.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/endorsements \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"orgUserId":1,"renderedText":"…"}'
get/training/enrollments

List enrollments

Staff see everyone's. A student always sees only their own, whatever they ask for — §141.101 gives them the right to their record, and no right to anyone else's.

Query parameters

orgUserIdintegerFilter to one student. Ignored for callers who are not staff.
courseIdintegerFilter to one course.
statusstringenrolled | graduated | terminated | transferred
limitintegerRows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row — total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKSuccess.{ data: object[] }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/enrollments \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/enrollments

Enroll a student

Pins the student to this syllabus version. A Part 141 course must be published first. Requires the admin role.

Request body

The enrollment.

versionIdrequiredinteger
orgUserIdrequiredinteger
enrollmentCertificateNumberstring§141.93 certificate of enrollment.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409Already enrolled, or the version is a draft or retired.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/enrollments \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"versionId":1,"orgUserId":1}'
get/training/grants

List training grants

Every grant in the school. Requires the admin role.

Query parameters

limitintegerRows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row — total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKSuccess.{ data: object[] }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/grants \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/grants

Grant a training permission

Gives someone a training grant. courseId is only accepted for checkInstructor, which §141.37 designates per approved course. Requires the admin role.

Request body

The grant.

orgUserIdrequiredinteger
grantrequired"configureTraining" | "manageEnrollment" | "checkInstructor" | "auditor"
courseIdintegerOnly for checkInstructor. Omit for a school-wide designation.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/grants \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"orgUserId":1,"grant":"configureTraining"}'
post/training/records

Grade a lesson

Creates or updates a training record. Editable until it is signed and frozen the moment it is. Pass reservationId to tie it to the booking it came from. Requires the instructor or admin role.

Request body

The grade.

enrollmentIdrequiredinteger
lessonIdrequiredinteger
recordIdintegerOmit to create.
gradestringFrom the course version's grading scale. Defaults to S / U / I.
notesstring
flightDeciHoursintegerTenths. Normally the Hobbs delta.
instructionDeciHoursintegerTenths. Normally the briefing time.
simulatorDeciHoursintegerTenths. The part flown in a simulator or FTD.
reservationIdinteger
instructorOrgUserIdintegerDefaults to the caller.
taskGradesobject[]

Responses

200OKSaved. warning carries a Part 141 out-of-order notice, if any.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The record is already signed.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/records \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enrollmentId":1,"lessonId":1}'
get/training/templates

List syllabus templates

Ready-made syllabi a school can fork. Requires the admin role.

Query parameters

limitintegerRows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row — total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKSuccess.{ data: object[] }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/templates \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/training/courses/{courseId}

Get a course

The course and every version of its syllabus. Requires the admin role.

Path parameters

courseIdrequiredintegerThe course id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/courses/:courseId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
patch/training/courses/{courseId}

Update a course

Requires the admin role. regulatoryPart cannot be changed.

Path parameters

courseIdrequiredintegerThe course id.

Request body

Fields to change.

namestring
descriptionstring
certificateSoughtstring
ratingIdinteger
archivedboolean

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X PATCH https://api.aerscheduler.com/training/courses/:courseId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"…","description":"…"}'
get/training/endorsements/templates

Endorsement templates

The AC 61-65K Appendix A endorsements a Part 61/141 aircraft school actually signs. Pass orgUserId and the student's name is substituted for you; every other {placeholder} is left for the instructor, because inventing values would be putting words into a signature.

Query parameters

orgUserIdintegerPre-fill the student's name.
limitintegerRows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row — total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKSuccess.{ data: object[] }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/endorsements/templates \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/training/enrollments/{enrollmentId}

A student's progress

The syllabus, every graded record against it, and where the ledger stands on each requirement — including what a simulator or transfer ceiling disallowed. Readable by the student themselves, and by instructors and admins.

Path parameters

enrollmentIdrequiredintegerThe enrollment id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/enrollments/:enrollmentId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
delete/training/grants/{grantId}

Revoke a training grant

Requires the admin role.

Path parameters

grantIdrequiredintegerThe grant id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X DELETE https://api.aerscheduler.com/training/grants/:grantId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/training/grants/catalog

List the training grants on offer

The four grants a school can hand out, with a description of each. Any member may read this — it is a vocabulary, not a permission.

Query parameters

limitintegerRows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected.
offsetintegerRows to skip, for paging. Defaults to 0.
sortstringField to order by before paging, as a dot path into the row — total, user.firstName. Omit to keep the endpoint's own order. Numbers and ISO timestamps order as numbers and instants, not as text, and empty values always sort last regardless of direction. Ordering happens before the page is cut, so it orders the whole collection rather than the page you are holding.
order"asc" | "desc"asc (default) or desc. Only meaningful with sort.

Responses

200OKSuccess.{ data: object[] }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/grants/catalog \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
get/training/grants/mine

What the caller may do in training

The grants held by the caller, the ones their role implies, and whether they may grade. Every client needs this to decide which buttons to offer.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/grants/mine \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/templates/{templateKey}

Create a course from a template

Builds a complete course — stages, lessons, ACS-coded tasks and requirements, with the credit map already wired — as an editable draft. Templates are always created as Part 61: a template cannot be an FAA-approved Training Course Outline, because approval is per school and per FSDO. Requires the admin role.

Path parameters

templateKeyrequiredintegerThe template key, e.g. ppl-asel-part61.

Request body

Optional overrides.

namestringDefaults to the template's name.
ratingIdinteger

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
404Not FoundNo such template.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/templates/:templateKey \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"…","ratingId":1}'
get/training/versions/{versionId}

Get a syllabus version

The whole syllabus: stages, lessons, tasks and requirements. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl https://api.aerscheduler.com/training/versions/:versionId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/courses/{courseId}/versions

Create a syllabus version

Pass copyFromVersionId to fork an existing version — the normal way to revise a published syllabus, since the published one cannot be edited. The copy is deep and the new version is an editable draft. Requires the admin role.

Path parameters

courseIdrequiredintegerThe course id.

Request body

The version.

labelrequiredstringFree text, e.g. "Rev B" — schools match what they filed with their FSDO.
copyFromVersionIdinteger

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409A version with that label already exists.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/courses/:courseId/versions \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label":"…"}'
post/training/credits/{creditId}/reverse

Reverse a ledger entry

Writes a negative entry alongside. Nothing is deleted, and a reversal cannot itself be reversed. Requires the admin role.

Path parameters

creditIdrequiredintegerThe entry id.

Request body

Why.

reasonrequiredstring

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409Already reversed, or itself a reversal.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/credits/:creditId/reverse \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"…"}'
post/training/enrollments/{enrollmentId}/certify

Certify a training record

§141.85 — the chief instructor certifying the record before graduation. Requires the admin role.

Path parameters

enrollmentIdrequiredintegerThe enrollment id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/enrollments/:enrollmentId/certify \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/enrollments/{enrollmentId}/end

Terminate or transfer an enrollment

§141.101 wants the date and the reason. Requires the admin role.

Path parameters

enrollmentIdrequiredintegerThe enrollment id.

Request body

How it ended.

statusrequired"terminated" | "transferred"
reasonstring

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The enrollment has already ended.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/enrollments/:enrollmentId/end \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"terminated"}'
post/training/enrollments/{enrollmentId}/fee

Bill the course enrollment fee

Raises an invoice for the fee this enrollment snapshotted when the student enrolled. Refuses if the course had no fee or the fee has already been invoiced — a second invoice for the same fee is not something a refund undoes cleanly. Requires the manageEnrollment grant or the admin role.

Path parameters

enrollmentIdrequiredintegerThe enrollment id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/enrollments/:enrollmentId/fee \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/enrollments/{enrollmentId}/graduate

Graduate a student

Under Part 141 this refuses while any FAA-sourced requirement is unmet, and requires the chief instructor to have certified the record. Under Part 61 nothing blocks — the instructor decides readiness. Requires the admin role.

Path parameters

enrollmentIdrequiredintegerThe enrollment id.

Request body

Optional.

graduationCertificateNumberstring§141.95 graduation certificate.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409Requirements are unmet, or the enrollment has already ended.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/enrollments/:enrollmentId/graduate \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"graduationCertificateNumber":"…"}'
post/training/records/{recordId}/amend

Amend a signed lesson

A signed record is never edited. This writes a new record superseding it and reverses everything the original posted to the ledger. Both records stay, and so do both sets of ledger entries. Requires the instructor or admin role.

Path parameters

recordIdrequiredintegerThe record id.

Request body

Why.

reasonrequiredstringStays on the record and on every reversing entry.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409Not signed, or already amended.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/records/:recordId/amend \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"…"}'
post/training/records/{recordId}/countersign

Countersign a lesson

The student's signature on what their instructor recorded. Only the student on the record may call it, and only after the instructor has signed.

Path parameters

recordIdrequiredintegerThe record id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenNot your record.
409The instructor has not signed yet.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/records/:recordId/countersign \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
post/training/records/{recordId}/sign

Sign a lesson

Freezes the record and posts what it earned to the ledger, atomically. By default the credits come from what the syllabus says the lesson credits; pass credits to override — weather turns a night cross-country into a local day flight, and the record has to be able to say so. Requires the instructor or admin role.

Path parameters

recordIdrequiredintegerThe record id.

Request body

Optional credit override.

creditsobject[]

Responses

200OKSigned. creditsPosted is how many ledger entries it wrote.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409Already signed, or not graded yet.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/records/:recordId/sign \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"credits":[]}'
put/training/versions/{versionId}/gradingScale

Set the grading scale

Declares this course's marks and which of them mean a lesson is complete. "3" passes at a school marking 1–4 and fails at one marking 1–3, so guessing from the string is how a gradebook quietly disagrees with the school using it. Draft versions only. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.

Request body

The full scale, in display order.

scalerequiredobject[]

Responses

200OKSuccess.{ data: object }
400Bad RequestEvery grade cannot fail, and two grades cannot share a name.
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X PUT https://api.aerscheduler.com/training/versions/:versionId/gradingScale \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scale":[]}'
put/training/versions/{versionId}/lessons

Create or update a lesson

Omit lessonId to create. credits declares what this lesson is designed to credit and from which clock — this is what makes one flight post to several requirements at once. Only works on a draft. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.

Request body

The lesson.

lessonIdinteger
stageIdrequiredinteger
namerequiredstring
positionrequiredinteger
kindrequired"ground" | "flight" | "sim"
objectivesstring
completionStandardsstring
minFlightDeciHoursintegerTenths of an hour.
minGroundDeciHoursintegerTenths of an hour.
creditsobject[]Which requirements this lesson credits.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The version is published.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X PUT https://api.aerscheduler.com/training/versions/:versionId/lessons \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"stageId":1,"name":"…","position":1,"kind":"ground"}'
post/training/versions/{versionId}/publish

Publish a syllabus version

Freezes the version permanently. After this, no stage, lesson, task or requirement under it can be changed — students are enrolled against exactly these lessons. To revise, create a new version from this one. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.

Request body

Optional FSDO approval details, for Part 141.

approvedAtstring
approvalReferencestring

Responses

200OKSuccess.{ data: object }
400Bad RequestThe version has no lessons.
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409Already published.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/versions/:versionId/publish \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"approvedAt":"2026-08-04T15:00:00-06:00","approvalReference":"…"}'
put/training/versions/{versionId}/requirements

Create or update a requirement

What a student must accumulate — 35 hours total, 3 hours night, 10 towered landings. Measured in hours or a count, never both. source is part61, part141 or school; only FAA-sourced ones can block a Part 141 graduation. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.

Request body

The requirement.

requirementIdinteger
coderequiredstringStable machine key, e.g. "total_flight", "night", "cross_country".
labelrequiredstring
minDeciHoursintegerTenths of an hour.
minCountinteger
source"part61" | "part141" | "school"
maxSimulatorBpsintegerCeiling on simulator credit, in basis points. Appendix B allows 2000 (20%).
maxTransferBpsintegerCeiling on transferred credit, in basis points. §141.77 allows 5000 from an approved course, 2500 otherwise.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The version is published, or the code is already used.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X PUT https://api.aerscheduler.com/training/versions/:versionId/requirements \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"code":"…","label":"…"}'
post/training/versions/{versionId}/retire

Retire a syllabus version

Stops new enrollments. Students already on it finish on it. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.

Request body

Set retired false to un-retire.

retiredboolean

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X POST https://api.aerscheduler.com/training/versions/:versionId/retire \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"retired":true}'
put/training/versions/{versionId}/stages

Create or update a stage

Omit stageId to create. Only works on a draft. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.

Request body

The stage.

stageIdinteger
namerequiredstring
objectivestring
positionrequiredinteger
requiresStageCheckboolean

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The version is published and cannot be changed.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X PUT https://api.aerscheduler.com/training/versions/:versionId/stages \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"…","position":1}'
delete/training/versions/{versionId}/lessons/{lessonId}

Delete a lesson

Only works on a draft. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.
lessonIdrequiredintegerThe lesson id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The version is published.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X DELETE https://api.aerscheduler.com/training/versions/:versionId/lessons/:lessonId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
delete/training/versions/{versionId}/requirements/{requirementId}

Delete a requirement

Only works on a draft. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.
requirementIdrequiredintegerThe requirement id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The version is published.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X DELETE https://api.aerscheduler.com/training/versions/:versionId/requirements/:requirementId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
delete/training/versions/{versionId}/stages/{stageId}

Delete a stage

Only works on a draft. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.
stageIdrequiredintegerThe stage id.

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The version is published.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X DELETE https://api.aerscheduler.com/training/versions/:versionId/stages/:stageId \
  -H "Authorization: Bearer $AERSCHEDULER_KEY"
put/training/versions/{versionId}/lessons/{lessonId}/tasks

Replace a lesson's tasks

Send the full list; it replaces what is there. acsCode maps a task to the ACS, e.g. PA.VI.A. Requires the admin role.

Path parameters

versionIdrequiredintegerThe version id.
lessonIdrequiredintegerThe lesson id.

Request body

The full task list.

tasksrequiredobject[]

Responses

200OKSuccess.{ data: object }
401UnauthorizedNo token, an expired token, or a malformed one. Sign in again.
403ForbiddenAuthenticated, but not allowed to do this.
409The version is published.
429Too Many RequestsRate limited. Retry-After says how long to wait.
Example request
curl -X PUT https://api.aerscheduler.com/training/versions/:versionId/lessons/:lessonId/tasks \
  -H "Authorization: Bearer $AERSCHEDULER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tasks":[]}'