Technical Documentation
Document 04 of 12

API Design & Contracts

Dev Team March 2026 Grio AI Education Platform

Grio AI Education Platform — API Design & Contracts

Document Version: 1.0 Last Updated: 2026-03-24 Audience: Development Team (Internal) Status: Approved for Implementation


1. API Design Principles

1.1 RESTful API Design

1.2 JSON Request/Response Format

1.3 JWT Bearer Token Authentication

1.4 Consistent Error Response Format

All errors follow this standardized structure:

{
  "error": {
    "code": "ERROR_CODE_CONSTANT",
    "message": "Human-readable error message",
    "details": {
      "field": ["specific error about this field"],
      "nested_field": ["error details"]
    }
  }
}

1.5 Versioning Strategy

1.6 Pagination Patterns

{
  "data": [...],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 150,
    "has_next": true,
    "has_previous": false
  }
}

2. Authentication & Authorization

2.1 POST /api/v1/auth/login/

Description: Authenticate user and return JWT token pair Authentication: None (public endpoint) Rate Limit: 5 requests per minute per IP

Request:

{
  "email": "teacher@school.example.com",
  "password": "SecurePassword123!",
  "remember_me": false
}

Response (200 OK):

{
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
      "id": 42,
      "email": "teacher@school.example.com",
      "first_name": "John",
      "last_name": "Doe",
      "role": "TEACHER",
      "school_id": 5,
      "school_name": "St. Mary's Academy",
      "avatar_url": "https://cdn.grio.ai/avatars/42.jpg"
    },
    "expires_in": 900
  }
}

Errors: - INVALID_CREDENTIALS (401): Email or password incorrect - ACCOUNT_DISABLED (403): User account is disabled - EMAIL_NOT_VERIFIED (403): Email verification required

2.2 POST /api/v1/auth/refresh/

Description: Refresh expired access token Authentication: Refresh token required

Request:

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response (200 OK):

{
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_in": 900
  }
}

2.3 GET /api/v1/auth/me/

Description: Fetch current authenticated user profile Authentication: Bearer token required

Response (200 OK):

{
  "data": {
    "id": 42,
    "email": "teacher@school.example.com",
    "first_name": "John",
    "last_name": "Doe",
    "role": "TEACHER",
    "school_id": 5,
    "permissions": ["view_class", "create_assignment", "view_analytics"],
    "created_at": "2025-09-15T08:30:00Z",
    "last_login": "2026-03-24T14:22:15Z"
  }
}

2.4 Role-Based Access Control (RBAC)

Roles and default permissions:

