Curriculum API
The Curriculum API manages the learning content hierarchy that lives under courses: Units group lessons, Lessons place resources at positions within units, and Resources are the actual content items (videos, QTI assessments, articles, etc.). The hierarchy is Course → Unit → Lesson → Resource.
All endpoints use the same /rostering/1.0 prefix as the Rostering API — rostering and curriculum paths are disjoint with no conflicts. All endpoints require Authorization: Bearer <token>.
Base prefix: https://api.alpha-1edtech.ai/rostering/1.0
GET /rostering/1.0/units
Returns a paginated list of all units (across all your courses). Supports filter/sort/search.
Scope: roster.readonly
Query params
| Name | Description | Required |
|---|---|---|
limit | Maximum records per page (default 100, max 1000) | no |
offset | Number of records to skip (default 0) | no |
filter | OneRoster filter expression | no |
sort | Field to sort by | no |
orderBy | Sort direction: asc or desc | no |
search | Free-text search term | no |
fields | Comma-separated list of fields to include | no |
Response
200 OK — { "units": [...], "offset": 0, "limit": 100, "total": N }
Each unit includes: sourcedId, title, course, parent, sortOrder, prerequisites.
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/units" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /rostering/1.0/units/:sourcedId
Returns a single unit by its sourcedId.
Scope: roster.readonly
Path params
| Name | Description |
|---|---|
sourcedId | Unit UUID |
Response
200 OK — { "unit": { ... } }. 404 if not found.
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/units/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
PUT /rostering/1.0/units/:sourcedId
Create or update a Unit under a Course.
Unit is an Alpha extension following OneRoster conventions. The curriculum hierarchy is Course -> Unit -> Lesson -> Resource.
Required fields: sourcedId, status, dateLastModified, title, course.
Create the parent Course first, then PUT Units referencing it.
Scope: roster.createput
Path params
| Name | Description |
|---|---|
sourcedId | Unit UUID (must match body) |
Request body
Wrapped as { "unit": { ... } }.
| Field | Type | Required | Description |
|---|---|---|---|
sourcedId | string (UUID) | yes | Must match the URL path parameter |
dateLastModified | string (ISO 8601) | yes | Timestamp |
title | string | yes | Display name (e.g., "Fractions Unit 1") |
course | { sourcedId } | yes | Parent course reference |
parent | { sourcedId } or null | no | Parent unit reference (null for root-level units) |
sortOrder | integer | no | Order among siblings (default 0) |
prerequisites | string[] | no | sourcedIds this unit depends on (pass-through only) |
metadata | object | no | Stored as extensions on GET |
Response
201 Created or 200 OK — { "status": "...", "sourcedId": "..." }
Example
curl -X PUT "https://api.alpha-1edtech.ai/rostering/1.0/units/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"unit": {
"sourcedId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"dateLastModified": "2026-01-15T00:00:00.000Z",
"title": "Fractions Unit 1",
"course": { "sourcedId": "44444444-4444-4444-4444-444444444444" },
"sortOrder": 1
}
}'
DELETE /rostering/1.0/units/:sourcedId
Soft-deletes the unit by setting its status to 'tobedeleted'. Ownership enforced.
Scope: roster.createput
Path params
| Name | Description |
|---|---|
sourcedId | Unit UUID |
Response
204 No Content on success. 403 — ownership violation. 404 — not found.
Example
curl -X DELETE "https://api.alpha-1edtech.ai/rostering/1.0/units/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /rostering/1.0/courses/:sourcedId/units
Returns root-level units belonging to a course.
Scope: roster.readonly
Path params
| Name | Description |
|---|---|
sourcedId | Course UUID |
Query params
Standard pagination query params.
Response
200 OK — { "units": [...], "offset": 0, "limit": 100, "total": N }
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/courses/44444444-4444-4444-4444-444444444444/units" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /rostering/1.0/units/:sourcedId/units
Returns sub-units of the given unit.
Scope: roster.readonly
Path params
| Name | Description |
|---|---|
sourcedId | Parent Unit UUID |
Query params
Standard pagination query params.
Response
200 OK — { "units": [...], "offset": 0, "limit": 100, "total": N }
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/units/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/units" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /rostering/1.0/units/:sourcedId/lessons
Returns lessons belonging to a unit.
Scope: roster.readonly
Path params
| Name | Description |
|---|---|
sourcedId | Unit UUID |
Query params
Standard pagination query params.
Response
200 OK — { "lessons": [...], "offset": 0, "limit": 100, "total": N }
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/units/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/lessons" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /rostering/1.0/lessons
Returns a paginated list of all lessons. Supports filter/sort/search.
Scope: roster.readonly
Query params
Standard pagination query params.
Response
200 OK — { "lessons": [...], "offset": 0, "limit": 100, "total": N }
Each lesson includes: sourcedId, title, unit, resource, sortOrder, lessonType.
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/lessons" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /rostering/1.0/lessons/:sourcedId
Returns a single lesson by its sourcedId.
Scope: roster.readonly
Path params
| Name | Description |
|---|---|
sourcedId | Lesson UUID |
Response
200 OK — { "lesson": { ... } }. 404 if not found.
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/lessons/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
PUT /rostering/1.0/lessons/:sourcedId
Create or update a Lesson — the placement of a Resource in a Unit.
Required fields: sourcedId, status, dateLastModified, title, unit, resource.
Create the Unit and Resource first, then PUT the Lesson linking them.
Scope: roster.createput
Path params
| Name | Description |
|---|---|
sourcedId | Lesson UUID (must match body) |
Request body
Wrapped as { "lesson": { ... } }.
| Field | Type | Required | Description |
|---|---|---|---|
sourcedId | string (UUID) | yes | Must match the URL path parameter |
dateLastModified | string (ISO 8601) | yes | Timestamp |
title | string | yes | Display name |
unit | { sourcedId } | yes | Parent unit reference |
resource | { sourcedId } | yes | The resource this lesson places in the curriculum |
sortOrder | integer | no | Order within the unit (default 0) |
lessonType | string | no | One of: powerpath-100, quiz, test-out, placement, unit-test, alpha-read-article |
metadata | object | no | Stored as extensions on GET |
Response
201 Created or 200 OK — { "status": "...", "sourcedId": "..." }
Example
curl -X PUT "https://api.alpha-1edtech.ai/rostering/1.0/lessons/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"lesson": {
"sourcedId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
"dateLastModified": "2026-01-15T00:00:00.000Z",
"title": "Introduction to Fractions",
"unit": { "sourcedId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" },
"resource": { "sourcedId": "cccccccc-cccc-cccc-cccc-cccccccccccc" },
"sortOrder": 1,
"lessonType": "quiz"
}
}'
DELETE /rostering/1.0/lessons/:sourcedId
Soft-deletes the lesson. Ownership enforced.
Scope: roster.createput
Path params
| Name | Description |
|---|---|
sourcedId | Lesson UUID |
Response
204 No Content on success. 403 — ownership violation. 404 — not found.
Example
curl -X DELETE "https://api.alpha-1edtech.ai/rostering/1.0/lessons/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /rostering/1.0/resources
Returns a paginated list of all resources. Supports filter/sort/search.
Scope: roster.readonly
Query params
Standard pagination query params.
Response
200 OK — { "resources": [...], "offset": 0, "limit": 100, "total": N }
Each resource includes: sourcedId, title, type, url, vendorResourceId, learningObjectiveSet.
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/resources" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /rostering/1.0/resources/:sourcedId
Returns a single resource by its sourcedId with synthesized metadata (url, description, learningObjectiveSet promoted to top-level).
Scope: roster.readonly
Path params
| Name | Description |
|---|---|
sourcedId | Resource UUID |
Response
200 OK — { "resource": { ... } }. 404 if not found.
Example
curl "https://api.alpha-1edtech.ai/rostering/1.0/resources/cccccccc-cccc-cccc-cccc-cccccccccccc" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
PUT /rostering/1.0/resources/:sourcedId
Create or update a Resource (content item).
Required fields: sourcedId, status, dateLastModified, title, vendorResourceId, url, learningObjectiveSet.
Each learningObjectiveId is validated against the standards tables. Invalid IDs return 400 with an invalidIds array.
Workflow: (1) GET /standards/1.0/frameworks to find a framework, (2) GET /standards/1.0/frameworks/{id}/package to browse objectives, (3) submit objective sourcedIds here with source='CASE'.
Scope: roster.createput
Path params
| Name | Description |
|---|---|
sourcedId | Resource UUID (must match body) |
Request body
Wrapped as { "resource": { ... } }.
| Field | Type | Required | Description |
|---|---|---|---|
sourcedId | string (UUID) | yes | Must match the URL path parameter |
dateLastModified | string (ISO 8601) | yes | Timestamp |
title | string | yes | Display name |
type | string | yes | Content type: qti, text, audio, video, interactive, visual, course-material, assessment-bank |
url | string (URL) | yes | Where students access this content |
learningObjectiveSet | array | yes | At least one entry: { "source": "CASE", "learningObjectiveIds": ["..."] } |
vendorResourceId | string | no | Your internal ID (defaults to sourcedId if omitted) |
subType | string | no | Required when type is qti or course-material |
format | string | no | Required when type is text, audio, video, or visual (e.g., "mp4", "html") |
description | string | no | Human-readable description |
roles | string[] | no | ["primary"], ["secondary"], etc. |
metadata | object | no | Stored as extensions on GET |
Response
201 Created or 200 OK — { "status": "...", "sourcedId": "..." }
400 Bad Request — validation error including invalidIds array for bad objective IDs.
Example
curl -X PUT "https://api.alpha-1edtech.ai/rostering/1.0/resources/cccccccc-cccc-cccc-cccc-cccccccccccc" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"resource": {
"sourcedId": "cccccccc-cccc-cccc-cccc-cccccccccccc",
"dateLastModified": "2026-01-15T00:00:00.000Z",
"title": "Fractions Quiz 1",
"type": "qti",
"subType": "qti-test",
"url": "https://vendor.example.com/assessments/fractions-quiz-1",
"learningObjectiveSet": [
{ "source": "CASE", "learningObjectiveIds": ["OBJECTIVE_SOURCED_ID"] }
]
}
}'
DELETE /rostering/1.0/resources/:sourcedId
Soft-deletes the resource. Ownership enforced.
Scope: roster.createput
Path params
| Name | Description |
|---|---|
sourcedId | Resource UUID |
Response
204 No Content on success. 403 — ownership violation. 404 — not found.
Example
curl -X DELETE "https://api.alpha-1edtech.ai/rostering/1.0/resources/cccccccc-cccc-cccc-cccc-cccccccccccc" \
-H "Authorization: Bearer <ACCESS_TOKEN>"