Endpoint reference
All paths are relative to https://<your-api-host>/api/v2, and every request needs an Authorization header — see Authentication.
| Method | Path | Purpose |
|---|---|---|
GET | /v2/public/courses | Every public course, with its next class |
GET | /v2/public/popular | The three most-registered courses |
GET | /v2/public/classes | Paginated, filterable class search |
GET | /v2/public/course/{id}/classes | The same search, scoped to one course |
GET | /v2/public/course/{id} | A single course |
GET | /v2/public/class/{id} | A single class, in full |
List public courses
GET /v2/public/courses
Every public course, alphabetically by name, each with a summary of its next upcoming public class. Designed to render a course catalogue page in one request.
Query parameters
| Name | Type | Description |
|---|---|---|
type | string or array | Restrict to one or more course types. Repeat the key for several: ?type[]=Online&type[]=Blended. Must be Online, Brick and Mortar, or Blended. |
This endpoint is not paginated — it returns the full catalogue. limit and page are ignored if sent.
Response 200
{
"data": [
{
"id": 12,
"name": "Basic Safety Training",
"upcoming_class": {
"start": "2026-10-06",
"end": "2026-10-10",
"type": "Brick and Mortar",
"city": "Norfolk",
"state": "VA",
"cost": 129500,
"available_seats": 4
}
},
{
"id": 19,
"name": "Radar Observer Recertification",
"upcoming_class": null
}
]
}
upcoming_class is null when a course has no upcoming public class — render the course without a "next date" rather than hiding it.
Example
curl -H "Authorization: Bearer $TOKEN" \
"$API_BASE/v2/public/courses?type[]=Online&type[]=Blended"
Popular courses
GET /v2/public/popular
The three courses with the most registrations of all time, each with its next upcoming public class. Intended for a homepage "most popular" strip.
Takes no parameters.
This response is a bare JSON array, not an object with a data key.
Response 200
[
{
"id": 12,
"name": "Basic Safety Training",
"upcoming_class": {
"id": 340,
"cost": 129500,
"start": "2026-10-06",
"end": "2026-10-10",
"available_seats": 4
}
}
]
The upcoming_class shape here differs from /v2/public/courses: it carries the class id (so you can link straight to it) but no location or type.
Search classes
GET /v2/public/classes
Paginated search across every upcoming public class. This is the endpoint behind a "find a class" page.
Results are ordered by start date ascending. Classes in the past are excluded, except for online courses, which have no fixed sitting and are always included.
Query parameters
| Name | Type | Default | Description |
|---|---|---|---|
search | string | — | Case-insensitive partial match on the course name. |
start | MM-DD-YYYY | — | Only classes starting on or after this date. |
end | MM-DD-YYYY | — | Only classes starting on or before this date. |
date | MM-DD-YYYY | — | Only classes running on this date (start ≤ date ≤ end). |
limit | integer ≤ 50 | 25 | Results per page. |
page | integer | 1 | Page number. |
Date filters use MM-DD-YYYY, unlike the YYYY-MM-DD dates in responses.
The literal string invalid date is accepted and ignored for start, end, and date, which lets a front-end pass a half-filled date picker straight through. Any other unparseable value raises a 500.
Response 200
{
"data": [
{
"id": "340",
"course_id": "12",
"course": "Basic Safety Training",
"start": "2026-10-06",
"end": "2026-10-10",
"type": "Brick and Mortar",
"city": "Norfolk",
"state": "VA",
"schedule": null,
"cost": 129500,
"full": false,
"available_seats": 4
}
],
"total": 87,
"last_page": 4
}
| Field | Notes |
|---|---|
id, course_id | Returned as strings here, and as integers elsewhere. Compare loosely or cast. |
city, state | null for online classes and for classes with no room assigned yet. |
schedule | Not populated in search results. Use Get a class for the schedule text. |
full | true only when a capped class has no seats left. An uncapped class is never full. |
available_seats | null when uncapped. See Seat counts. |
total, last_page | Pagination metadata, alongside data rather than nested. |
Example
curl -H "Authorization: Bearer $TOKEN" \
"$API_BASE/v2/public/classes?search=safety&start=10-01-2026&end=12-31-2026&limit=10&page=1"
Search a course's classes
GET /v2/public/course/{id}/classes
Identical to Search classes — same parameters, same response shape — but restricted to one course. Use it for a course detail page's list of sittings.
curl -H "Authorization: Bearer $TOKEN" \
"$API_BASE/v2/public/course/12/classes?limit=50"
A course that is not public returns an empty result set rather than a 404.
Get a course
GET /v2/public/course/{id}
Response 200
{
"id": 12,
"name": "Basic Safety Training",
"type": "Brick and Mortar",
"description": "<p>A five-day STCW course covering...</p>"
}
description may contain HTML authored in the AnchorPoint admin. Sanitise it before rendering it into your page.
Returns 404 if the course does not exist or is not public.
Get a class
GET /v2/public/class/{id}
Full detail for a single class — the endpoint behind a "class details" page or a registration call-to-action.
Response 200
{
"course_id": 12,
"course_name": "Basic Safety Training",
"course_type": "Brick and Mortar",
"start": "2026-10-06",
"end": "2026-10-10",
"schedule": "Mon-Fri, 08:00-16:30",
"cost": 129500,
"can_register": true,
"location": {
"name": "Norfolk Training Center",
"room": "Classroom B",
"city": "Norfolk",
"state": "VA",
"zip": "23510",
"country": "US"
},
"down_payment": "25000",
"registration_id": null,
"prev_reg_test_date": null,
"open_seats": 4
}
| Field | Notes |
|---|---|
schedule | Free-text schedule description entered by staff. May be null. |
can_register | Whether registration is open: seats remain and the class has not started. Always true for online courses. |
location | An object for in-person classes. For online courses it is the literal string "online" — check the type before reading properties. Fields are null when no room has been assigned yet. |
down_payment | Cents, but returned as a string ("25000") because of the underlying column type. null if the class requires payment in full. Cast before doing arithmetic. |
open_seats | null when uncapped. |
registration_id and prev_reg_test_date are personalisation fields resolved from the signed-in user. With an API token there is no user, so they are always null. can_register likewise reflects only class-level availability, not whether a particular person is eligible. If you need per-student state, the caller must authenticate with a JWT instead.
Returns 404 if the class does not exist, is not public, or belongs to a non-public course.