RoleEndpoints AccessFeatures
Super AdminAll /api/admin/Manage schools, users, analytics
School Admin/api/admin/school/*, /api/teachers/, /api/students/Manage school users, view reports
Teacher/api/sessions/, /api/teachers/me/*, /api/ai/Manage classes, create assignments, AI tutoring
Student/api/students/me/*, /api/sessions/, /api/ai/chat/Dashboard, learning history, AI chat
Independent Learner/api/students/me/*, /api/sessions/, /api/ai/chat/Same as Student, no school affiliation

3. Curriculum API

3.1 GET /api/v1/curricula/

Description: List all available curricula frameworks Authentication: Bearer token required

Query Parameters: - country (optional): Filter by country code (UG, ZM, KE) - active_only (default true): Include only active curricula

Response (200 OK):

{
  "data": [
    {
      "id": 1,
      "name": "Uganda National Curriculum Development Centre (NCDC)",
      "country": "UG",
      "short_code": "NCDC",
      "description": "Official Ugandan primary and secondary curriculum",
      "grades": ["P1", "P2", "P3", "P4", "P5", "P6", "P7", "S1", "S2", "S3", "S4", "S5", "S6"],
      "is_active": true,
      "created_at": "2025-01-01T00:00:00Z"
    },
    {
      "id": 2,
      "name": "Zambia Education Curriculum Framework (ZEC)",
      "country": "ZM",
      "short_code": "ZEC",
      "grades": ["Grade1", "Grade2", "Grade3", "Grade4", "Grade5", "Grade6", "Grade7", "Grade8", "Grade9", "Grade10", "Grade11", "Grade12"],
      "is_active": true,
      "created_at": "2025-01-05T00:00:00Z"
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 2,
    "has_next": false,
    "has_previous": false
  }
}

3.2 GET /api/v1/classes/

Description: List classes for a given curriculum Query Parameters: - curriculum_id (required): Curriculum ID - grade (optional): Filter by grade level

Response (200 OK):

{
  "data": [
    {
      "id": 10,
      "curriculum_id": 1,
      "grade": "P6",
      "name": "Primary 6",
      "description": "Primary education, Level 6"
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 1,
    "has_next": false,
    "has_previous": false
  }
}

3.3 GET /api/v1/subjects/

Description: List subjects for a given class Query Parameters: - class_id (required): Class ID

Response (200 OK):

{
  "data": [
    {
      "id": 101,
      "class_id": 10,
      "name": "English Language",
      "code": "ENG",
      "description": "English language and literature"
    },
    {
      "id": 102,
      "class_id": 10,
      "name": "Mathematics",
      "code": "MATH",
      "description": "Mathematics fundamentals"
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 2,
    "has_next": false,
    "has_previous": false
  }
}

3.4 GET /api/v1/topics/

Description: List topics for a class-subject-term combination Query Parameters: - class_subject_id (required): Class-subject ID - term_id (optional): Term ID (1, 2, 3) — defaults to current term

Response (200 OK):

{
  "data": [
    {
      "id": 501,
      "class_subject_id": 101,
      "term_id": 1,
      "name": "Introduction to Grammar",
      "description": "Parts of speech, sentence structure",
      "order": 1,
      "lesson_count": 5
    },
    {
      "id": 502,
      "class_subject_id": 101,
      "term_id": 1,
      "name": "Reading Comprehension",
      "description": "Strategies for understanding texts",
      "order": 2,
      "lesson_count": 4
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 2,
    "has_next": false,
    "has_previous": false
  }
}

3.5 GET /api/v1/lessons/

Description: List lessons within a topic Query Parameters: - topic_id (required): Topic ID

Response (200 OK):

{
  "data": [
    {
      "id": 2001,
      "topic_id": 501,
      "title": "Parts of Speech Overview",
      "order": 1,
      "duration_minutes": 30,
      "has_quiz": true,
      "has_video": true
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 1,
    "has_next": false,
    "has_previous": false
  }
}

3.6 GET /api/v1/lessons/{id}/content/

Description: Retrieve full lesson content including text, videos, quizzes Authentication: Bearer token required

Response (200 OK):

{
  "data": {
    "id": 2001,
    "title": "Parts of Speech Overview",
    "content_blocks": [
      {
        "type": "text",
        "content": "Parts of speech are the grammatical categories..."
      },
      {
        "type": "video",
        "url": "https://media.grio.ai/videos/2001-intro.mp4",
        "duration": 480,
        "transcript": "In this video we explore..."
      },
      {
        "type": "quiz",
        "quiz_id": 3001,
        "questions_count": 5
      }
    ],
    "estimated_completion_time": 30
  }
}

4. Classroom Session API

4.1 POST /api/v1/sessions/start/

Description: Start a new classroom or learning session Authentication: Bearer token required

Request:

{
  "class_id": 10,
  "subject_id": 101,
  "topic_id": 501,
  "lesson_id": 2001,
  "mode": "teach",
  "session_name": "P6 English - Lesson 1"
}

Response (201 Created):

{
  "data": {
    "id": "sess_abc123xyz",
    "class_id": 10,
    "subject_id": 101,
    "topic_id": 501,
    "lesson_id": 2001,
    "mode": "teach",
    "status": "active",
    "started_at": "2026-03-24T14:30:00Z",
    "ends_at": null,
    "participants": []
  }
}

4.2 GET /api/v1/sessions/{id}/

Description: Retrieve session details and current state Authentication: Bearer token required

Response (200 OK):

{
  "data": {
    "id": "sess_abc123xyz",
    "class_id": 10,
    "mode": "teach",
    "status": "active",
    "started_at": "2026-03-24T14:30:00Z",
    "participants": [
      {
        "user_id": 101,
        "name": "Alice Mwaka",
        "role": "STUDENT",
        "joined_at": "2026-03-24T14:30:15Z"
      }
    ]
  }
}

4.3 PATCH /api/v1/sessions/{id}/mode/

Description: Switch session mode (teach/explore/practice/revision) Authentication: Bearer token required

Request:

{
  "mode": "practice"
}

Response (200 OK):

{
  "data": {
    "id": "sess_abc123xyz",
    "mode": "practice",
    "switched_at": "2026-03-24T14:45:00Z"
  }
}

4.4 POST /api/v1/sessions/{id}/end/

Description: End an active session Authentication: Bearer token required

Response (200 OK):

{
  "data": {
    "id": "sess_abc123xyz",
    "status": "completed",
    "ended_at": "2026-03-24T15:15:00Z",
    "duration_minutes": 45,
    "summary": {
      "participants": 1,
      "questions_asked": 12,
      "interactions": 34
    }
  }
}

4.5 GET /api/v1/sessions/active/

Description: Get active session for a class Query Parameters: - class_id (required): Class ID

Response (200 OK):

{
  "data": {
    "id": "sess_abc123xyz",
    "class_id": 10,
    "status": "active",
    "mode": "teach",
    "started_at": "2026-03-24T14:30:00Z"
  }
}

5. AI / Tutoring API

5.1 POST /api/v1/ai/chat/

Description: Send message to AI tutor and receive response Authentication: Bearer token required Rate Limit: 100 requests per minute per user

Request:

{
  "session_id": "sess_abc123xyz",
  "message": "How do I identify a noun in a sentence?",
  "mode": "teach",
  "context": {
    "lesson_id": 2001,
    "topic_id": 501
  }
}

Response (200 OK):

{
  "data": {
    "id": "msg_xyz789abc",
    "session_id": "sess_abc123xyz",
    "role": "assistant",
    "message": "A noun is a word that names a person, place, thing, or idea...",
    "type": "explanation",
    "confidence": 0.95,
    "metadata": {
      "sources": ["lesson_2001", "content_segment_3"],
      "follow_up_suggestions": [
        "Can you give me examples?",
        "How are nouns used in sentences?"
      ]
    },
    "timestamp": "2026-03-24T14:35:12Z"
  }
}

5.2 POST /api/v1/ai/lesson/start/

Description: Begin structured AI-led lesson delivery Authentication: Bearer token required

Request:

{
  "session_id": "sess_abc123xyz",
  "lesson_id": 2001,
  "teaching_style": "socratic"
}

Response (201 Created):

{
  "data": {
    "lesson_delivery_id": "ld_123abc",
    "lesson_id": 2001,
    "phase": "introduction",
    "introduction_message": "Today we'll explore the parts of speech...",
    "next_action": "present_content"
  }
}

5.3 POST /api/v1/ai/lesson/next/

Description: Advance to next step in lesson delivery Authentication: Bearer token required

Request:

{
  "lesson_delivery_id": "ld_123abc",
  "student_response": "I think nouns are action words"
}

Response (200 OK):

{
  "data": {
    "phase": "content",
    "content": "Actually, that describes verbs. Nouns are words that name things...",
    "next_action": "ask_question",
    "question": "Can you name a noun from your classroom?"
  }
}

5.4 POST /api/v1/ai/practice/question/

Description: Generate a practice question for a student Authentication: Bearer token required

Request:

{
  "session_id": "sess_abc123xyz",
  "topic_id": 501,
  "difficulty": "medium",
  "question_type": "multiple_choice"
}

Response (200 OK):

{
  "data": {
    "question_id": "q_456def",
    "question": "Which word is a noun? A) run, B) happy, C) dog, D) quickly",
    "question_type": "multiple_choice",
    "options": ["run", "happy", "dog", "quickly"],
    "difficulty": "medium",
    "estimated_time_seconds": 45
  }
}

5.5 POST /api/v1/ai/practice/validate/

Description: Validate student answer and provide feedback Authentication: Bearer token required

Request:

{
  "question_id": "q_456def",
  "student_answer": "C",
  "session_id": "sess_abc123xyz"
}

Response (200 OK):

{
  "data": {
    "is_correct": true,
    "feedback": "Excellent! 'Dog' is a noun because it names a thing.",
    "explanation": "Nouns are words that name people, places, things, or ideas...",
    "points_awarded": 10,
    "difficulty_adjustment": "increase",
    "next_question_difficulty": "hard"
  }
}

5.6 GET /api/v1/ai/health/

Description: Check AI service health and readiness Authentication: None (health check)

Response (200 OK):

{
  "data": {
    "status": "healthy",
    "version": "1.2.5",
    "response_time_ms": 45,
    "model_loaded": true,
    "last_training": "2026-03-20T00:00:00Z"
  }
}

6. Student API

6.1 GET /api/v1/students/me/dashboard/

Description: Retrieve student dashboard with progress and learning status Authentication: Bearer token required

Response (200 OK):

{
  "data": {
    "student_id": 42,
    "name": "Alice Mwaka",
    "avatar": "https://cdn.grio.ai/avatars/42.jpg",
    "class": "P6",
    "school": "St. Mary's Academy",
    "current_subjects": [
      {
        "id": 101,
        "name": "English Language",
        "progress_percent": 65,
        "lessons_completed": 8,
        "lessons_total": 12,
        "last_studied": "2026-03-24T14:30:00Z"
      },
      {
        "id": 102,
        "name": "Mathematics",
        "progress_percent": 42,
        "lessons_completed": 5,
        "lessons_total": 12,
        "last_studied": "2026-03-23T16:00:00Z"
      }
    ],
    "continue_learning": {
      "lesson_id": 2003,
      "lesson_title": "Reading Comprehension - Techniques",
      "subject": "English Language",
      "progress": "partially_completed"
    }
  }
}

6.2 GET /api/v1/students/me/progress/

Description: Get detailed progress data for a specific subject Query Parameters: - subject_id (required): Subject ID

Response (200 OK):

{
  "data": {
    "subject_id": 101,
    "subject_name": "English Language",
    "overall_progress": 65,
    "topics": [
      {
        "id": 501,
        "name": "Introduction to Grammar",
        "progress": 100,
        "lessons": [
          {
            "id": 2001,
            "title": "Parts of Speech",
            "status": "completed",
            "score": 92
          }
        ]
      }
    ],
    "milestones": [
      {
        "id": "m_001",
        "title": "First 5 Lessons",
        "unlocked_at": "2026-03-20T10:30:00Z"
      }
    ]
  }
}

6.3 GET /api/v1/students/me/history/

Description: Retrieve learning history for Grio Continuity feature Query Parameters: - limit (default 20): Number of records - offset (default 0): Pagination offset

Response (200 OK):

{
  "data": [
    {
      "id": "h_001",
      "lesson_id": 2001,
      "lesson_title": "Parts of Speech",
      "subject": "English Language",
      "class": "P6",
      "accessed_at": "2026-03-24T14:30:00Z",
      "duration_minutes": 25,
      "status": "completed",
      "score": 92
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 156,
    "has_next": true,
    "has_previous": false
  }
}

6.4 POST /api/v1/students/me/continue/

Description: Resume last learning session (Grio Continuity) Authentication: Bearer token required

Response (200 OK):

{
  "data": {
    "session_id": "sess_resumed_123",
    "lesson_id": 2003,
    "lesson_title": "Reading Comprehension - Techniques",
    "subject": "English Language",
    "last_position": {
      "block_index": 2,
      "timestamp": "2026-03-24T14:32:00Z"
    },
    "resume_url": "https://app.grio.ai/learn/session/sess_resumed_123"
  }
}

7. Teacher API

7.1 GET /api/v1/teachers/me/classes/

Description: List all classes taught by the current teacher Authentication: Bearer token required

Response (200 OK):

{
  "data": [
    {
      "id": 10,
      "name": "Primary 6 - Section A",
      "grade": "P6",
      "subject_ids": [101, 102],
      "student_count": 35,
      "schedule": {
        "monday": ["09:00-10:30"],
        "wednesday": ["11:00-12:30"]
      }
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 1,
    "has_next": false,
    "has_previous": false
  }
}

7.2 GET /api/v1/teachers/me/classes/{id}/students/

Description: Get students enrolled in a specific class Authentication: Bearer token required

Response (200 OK):

{
  "data": [
    {
      "id": 42,
      "name": "Alice Mwaka",
      "enrollment_date": "2026-01-15T00:00:00Z",
      "subjects": [101, 102],
      "attendance_percent": 94
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 35,
    "has_next": true,
    "has_previous": false
  }
}

7.3 GET /api/v1/teachers/me/classes/{id}/performance/

Description: Retrieve aggregated performance data for a class Authentication: Bearer token required

Response (200 OK):

{
  "data": {
    "class_id": 10,
    "class_name": "P6 - Section A",
    "average_score": 78.5,
    "average_progress": 62,
    "top_performers": [
      {
        "student_id": 42,
        "name": "Alice Mwaka",
        "average_score": 92,
        "progress": 85
      }
    ],
    "needs_support": [
      {
        "student_id": 55,
        "name": "Bob Banda",
        "average_score": 42,
        "progress": 28
      }
    ]
  }
}

7.4 POST /api/v1/teachers/me/assignments/

Description: Create new assignment for a class Authentication: Bearer token required

Request:

{
  "class_id": 10,
  "title": "Grammar Practice - Nouns and Verbs",
  "description": "Practice identifying parts of speech",
  "due_date": "2026-03-28T23:59:59Z",
  "topic_ids": [501, 502]
}

Response (201 Created):

{
  "data": {
    "id": "a_001",
    "title": "Grammar Practice - Nouns and Verbs",
    "class_id": 10,
    "created_at": "2026-03-24T15:00:00Z",
    "due_date": "2026-03-28T23:59:59Z",
    "status": "active"
  }
}

8. Admin API

8.1 Admin CRUD Operations

Base Endpoints: - GET /api/v1/admin/schools/ — List all schools - POST /api/v1/admin/schools/ — Create school - GET /api/v1/admin/schools/{id}/ — School details - PATCH /api/v1/admin/schools/{id}/ — Update school - DELETE /api/v1/admin/schools/{id}/ — Delete school - GET /api/v1/admin/users/ — List users - POST /api/v1/admin/users/ — Create user - PATCH /api/v1/admin/users/{id}/ — Update user

Authentication: Bearer token required, Super Admin or School Admin role

8.2 GET /api/v1/admin/analytics/school/{id}/

Description: School-level analytics and KPIs Authentication: Bearer token (Super Admin or School Admin)

Response (200 OK):

{
  "data": {
    "school_id": 5,
    "school_name": "St. Mary's Academy",
    "total_students": 450,
    "total_teachers": 25,
    "average_engagement": 76,
    "lessons_completed_today": 234,
    "lessons_completed_week": 1456,
    "top_subjects": [
      {
        "subject": "Mathematics",
        "students_active": 150,
        "average_score": 74.2
      }
    ]
  }
}

8.3 GET /api/v1/admin/analytics/national/ (Future)

Description: National-level analytics across all schools Authentication: Bearer token (Super Admin only)


9. Webhook & Event Patterns

9.1 Session Completed Events

When a session ends, POST to registered webhook URL:

{
  "event_type": "session.completed",
  "event_id": "evt_abc123",
  "timestamp": "2026-03-24T15:15:00Z",
  "data": {
    "session_id": "sess_abc123xyz",
    "class_id": 10,
    "duration_minutes": 45,
    "participants": 1,
    "completed_lessons": 1
  }
}

9.2 Student Progress Milestones

Triggered when student reaches milestone:

{
  "event_type": "student.milestone_unlocked",
  "timestamp": "2026-03-24T15:20:00Z",
  "data": {
    "student_id": 42,
    "milestone": "First 5 Lessons Completed",
    "milestone_id": "m_001",
    "unlocked_at": "2026-03-24T15:20:00Z"
  }
}

9.3 Analytics Aggregation Triggers

Hourly aggregation of session and progress data for reporting


10. Error Handling

10.1 Standard Error Response Format

All errors return JSON with consistent structure:

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "The requested lesson does not exist",
    "details": {
      "lesson_id": ["Lesson with ID 9999 not found"]
    }
  }
}

10.2 HTTP Status Codes

CodeMeaningUse Case
200OKSuccessful GET, PATCH, DELETE
201CreatedSuccessful POST (resource created)
400Bad RequestInvalid input, malformed JSON
401UnauthorizedMissing or invalid JWT token
403ForbiddenUser lacks permission for resource
404Not FoundResource does not exist
422Unprocessable EntityValidation errors on data
429Too Many RequestsRate limit exceeded
500Server ErrorUnexpected server error

10.3 Common Error Codes

CodeHTTP StatusDescription
INVALID_CREDENTIALS401Email/password incorrect
INVALID_TOKEN401JWT token is invalid or expired
RESOURCE_NOT_FOUND404Requested resource doesn’t exist
PERMISSION_DENIED403User doesn’t have required role/permission
VALIDATION_ERROR422Input validation failed
RATE_LIMIT_EXCEEDED429Too many requests
INTERNAL_SERVER_ERROR500Unexpected server error

10.4 Rate Limiting Headers

All responses include rate limit headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1711270800

11. Implementation Guidelines

11.1 Request/Response Best Practices

11.2 Security Considerations


Document End Next Review Date: 2026-06-24