Curriculum API Reference
Base path: /api/curriculum
The Curriculum API provides access to curriculum framework hierarchies (synced from the Central Curriculum API) and manages the attachment of curriculum metadata to H5P content items.
Endpoints
GET /api/curriculum/status
Check connectivity to the Central Curriculum (CC) API.
Auth: Authenticated user (JWT, authMiddleware)
The user's Bearer token is forwarded to the CC API for authentication.
Response (200):
{
"success": true,
"data": {
"connected": true
}
}
{
"success": true,
"data": {
"connected": false,
"error": "API request failed (401): Unauthorized"
}
}
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to check connection status | Internal error |
Sync Endpoints (Admin Only)
These endpoints fetch data from the Central Curriculum API and upsert it into the local PostgreSQL database. They require admin role (requireAdmin middleware).
POST /api/curriculum/sync/frameworks
Sync all frameworks from the Central Curriculum API. Performs upsert: existing frameworks are updated, new ones are inserted.
Auth: Admin (JWT, authMiddleware + requireAdmin)
Headers: Authorization: Bearer <keycloak-token> (required; forwarded to CC API)
Response (200):
{
"success": true,
"data": {
"synced": 5,
"errors": []
},
"message": "Synced 5 frameworks"
}
Errors:
| Status | Error | Cause |
|---|---|---|
| 401 | Bearer token required | Missing Authorization header |
| 403 | Admin access required | User role is not admin |
| 500 | Failed to sync frameworks | CC API unreachable or internal error |
POST /api/curriculum/sync/frameworks/:code
Sync a single framework with its complete hierarchy: stages, grades, subjects, units, topics, and learning objectives. Creates a sync log entry for auditing.
Auth: Admin (JWT, authMiddleware + requireAdmin)
Headers: Authorization: Bearer <keycloak-token> (required; forwarded to CC API)
URL Parameters:
| Param | Type | Description |
|---|---|---|
code | string | Framework code (e.g., TR-MEB-2024) |
Response (200):
{
"success": true,
"data": {
"stages": 3,
"grades": 12,
"subjects": 8,
"units": 45,
"topics": 180,
"objectives": 720,
"errors": []
},
"message": "Synced framework TR-MEB-2024"
}
The sync log entry status is set to completed if there are no errors, or completed_with_errors if some items failed to upsert.
Errors:
| Status | Error | Cause |
|---|---|---|
| 401 | Bearer token required | Missing Authorization header |
| 403 | Admin access required | User role is not admin |
| 500 | Failed to sync framework | CC API unreachable or internal error |
GET /api/curriculum/sync/history
Get recent sync log entries.
Auth: None (public endpoint)
Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
limit | integer | 10 | Number of entries to return |
Response (200):
{
"success": true,
"data": [
{
"id": 1,
"framework_code": "TR-MEB-2024",
"sync_type": "full",
"status": "completed",
"items_synced": 968,
"error_message": null,
"started_at": "2025-01-15T10:00:00.000Z",
"completed_at": "2025-01-15T10:02:30.000Z"
}
]
}
Sync log status values:
| Status | Meaning |
|---|---|
in_progress | Sync currently running |
completed | All items synced successfully |
completed_with_errors | Sync finished but some items failed |
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get sync history | Internal error |
Framework Hierarchy Endpoints (Public)
These endpoints read from the local database (populated by sync). No authentication is required.
GET /api/curriculum/frameworks
List all active curriculum frameworks.
Auth: None
Response (200):
{
"success": true,
"data": [
{
"code": "TR-MEB-2024",
"name": "MEB 2024 Curriculum",
"description": "Turkish Ministry of Education curriculum",
"framework_type": "national",
"country_code": "TR",
"organization": "MEB",
"version": "2024",
"language": "tr",
"valid_from": "2024-01-01",
"valid_until": null,
"is_active": true,
"is_published": true
}
]
}
Only frameworks with is_active = true are returned. Results are ordered by name.
Framework types: national, international, regional, enrichment
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get frameworks | Internal error |
GET /api/curriculum/frameworks/:code/stages
List stages (education levels) for a framework.
Auth: None
URL Parameters:
| Param | Type | Description |
|---|---|---|
code | string | Framework code |
Response (200):
{
"success": true,
"data": [
{
"framework_code": "TR-MEB-2024",
"code": "primary",
"name": "Primary Education",
"description": "Grades 1-4",
"age_start": 6,
"age_end": 10,
"sequence": 0
},
{
"framework_code": "TR-MEB-2024",
"code": "middle",
"name": "Middle School",
"description": "Grades 5-8",
"age_start": 10,
"age_end": 14,
"sequence": 1
}
]
}
Results are ordered by sequence.
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get stages | Internal error |
GET /api/curriculum/frameworks/:frameworkCode/stages/:stageCode/grades
List grade levels for a specific stage within a framework.
Auth: None
URL Parameters:
| Param | Type | Description |
|---|---|---|
frameworkCode | string | Framework code |
stageCode | string | Stage code |
Response (200):
{
"success": true,
"data": [
{
"framework_code": "TR-MEB-2024",
"stage_code": "middle",
"code": "grade-5",
"name": "5th Grade",
"typical_age": 10,
"sequence": 0
}
]
}
Results are ordered by sequence.
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get grades | Internal error |
GET /api/curriculum/frameworks/:code/subjects
List subjects for a framework.
Auth: None
URL Parameters:
| Param | Type | Description |
|---|---|---|
code | string | Framework code |
Response (200):
{
"success": true,
"data": [
{
"framework_code": "TR-MEB-2024",
"code": "math",
"name": "Mathematics",
"description": "Mathematics curriculum",
"icon": "calculator",
"color": "#2196F3",
"is_core": true,
"sequence": 0
}
]
}
Results are ordered by sequence.
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get subjects | Internal error |
GET /api/curriculum/frameworks/:frameworkCode/subjects/:subjectCode/grades/:gradeCode/units
List units for a specific subject and grade combination.
Auth: None
URL Parameters:
| Param | Type | Description |
|---|---|---|
frameworkCode | string | Framework code |
subjectCode | string | Subject code |
gradeCode | string | Grade code |
Response (200):
{
"success": true,
"data": [
{
"framework_code": "TR-MEB-2024",
"subject_code": "math",
"grade_code": "grade-8",
"code": "unit-1",
"name": "Numbers and Operations",
"description": "Fundamental number concepts",
"estimated_hours": 20,
"sequence": 0
}
]
}
Results are ordered by sequence.
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get units | Internal error |
GET /api/curriculum/frameworks/:frameworkCode/subjects/:subjectCode/grades/:gradeCode/units/:unitCode/topics
List topics within a unit.
Auth: None
URL Parameters:
| Param | Type | Description |
|---|---|---|
frameworkCode | string | Framework code |
subjectCode | string | Subject code |
gradeCode | string | Grade code |
unitCode | string | Unit code |
Response (200):
{
"success": true,
"data": [
{
"framework_code": "TR-MEB-2024",
"subject_code": "math",
"grade_code": "grade-8",
"unit_code": "unit-1",
"code": "topic-1",
"name": "Integer Operations",
"description": "Addition, subtraction, multiplication of integers",
"base_difficulty": 0.5,
"estimated_minutes": 45,
"sequence": 0
}
]
}
Results are ordered by sequence.
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get topics | Internal error |
GET /api/curriculum/frameworks/:frameworkCode/subjects/:subjectCode/grades/:gradeCode/units/:unitCode/topics/:topicCode/objectives
List learning objectives for a topic.
Auth: None
URL Parameters:
| Param | Type | Description |
|---|---|---|
frameworkCode | string | Framework code |
subjectCode | string | Subject code |
gradeCode | string | Grade code |
unitCode | string | Unit code |
topicCode | string | Topic code |
Response (200):
{
"success": true,
"data": [
{
"framework_code": "TR-MEB-2024",
"subject_code": "math",
"grade_code": "grade-8",
"unit_code": "unit-1",
"topic_code": "topic-1",
"code": "obj-1",
"objective": "Students can add and subtract integers fluently",
"bloom_level": "apply",
"mastery_threshold": 0.7,
"sequence": 0
}
]
}
Results are ordered by sequence.
Bloom's levels: remember, understand, apply, analyze, evaluate, create
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get objectives | Internal error |
Content Metadata Endpoints
These endpoints link H5P content to curriculum frameworks.
POST /api/curriculum/content/:contentId/metadata
Save or update curriculum metadata for an H5P content item. Uses upsert: if metadata already exists for the content ID, it is replaced.
Auth: Authenticated user (JWT, authMiddleware)
URL Parameters:
| Param | Type | Description |
|---|---|---|
contentId | string | H5P content ID |
Request Body:
{
"frameworkCode": "TR-MEB-2024",
"frameworkName": "MEB 2024 Curriculum",
"countryCode": "TR",
"stageCode": "middle",
"stageName": "Middle School",
"gradeCode": "grade-8",
"gradeName": "8th Grade",
"subjectCode": "math",
"subjectName": "Mathematics",
"topicCodes": ["topic-1", "topic-2"],
"topicNames": ["Integer Operations", "Fractions"],
"objectiveCodes": ["obj-1", "obj-2"],
"objectiveDescriptions": [
"Students can add and subtract integers",
"Students can multiply fractions"
],
"difficulty": "medium",
"language": "tr"
}
| Field | Type | Required | Constraints |
|---|---|---|---|
frameworkCode | string | Yes | max 100 chars |
frameworkName | string | Yes | max 255 chars |
countryCode | string | Yes | max 10 chars |
stageCode | string | No | max 100 chars |
stageName | string | No | max 255 chars |
gradeCode | string | Yes | max 100 chars |
gradeName | string | Yes | max 255 chars |
subjectCode | string | Yes | max 100 chars |
subjectName | string | Yes | max 255 chars |
topicCodes | string[] | No | max 50 items, each max 100 chars; default [] |
topicNames | string[] | No | max 50 items, each max 255 chars; default [] |
objectiveCodes | string[] | No | max 200 items, each max 100 chars; default [] |
objectiveDescriptions | string[] | No | max 200 items, each max 500 chars; default [] |
difficulty | string | No | max 50 chars; default "medium" |
language | string | No | max 10 chars; default "en" |
Response (200):
{
"success": true,
"message": "Content curriculum metadata saved"
}
Errors:
| Status | Error | Cause |
|---|---|---|
| 400 | Validation error: ... | Invalid request body |
| 500 | Failed to save metadata | Internal error |
GET /api/curriculum/content/:contentId/metadata
Get curriculum metadata for an H5P content item.
Auth: None (public endpoint)
URL Parameters:
| Param | Type | Description |
|---|---|---|
contentId | string | H5P content ID |
Response (200):
{
"success": true,
"data": {
"content_id": "42",
"framework_code": "TR-MEB-2024",
"framework_name": "MEB 2024 Curriculum",
"country_code": "TR",
"stage_code": "middle",
"stage_name": "Middle School",
"grade_code": "grade-8",
"grade_name": "8th Grade",
"subject_code": "math",
"subject_name": "Mathematics",
"topic_codes": ["topic-1"],
"topic_names": ["Integer Operations"],
"objective_codes": ["obj-1"],
"objective_descriptions": ["Students can add and subtract integers"],
"difficulty": "medium",
"language": "tr",
"created_at": "2025-01-15T10:00:00.000Z",
"updated_at": "2025-01-15T10:00:00.000Z"
}
}
Returns null in data if no metadata exists for the content ID.
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to get metadata | Internal error |
DELETE /api/curriculum/content/:contentId/metadata
Delete curriculum metadata for an H5P content item.
Auth: Authenticated user (JWT, authMiddleware)
URL Parameters:
| Param | Type | Description |
|---|---|---|
contentId | string | H5P content ID |
Response (200):
{
"success": true,
"message": "Content curriculum metadata deleted"
}
Errors:
| Status | Error | Cause |
|---|---|---|
| 500 | Failed to delete metadata | Internal error |
Data Model
Curriculum Hierarchy
The curriculum data follows a strict hierarchy:
Framework
-> Stage (education level, e.g., Primary, Middle School)
-> Grade (e.g., 5th Grade, 8th Grade)
-> Subject (e.g., Mathematics, Science)
-> Unit (per subject + grade combination)
-> Topic (specific learning area)
-> Learning Objective (with Bloom's level)
Framework
| Field | Type | Description |
|---|---|---|
code | string (PK) | Unique framework identifier |
name | string | Display name |
description | string | Framework description |
framework_type | enum | national, international, regional, enrichment |
country_code | string | ISO country code |
organization | string | Publishing organization |
version | string | Version identifier |
language | string | Primary language |
valid_from | date | Effective start date |
valid_until | date | Effective end date (null if current) |
is_active | boolean | Whether framework is active |
is_published | boolean | Whether framework is published |
Learning Objective
| Field | Type | Description |
|---|---|---|
code | string | Unique code within topic scope |
objective | string | Objective description text |
bloom_level | enum | remember, understand, apply, analyze, evaluate, create |
mastery_threshold | decimal | Required mastery score (0.0-1.0, default 0.7) |
sequence | integer | Display order |
Content Curriculum Metadata
| Field | Type | Description |
|---|---|---|
content_id | string (PK) | H5P content ID |
framework_code | string | Framework code |
framework_name | string | Framework display name |
country_code | string | ISO country code |
stage_code | string | Stage code (optional) |
stage_name | string | Stage display name (optional) |
grade_code | string | Grade code |
grade_name | string | Grade display name |
subject_code | string | Subject code |
subject_name | string | Subject display name |
topic_codes | string[] | Associated topic codes |
topic_names | string[] | Associated topic display names |
objective_codes | string[] | Associated objective codes |
objective_descriptions | string[] | Associated objective descriptions |
difficulty | string | Difficulty level (default "medium") |
language | string | Language code (default "en") |
created_at | timestamp | Creation timestamp |
updated_at | timestamp | Last update timestamp |