For the complete documentation index, see llms.txt. This page is also available as Markdown.

Conventions

The response envelope, pagination, filtering, sorting and embedded relationships — the rules every endpoint follows.

Every endpoint follows the same conventions, so once you can read one response you can read them all.

Base URL

https://api.masteryconnect.com

Path prefix

/api/v2

Methods

GET only

Content type

application/json

Envelope

JSON:API-shaped

Timestamps

ISO 8601, UTC (2026-09-01T14:32:07.000Z)

Ids

Strings in data.id, integers in filter parameters

Response Envelope

A Single Resource

GET /api/v2/sections/4321

{
  "data": {
    "id": "4321",
    "type": "section",
    "attributes": {
      "name": "Period 3 Biology",
      "archived": false,
      "course_number": "BIO-101",
      "created_at": "2026-08-14T09:12:44.000Z",
      "updated_at": "2026-08-28T16:03:11.000Z"
    },
    "relationships": {
      "school": { "data": { "id": "5678", "type": "school" } }
    }
  }
}

A Collection

Collections add meta and links. Note that data is an array, and each entry has the same shape as a single resource.

Members

Member
Present on
Contains

data

Always

The resource, or an array of them.

data.id

Always

The id, as a string.

data.type

Always

The resource type, singular (section, material).

data.attributes

Always

The resource's own fields.

data.relationships

When the resource has related records

Linkage only — ids and types, not the related objects.

meta

Collections

Pagination counts.

links

Collections

Pagination URLs.

Pagination

Every collection is paginated.

Parameter
Default
Maximum
Meaning

page[number]

1

—

1-based page number.

page[size]

25

100

Records per page.

Out-of-range values are rejected rather than clamped: page[size]=500 returns 422, not a page of 100. A page[number] beyond the last page returns 200 with an empty data array.

Paging Correctly

Follow links.next until it is absent, rather than incrementing a counter and guessing when to stop:

links.next is omitted on the last page; first and last are always present.

Always request page[size]=100 for bulk reads. It is the same rate limit cost as page[size]=25 but returns four times the data.

Pagination Is Not a Snapshot

Paging is offset-based against live data. If records are created or deleted while you page, a record can appear twice across pages or be skipped. For a consistent extract, sort by a stable column (sort=created_at) and de-duplicate by id as you go.

Filtering

Filters use filter[key]=value. Each endpoint allows a specific set of keys.

Multiple filters combine with AND. Each key takes a single value — there is no IN, no range and no negation.

Allowed Filters

Endpoint
Filters

/districts

—

/districts/{id}/schools

nces_school_id

/sections

school_id, archived

/classrooms

school_id, teacher_id, archived

/teachers

school_id

/materials

subject_id, objective_id, draft, available, updated_since

/banks

bank_type, name

/curriculum_maps

privacy_level

/class_objectives

available, class_objective_type

/pathways

available, subject_id

/reports/{report_name}

Per report — see Reports

Nested collections (/banks/{id}/questions, /materials/{id}/items, /curriculum_maps/{id}/objectives, /classrooms/{id}/objectives, /trackers/{id}/assessments) are already scoped by their parent and accept no filters of their own.

/teachers intentionally has no name filter — a teacher's name is assembled from several columns, so there is no single column to match on.

Filtering by Modification Time

filter[updated_since] takes a full ISO 8601 datetime and returns records modified at or after it — the basis of an incremental sync:

updated_since is currently supported on /materials only. Other resources either have no modification timestamp or have not yet opted in; sending it elsewhere is a 422. A value that is not a complete ISO 8601 datetime is also a 422 rather than being ignored, so a malformed timestamp cannot silently return your whole dataset.

Sorting

sort takes a comma-separated list of columns. Prefix a column with - for descending.

Like filters, sort columns are allow-listed; an unknown column is a 422.

Endpoint
Sortable columns

/districts/{id}/schools

name, created_at

/sections

name, created_at

/classrooms

title, created_at

/classrooms/{id}/objectives

name, created_at

/teachers

last_name, created_at

/materials

title, created_at, updated_at

/materials/{id}/items

id

/banks

name, created_at

/banks/{id}/questions

created_at

/banks/{id}/passages

created_at

/curriculum_maps

title, created_at, updated_at

/curriculum_maps/{id}/materials

title, created_at, updated_at

/curriculum_maps/{id}/objectives

name, created_at, updated_at

/class_objectives

name

/pathways

name

Relationships and Embeds

Related data appears in two different places, and the difference matters.

relationships — Linkage Only

relationships gives you ids and types, never the related object:

To resolve one, call its own endpoint. A to-one relationship with no record is { "data": null }.

Some resources also render related objects inside attributes, so you get them without a second request. A material, for example, embeds its objective, subject and teacher:

Note that objective appears in both places — embedded under attributes and as linkage under relationships. That is expected; they are independent.

Embeds are fixed by the API, not requested by you. There is no include or fields parameter — which relationships are embedded is decided per resource, and you get the same shape on every call.

Two rules govern which embeds you see:

  • To-one embeds (a material's teacher) appear on both single-resource and collection responses.

  • To-many embeds (a material's items) appear only on single-resource responses. Embedding them in a collection would multiply the payload by the page size, so collections omit them.

So if you need every material's items, list the materials and then fetch each one — or use /materials/{id}/items, which pages properly. To-many embeds are also count-capped, so a resource with hundreds of children will not return all of them inline; page the nested route when you need the full set.

Next

Last updated

Was this helpful?