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
/training/candidatesWhich 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
orgUserId | integer | The student. |
type | string | The booking type: dual, solo, ground or sim. Omit for every lesson. |
limit | integer | Rows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected. |
offset | integer | Rows to skip, for paging. Defaults to 0. |
sort | string | Field 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
200 | OK | Success.→ { data: object[] } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/candidates \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/coursesList courses
The courses your school teaches. Requires the admin role — a syllabus is not students' business.
Query parameters
includeArchived | boolean | Include retired courses. |
limit | integer | Rows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected. |
offset | integer | Rows to skip, for paging. Defaults to 0. |
sort | string | Field 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
200 | OK | Success.→ { data: object[] } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/courses \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/coursesCreate a course
Creates the course and its first editable draft version, Rev A. Requires the admin role.
Request body
The course.
namerequired | string | |
description | string | |
enrollmentFeeCents | integer | What the school charges to enroll, in cents. Omit for a free course. |
enrollmentFeeLabel | string | How 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. |
certificateSought | string | private | instrument | commercial | cfi | atp | endorsement | other. |
ratingId | integer | An instruction rate to price this course from. Pricing only — a rating is a rate card, not the course. |
Responses
200 | OK | Success.→ { data: object } |
400 | Bad Request | Validation failed. |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/courses \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"…"}'/training/creditsPost 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.
enrollmentIdrequired | integer | |
requirementIdrequired | integer | |
deciHours | integer | Tenths. |
count | integer | |
sourcerequired | "lesson" | "transfer_141" | "transfer_61" | "simulator" | "manual" | |
notes | string | Required for manual. |
Responses
200 | OK | Success.→ { data: object } |
400 | Bad Request | The entry would be meaningless or unexplained. |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
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"}'/training/endorsementsList 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
orgUserId | integer | Whose. Ignored for callers who are not staff. |
includeSuperseded | boolean | Include replaced endorsements. |
limit | integer | Rows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected. |
offset | integer | Rows to skip, for paging. Defaults to 0. |
sort | string | Field 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
200 | OK | Success.→ { data: object[] } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/endorsements \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/endorsementsSign 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.
orgUserIdrequired | integer | Who it is for. |
templateCode | string | AC 61-65K paragraph, e.g. A.3. Optional; recorded for reference. |
title | string | |
renderedTextrequired | string | The endorsement exactly as signed, with every blank filled in. |
expiresAt | string | Defaults from the template — 90 days for a solo endorsement. Omit for one that does not expire. |
enrollmentId | integer | Optional. Plenty of endorsements belong to a person rather than a course. |
signerCertificateNumber | string | |
signerCertificateExpiry | string | |
supersedesId | integer |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | That endorsement has already been replaced. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/endorsements \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"orgUserId":1,"renderedText":"…"}'/training/enrollmentsList 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
orgUserId | integer | Filter to one student. Ignored for callers who are not staff. |
courseId | integer | Filter to one course. |
status | string | enrolled | graduated | terminated | transferred |
limit | integer | Rows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected. |
offset | integer | Rows to skip, for paging. Defaults to 0. |
sort | string | Field 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
200 | OK | Success.→ { data: object[] } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/enrollments \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/enrollmentsEnroll 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.
versionIdrequired | integer | |
orgUserIdrequired | integer | |
enrollmentCertificateNumber | string | §141.93 certificate of enrollment. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | Already enrolled, or the version is a draft or retired. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/enrollments \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"versionId":1,"orgUserId":1}'/training/grantsList training grants
Every grant in the school. Requires the admin role.
Query parameters
limit | integer | Rows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected. |
offset | integer | Rows to skip, for paging. Defaults to 0. |
sort | string | Field 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
200 | OK | Success.→ { data: object[] } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/grants \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/grantsGrant 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.
orgUserIdrequired | integer | |
grantrequired | "configureTraining" | "manageEnrollment" | "checkInstructor" | "auditor" | |
courseId | integer | Only for checkInstructor. Omit for a school-wide designation. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/grants \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"orgUserId":1,"grant":"configureTraining"}'/training/recordsGrade 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.
enrollmentIdrequired | integer | |
lessonIdrequired | integer | |
recordId | integer | Omit to create. |
grade | string | From the course version's grading scale. Defaults to S / U / I. |
notes | string | |
flightDeciHours | integer | Tenths. Normally the Hobbs delta. |
instructionDeciHours | integer | Tenths. Normally the briefing time. |
simulatorDeciHours | integer | Tenths. The part flown in a simulator or FTD. |
reservationId | integer | |
instructorOrgUserId | integer | Defaults to the caller. |
taskGrades | object[] |
Responses
200 | OK | Saved. warning carries a Part 141 out-of-order notice, if any.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The record is already signed. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/records \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"enrollmentId":1,"lessonId":1}'/training/templatesList syllabus templates
Ready-made syllabi a school can fork. Requires the admin role.
Query parameters
limit | integer | Rows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected. |
offset | integer | Rows to skip, for paging. Defaults to 0. |
sort | string | Field 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
200 | OK | Success.→ { data: object[] } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/templates \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/courses/{courseId}Get a course
The course and every version of its syllabus. Requires the admin role.
Path parameters
courseIdrequired | integer | The course id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/courses/:courseId \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/courses/{courseId}Update a course
Requires the admin role. regulatoryPart cannot be changed.
Path parameters
courseIdrequired | integer | The course id. |
Request body
Fields to change.
name | string | |
description | string | |
certificateSought | string | |
ratingId | integer | |
archived | boolean |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X PATCH https://api.aerscheduler.com/training/courses/:courseId \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"…","description":"…"}'/training/endorsements/templatesEndorsement 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
orgUserId | integer | Pre-fill the student's name. |
limit | integer | Rows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected. |
offset | integer | Rows to skip, for paging. Defaults to 0. |
sort | string | Field 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
200 | OK | Success.→ { data: object[] } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/endorsements/templates \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/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
enrollmentIdrequired | integer | The enrollment id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/enrollments/:enrollmentId \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/grants/{grantId}Revoke a training grant
Requires the admin role.
Path parameters
grantIdrequired | integer | The grant id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X DELETE https://api.aerscheduler.com/training/grants/:grantId \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/grants/catalogList 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
limit | integer | Rows to return, 1–1000. Defaults to 1000; a larger value is clamped rather than rejected. |
offset | integer | Rows to skip, for paging. Defaults to 0. |
sort | string | Field 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
200 | OK | Success.→ { data: object[] } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/grants/catalog \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/grants/mineWhat 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
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/grants/mine \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/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
templateKeyrequired | integer | The template key, e.g. ppl-asel-part61. |
Request body
Optional overrides.
name | string | Defaults to the template's name. |
ratingId | integer |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
404 | Not Found | No such template. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/templates/:templateKey \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"…","ratingId":1}'/training/versions/{versionId}Get a syllabus version
The whole syllabus: stages, lessons, tasks and requirements. Requires the admin role.
Path parameters
versionIdrequired | integer | The version id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl https://api.aerscheduler.com/training/versions/:versionId \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/courses/{courseId}/versionsCreate 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
courseIdrequired | integer | The course id. |
Request body
The version.
labelrequired | string | Free text, e.g. "Rev B" — schools match what they filed with their FSDO. |
copyFromVersionId | integer |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | A version with that label already exists. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/courses/:courseId/versions \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"label":"…"}'/training/credits/{creditId}/reverseReverse a ledger entry
Writes a negative entry alongside. Nothing is deleted, and a reversal cannot itself be reversed. Requires the admin role.
Path parameters
creditIdrequired | integer | The entry id. |
Request body
Why.
reasonrequired | string |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | Already reversed, or itself a reversal. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/credits/:creditId/reverse \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"reason":"…"}'/training/enrollments/{enrollmentId}/certifyCertify a training record
§141.85 — the chief instructor certifying the record before graduation. Requires the admin role.
Path parameters
enrollmentIdrequired | integer | The enrollment id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/enrollments/:enrollmentId/certify \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/enrollments/{enrollmentId}/endTerminate or transfer an enrollment
§141.101 wants the date and the reason. Requires the admin role.
Path parameters
enrollmentIdrequired | integer | The enrollment id. |
Request body
How it ended.
statusrequired | "terminated" | "transferred" | |
reason | string |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The enrollment has already ended. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/enrollments/:enrollmentId/end \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"terminated"}'/training/enrollments/{enrollmentId}/feeBill 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
enrollmentIdrequired | integer | The enrollment id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/enrollments/:enrollmentId/fee \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/enrollments/{enrollmentId}/graduateGraduate 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
enrollmentIdrequired | integer | The enrollment id. |
Request body
Optional.
graduationCertificateNumber | string | §141.95 graduation certificate. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | Requirements are unmet, or the enrollment has already ended. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/enrollments/:enrollmentId/graduate \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"graduationCertificateNumber":"…"}'/training/records/{recordId}/amendAmend 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
recordIdrequired | integer | The record id. |
Request body
Why.
reasonrequired | string | Stays on the record and on every reversing entry. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | Not signed, or already amended. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/records/:recordId/amend \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"reason":"…"}'/training/records/{recordId}/countersignCountersign 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
recordIdrequired | integer | The record id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Not your record. |
409 | The instructor has not signed yet. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/records/:recordId/countersign \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/records/{recordId}/signSign 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
recordIdrequired | integer | The record id. |
Request body
Optional credit override.
credits | object[] |
Responses
200 | OK | Signed. creditsPosted is how many ledger entries it wrote.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | Already signed, or not graded yet. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/records/:recordId/sign \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"credits":[]}'/training/versions/{versionId}/gradingScaleSet 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
versionIdrequired | integer | The version id. |
Request body
The full scale, in display order.
scalerequired | object[] |
Responses
200 | OK | Success.→ { data: object } |
400 | Bad Request | Every grade cannot fail, and two grades cannot share a name. |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X PUT https://api.aerscheduler.com/training/versions/:versionId/gradingScale \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"scale":[]}'/training/versions/{versionId}/lessonsCreate 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
versionIdrequired | integer | The version id. |
Request body
The lesson.
lessonId | integer | |
stageIdrequired | integer | |
namerequired | string | |
positionrequired | integer | |
kindrequired | "ground" | "flight" | "sim" | |
objectives | string | |
completionStandards | string | |
minFlightDeciHours | integer | Tenths of an hour. |
minGroundDeciHours | integer | Tenths of an hour. |
credits | object[] | Which requirements this lesson credits. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The version is published. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
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"}'/training/versions/{versionId}/publishPublish 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
versionIdrequired | integer | The version id. |
Request body
Optional FSDO approval details, for Part 141.
approvedAt | string | |
approvalReference | string |
Responses
200 | OK | Success.→ { data: object } |
400 | Bad Request | The version has no lessons. |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | Already published. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
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":"…"}'/training/versions/{versionId}/requirementsCreate 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
versionIdrequired | integer | The version id. |
Request body
The requirement.
requirementId | integer | |
coderequired | string | Stable machine key, e.g. "total_flight", "night", "cross_country". |
labelrequired | string | |
minDeciHours | integer | Tenths of an hour. |
minCount | integer | |
source | "part61" | "part141" | "school" | |
maxSimulatorBps | integer | Ceiling on simulator credit, in basis points. Appendix B allows 2000 (20%). |
maxTransferBps | integer | Ceiling on transferred credit, in basis points. §141.77 allows 5000 from an approved course, 2500 otherwise. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The version is published, or the code is already used. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X PUT https://api.aerscheduler.com/training/versions/:versionId/requirements \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"code":"…","label":"…"}'/training/versions/{versionId}/retireRetire a syllabus version
Stops new enrollments. Students already on it finish on it. Requires the admin role.
Path parameters
versionIdrequired | integer | The version id. |
Request body
Set retired false to un-retire.
retired | boolean |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X POST https://api.aerscheduler.com/training/versions/:versionId/retire \
-H "Authorization: Bearer $AERSCHEDULER_KEY" \
-H "Content-Type: application/json" \
-d '{"retired":true}'/training/versions/{versionId}/stagesCreate or update a stage
Omit stageId to create. Only works on a draft. Requires the admin role.
Path parameters
versionIdrequired | integer | The version id. |
Request body
The stage.
stageId | integer | |
namerequired | string | |
objective | string | |
positionrequired | integer | |
requiresStageCheck | boolean |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The version is published and cannot be changed. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
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}'/training/versions/{versionId}/lessons/{lessonId}Delete a lesson
Only works on a draft. Requires the admin role.
Path parameters
versionIdrequired | integer | The version id. |
lessonIdrequired | integer | The lesson id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The version is published. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X DELETE https://api.aerscheduler.com/training/versions/:versionId/lessons/:lessonId \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/versions/{versionId}/requirements/{requirementId}Delete a requirement
Only works on a draft. Requires the admin role.
Path parameters
versionIdrequired | integer | The version id. |
requirementIdrequired | integer | The requirement id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The version is published. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X DELETE https://api.aerscheduler.com/training/versions/:versionId/requirements/:requirementId \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/versions/{versionId}/stages/{stageId}Delete a stage
Only works on a draft. Requires the admin role.
Path parameters
versionIdrequired | integer | The version id. |
stageIdrequired | integer | The stage id. |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The version is published. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
curl -X DELETE https://api.aerscheduler.com/training/versions/:versionId/stages/:stageId \
-H "Authorization: Bearer $AERSCHEDULER_KEY"/training/versions/{versionId}/lessons/{lessonId}/tasksReplace 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
versionIdrequired | integer | The version id. |
lessonIdrequired | integer | The lesson id. |
Request body
The full task list.
tasksrequired | object[] |
Responses
200 | OK | Success.→ { data: object } |
401 | Unauthorized | No token, an expired token, or a malformed one. Sign in again. |
403 | Forbidden | Authenticated, but not allowed to do this. |
409 | The version is published. | |
429 | Too Many Requests | Rate limited. Retry-After says how long to wait. |
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":[]}'