{
    "openapi": "3.1.0",
    "info": {
        "title": "EduDesk REST API",
        "version": "1.3.0",
        "description": "Programmatic access to EduDesk school management data.\n\n## Authentication\nAll endpoints require a Bearer API key in the `Authorization` header:\n```\nAuthorization: Bearer <your_api_key>\n```\nCreate API keys from the **Settings → API Keys** page in your dashboard (admin only).\n\n## Rate Limits\nDefault: **300 requests / minute** per API key. Exceeded requests receive `HTTP 429`.\n\n## Response format\nAll responses are JSON with the envelope:\n```json\n{ \"ok\": true, \"data\": {...} }\n{ \"ok\": false, \"error\": \"Human-readable message\" }\n```\n\n## Multi-tenancy\nAll requests are automatically scoped to the school that owns the API key. You cannot access data from another school.",
        "contact": {
            "name": "EduDesk Support",
            "url": "https://edudesk.app/support"
        },
        "license": {
            "name": "Proprietary"
        }
    },
    "servers": [
        {
            "url": "https://www.edudesk.africa/api/v1",
            "description": "This EduDesk installation"
        }
    ],
    "security": [
        {
            "BearerApiKey": []
        }
    ],
    "components": {
        "securitySchemes": {
            "BearerApiKey": {
                "type": "http",
                "scheme": "bearer",
                "description": "API key generated from the EduDesk admin dashboard."
            }
        },
        "schemas": {
            "OkEnvelope": {
                "type": "object",
                "properties": {
                    "ok": {
                        "type": "boolean",
                        "example": true
                    },
                    "data": {
                        "description": "Response payload (type varies by endpoint)"
                    }
                }
            },
            "ErrEnvelope": {
                "type": "object",
                "properties": {
                    "ok": {
                        "type": "boolean",
                        "example": false
                    },
                    "error": {
                        "type": "string",
                        "example": "Student not found."
                    }
                }
            },
            "Student": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "school_id": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string",
                        "example": "Alex Chen"
                    },
                    "admission_no": {
                        "type": "string",
                        "example": "2024-0042"
                    },
                    "gender": {
                        "type": "string",
                        "enum": [
                            "Male",
                            "Female",
                            "Other"
                        ]
                    },
                    "class_name": {
                        "type": "string",
                        "example": "Grade 4A"
                    },
                    "dob": {
                        "type": "string",
                        "format": "date"
                    },
                    "parent_name": {
                        "type": "string"
                    },
                    "parent_phone": {
                        "type": "string"
                    },
                    "parent_email": {
                        "type": "string",
                        "format": "email"
                    },
                    "address": {
                        "type": "string"
                    },
                    "photo": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "Teacher": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "email": {
                        "type": "string",
                        "format": "email"
                    },
                    "phone": {
                        "type": "string"
                    },
                    "subject": {
                        "type": "string"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "active",
                            "inactive"
                        ]
                    }
                }
            },
            "Class": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string",
                        "example": "Grade 4A"
                    },
                    "section": {
                        "type": "string"
                    },
                    "capacity": {
                        "type": "integer"
                    },
                    "class_teacher": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                }
            },
            "FeeRecord": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "student_id": {
                        "type": "string"
                    },
                    "student_name": {
                        "type": "string"
                    },
                    "amount": {
                        "type": "number",
                        "format": "float"
                    },
                    "discount": {
                        "type": "number",
                        "format": "float"
                    },
                    "fine": {
                        "type": "number",
                        "format": "float"
                    },
                    "fee_type": {
                        "type": "string",
                        "enum": [
                            "tuition",
                            "boarding",
                            "transport",
                            "library",
                            "exam",
                            "other"
                        ]
                    },
                    "method": {
                        "type": "string"
                    },
                    "term": {
                        "type": "integer"
                    },
                    "year": {
                        "type": "string"
                    },
                    "date": {
                        "type": "string",
                        "format": "date"
                    },
                    "note": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                }
            },
            "AttendanceRecord": {
                "type": "object",
                "properties": {
                    "student_id": {
                        "type": "string"
                    },
                    "class_name": {
                        "type": "string"
                    },
                    "date": {
                        "type": "string",
                        "format": "date"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "present",
                            "absent",
                            "late",
                            "excused"
                        ]
                    },
                    "note": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "Notice": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "title": {
                        "type": "string"
                    },
                    "body": {
                        "type": "string"
                    },
                    "priority": {
                        "type": "string",
                        "enum": [
                            "low",
                            "normal",
                            "high"
                        ]
                    },
                    "target": {
                        "type": "string",
                        "enum": [
                            "all",
                            "students",
                            "teachers",
                            "parents"
                        ]
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "created_by": {
                        "type": "string"
                    }
                }
            }
        },
        "parameters": {
            "PageParam": {
                "name": "page",
                "in": "query",
                "schema": {
                    "type": "integer",
                    "default": 1
                }
            },
            "LimitParam": {
                "name": "limit",
                "in": "query",
                "schema": {
                    "type": "integer",
                    "default": 50,
                    "maximum": 200
                }
            },
            "QParam": {
                "name": "q",
                "in": "query",
                "description": "Full-text search query",
                "schema": {
                    "type": "string"
                }
            },
            "ClassParam": {
                "name": "class",
                "in": "query",
                "description": "Filter by class name",
                "schema": {
                    "type": "string"
                }
            }
        },
        "responses": {
            "Unauthorized": {
                "description": "Missing or invalid API key",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrEnvelope"
                        }
                    }
                }
            },
            "NotFound": {
                "description": "Resource not found",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrEnvelope"
                        }
                    }
                }
            },
            "BadRequest": {
                "description": "Validation error",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrEnvelope"
                        }
                    }
                }
            }
        }
    },
    "paths": {
        "/students.php": {
            "get": {
                "operationId": "listStudents",
                "summary": "List students",
                "tags": [
                    "Students"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PageParam"
                    },
                    {
                        "$ref": "#/components/parameters/LimitParam"
                    },
                    {
                        "$ref": "#/components/parameters/QParam"
                    },
                    {
                        "$ref": "#/components/parameters/ClassParam"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "List of students",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/OkEnvelope"
                                        },
                                        {
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Student"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "operationId": "createStudent",
                "summary": "Create a student",
                "tags": [
                    "Students"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string"
                                    },
                                    "gender": {
                                        "type": "string",
                                        "enum": [
                                            "Male",
                                            "Female",
                                            "Other"
                                        ]
                                    },
                                    "className": {
                                        "type": "string"
                                    },
                                    "dob": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "parentName": {
                                        "type": "string"
                                    },
                                    "parentPhone": {
                                        "type": "string"
                                    },
                                    "parentEmail": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "address": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Created student",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OkEnvelope"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/teachers.php": {
            "get": {
                "operationId": "listTeachers",
                "summary": "List teachers",
                "tags": [
                    "Teachers"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/QParam"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "List of teachers",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/OkEnvelope"
                                        },
                                        {
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Teacher"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "operationId": "createTeacher",
                "summary": "Create a teacher",
                "tags": [
                    "Teachers"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string"
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "phone": {
                                        "type": "string"
                                    },
                                    "subject": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Created teacher",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OkEnvelope"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/classes.php": {
            "get": {
                "operationId": "listClasses",
                "summary": "List classes",
                "tags": [
                    "Classes"
                ],
                "responses": {
                    "200": {
                        "description": "List of classes",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/OkEnvelope"
                                        },
                                        {
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Class"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/attendance.php": {
            "get": {
                "operationId": "getAttendance",
                "summary": "Get attendance records",
                "tags": [
                    "Attendance"
                ],
                "parameters": [
                    {
                        "name": "date",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "class",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Attendance records for the date",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/OkEnvelope"
                                        },
                                        {
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/AttendanceRecord"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "operationId": "saveAttendance",
                "summary": "Save attendance records",
                "tags": [
                    "Attendance"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "records"
                                ],
                                "properties": {
                                    "records": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/AttendanceRecord"
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Saved",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OkEnvelope"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/fees.php": {
            "get": {
                "operationId": "listFees",
                "summary": "List fee records",
                "tags": [
                    "Fees"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/PageParam"
                    },
                    {
                        "$ref": "#/components/parameters/LimitParam"
                    },
                    {
                        "name": "student_id",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "term",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "year",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Fee records",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/OkEnvelope"
                                        },
                                        {
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/FeeRecord"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "operationId": "recordFee",
                "summary": "Record a fee payment",
                "tags": [
                    "Fees"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "studentId",
                                    "amount"
                                ],
                                "properties": {
                                    "studentId": {
                                        "type": "string"
                                    },
                                    "amount": {
                                        "type": "number"
                                    },
                                    "discount": {
                                        "type": "number",
                                        "default": 0
                                    },
                                    "fine": {
                                        "type": "number",
                                        "default": 0
                                    },
                                    "fee_type": {
                                        "type": "string",
                                        "default": "tuition"
                                    },
                                    "method": {
                                        "type": "string",
                                        "example": "Bank Transfer"
                                    },
                                    "term": {
                                        "type": "integer"
                                    },
                                    "year": {
                                        "type": "string"
                                    },
                                    "date": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "note": {
                                        "type": "string"
                                    },
                                    "idempotency_key": {
                                        "type": "string",
                                        "description": "Optional unique key to prevent duplicate recording"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Fee recorded",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OkEnvelope"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/notices.php": {
            "get": {
                "operationId": "listNotices",
                "summary": "List school notices",
                "tags": [
                    "Notices"
                ],
                "parameters": [
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "default": 50
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Notices",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/OkEnvelope"
                                        },
                                        {
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Notice"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/reports.php": {
            "get": {
                "operationId": "getReport",
                "summary": "Get aggregated report data",
                "tags": [
                    "Reports"
                ],
                "parameters": [
                    {
                        "name": "type",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "fee_summary",
                                "attendance",
                                "exam_results",
                                "student_growth"
                            ]
                        },
                        "description": "Report type to generate"
                    },
                    {
                        "name": "term",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "year",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "class",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Report data",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OkEnvelope"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/settings.php": {
            "get": {
                "operationId": "getSettings",
                "summary": "Get non-sensitive school settings",
                "tags": [
                    "Settings"
                ],
                "responses": {
                    "200": {
                        "description": "Settings object",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OkEnvelope"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "patch": {
                "operationId": "updateSettings",
                "summary": "Update school settings (non-sensitive fields only)",
                "tags": [
                    "Settings"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "description": "Key-value pairs of settings to update. Only whitelisted keys are accepted.",
                                "example": {
                                    "schoolName": "Maplewood Academy",
                                    "timezone": "America/New_York",
                                    "currency": "USD"
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Saved keys list",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OkEnvelope"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/import.php": {
            "post": {
                "operationId": "bulkImport",
                "summary": "Bulk CSV import for students or teachers",
                "tags": [
                    "Import"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart/form-data": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "type",
                                    "csv"
                                ],
                                "properties": {
                                    "type": {
                                        "type": "string",
                                        "enum": [
                                            "students",
                                            "teachers"
                                        ]
                                    },
                                    "csv": {
                                        "type": "string",
                                        "format": "binary",
                                        "description": "CSV file (max 2000 rows)"
                                    },
                                    "dry_run": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Validate without inserting"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Import result",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/OkEnvelope"
                                        },
                                        {
                                            "properties": {
                                                "data": {
                                                    "type": "object",
                                                    "properties": {
                                                        "inserted": {
                                                            "type": "integer"
                                                        },
                                                        "skipped": {
                                                            "type": "integer"
                                                        },
                                                        "errors": {
                                                            "type": "array",
                                                            "items": {
                                                                "type": "string"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/timetable.php": {
            "get": {
                "operationId": "getTimetable",
                "summary": "Get timetable for a class",
                "tags": [
                    "Timetable"
                ],
                "parameters": [
                    {
                        "name": "class",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Timetable entries",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OkEnvelope"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        }
    },
    "tags": [
        {
            "name": "Students",
            "description": "Student enrollment and profile management"
        },
        {
            "name": "Teachers",
            "description": "Staff / teacher management"
        },
        {
            "name": "Classes",
            "description": "Class definitions and assignments"
        },
        {
            "name": "Attendance",
            "description": "Daily student attendance"
        },
        {
            "name": "Fees",
            "description": "Fee collection and payment records"
        },
        {
            "name": "Notices",
            "description": "School notice board"
        },
        {
            "name": "Reports",
            "description": "Aggregated data reports"
        },
        {
            "name": "Settings",
            "description": "Non-sensitive school configuration"
        },
        {
            "name": "Timetable",
            "description": "Class schedules"
        },
        {
            "name": "Import",
            "description": "Bulk data import"
        }
    ]
}