API contracts
Reference for the NexSchool REST API. All endpoints live under /api, organized by module. Tenant routes require an access token plus a tenant identifier. This page keeps every module and endpoint; verbose example bodies are trimmed to one representative shape per module where the source repeated them.
Conventions
Base path
All APIs are served under /api.
Auth headers
Required on all tenant-scoped routes:
Authorization: Bearer <access_token>
X-Tenant-ID: <tenant_id>
Content-Type: application/jsonThe tenant may alternatively be resolved from the request subdomain.
Success envelope
{ "success": true, "data": {} }Error envelope
{ "success": false, "error": "ErrorType", "message": "Human-readable message" }Pagination
List endpoints wrap results with a pagination block:
{
"success": true,
"data": [],
"pagination": { "page": 1, "pageSize": 20, "totalItems": 100, "totalPages": 5 }
}Common query params across list endpoints: page, pageSize, search, sort, order.
Health
Unauthenticated liveness probe.
| Method | Path | Purpose |
|---|---|---|
GET | /api/health | Service health check |
{ "status": "healthy", "service": "School ERP Backend", "version": "1.0.0" }Auth (/api/auth)
| Method | Path | Auth | Purpose |
|---|---|---|---|
POST | /api/auth/login | public | Authenticate, return access token + user context |
POST | /api/auth/logout | required | Invalidate session |
POST | /api/auth/refresh | X-Refresh-Token header | Issue new access token |
GET | /api/auth/profile | required | Get current user profile |
PUT | /api/auth/profile | required | Update first_name, last_name, phone |
POST | /api/auth/profile/picture | required | Upload profile picture (multipart/form-data, jpeg/png, max 5MB) |
POST | /api/auth/password/forgot | public | Send reset email |
POST | /api/auth/password/reset | public | Reset password with token |
GET | /api/auth/email/verify?token=<token> | public | Verify email via link |
POST | /api/auth/email/verify | public | Verify email with { "token": "..." } |
GET | /api/auth/enabled-features | required | List tenant’s enabled feature flags |
Login — tenant_id may be replaced with subdomain. The refresh token is returned in the X-Refresh-Token response header.
{
"email": "admin@school.com",
"password": "password123",
"tenant_id": 1
}{
"success": true,
"data": {
"access_token": "eyJ...",
"user": {
"id": 1,
"email": "admin@school.com",
"first_name": "John",
"last_name": "Doe",
"profile_picture_url": null
},
"permissions": ["student.read", "teacher.read"],
"enabled_features": ["attendance", "fees_management"]
}
}Refresh — send the refresh token in the header:
POST /api/auth/refresh
X-Refresh-Token: <refresh_token>Students (/api/students)
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/students | student.read | List students (?page, pageSize, search, class_id, academic_year_id, is_active) |
GET | /api/students/<student_id> | student.read | Get one student |
POST | /api/students | student.create | Create student (optionally a login account) |
PUT | /api/students/<student_id> | student.update | Update any student fields |
DELETE | /api/students/<student_id> | student.delete | Soft delete (sets deleted_at) |
GET | /api/students/me/dashboard | student role | Self dashboard (attendance, fees, schedule) |
POST | /api/students/promote | student.update | Bulk promote students to a class/year |
POST | /api/students/promotion/preview | required | Preview which students will be promoted |
GET | /api/students/<student_id>/documents | required | List student documents |
POST | /api/students/<student_id>/documents | required | Upload document (multipart/form-data) |
DELETE | /api/students/<student_id>/documents/<document_id> | required | Delete a document |
GET | /api/students/<student_id>/documents/<document_id>/file | required | Download document file stream |
Create student — set create_user_account: true to provision a login (then email is required):
{
"first_name": "Arun",
"last_name": "Kumar",
"roll_number": "2024001",
"admission_number": "ADM001",
"date_of_birth": "2010-05-15",
"gender": "male",
"class_id": 5,
"grade_id": 3,
"parent_name": "Suresh Kumar",
"parent_phone": "+91-9876543210",
"parent_email": "suresh@email.com",
"address": "123 Main Street",
"create_user_account": true,
"email": "arun@school.com"
}Bulk promote:
{ "student_ids": [1, 2, 3], "to_class_id": 10, "to_academic_year_id": 2 }Upload document — multipart/form-data fields: file (binary), document_type_id, description.
Teachers (/api/teachers)
| Method | Path | Purpose |
|---|---|---|
GET | /api/teachers | List teachers (?search, is_active) |
POST | /api/teachers | Create teacher |
GET | /api/teachers/<id> | Get teacher |
PUT | /api/teachers/<id> | Update teacher |
DELETE | /api/teachers/<id> | Delete teacher |
GET | /api/teachers/me | Current teacher profile |
GET | /api/teachers/me/today-schedule | Today’s schedule (timetable.read) |
GET | /api/teachers/me/classes | Classes assigned to this teacher |
POST | /api/teachers/leaves | Apply for leave |
GET | /api/teachers/<id>/leaves | List leaves (?status, academic_year_id) |
PUT | /api/teachers/leaves/<leave_id> | Approve/reject leave (admin) |
DELETE | /api/teachers/leaves/<leave_id> | Delete leave request |
GET | /api/teachers/<id>/availability | Get availability grid |
PUT | /api/teachers/<id>/availability | Set availability slots |
GET | /api/teachers/<id>/workload | Current period assignment count |
PUT | /api/teachers/<id>/workload-rule | Set max periods per day/week |
Apply for leave:
{ "leave_type": "sick", "start_date": "2025-01-10", "end_date": "2025-01-12", "reason": "..." }Set availability — array of slots:
[{ "day_of_week": 0, "period": 1, "is_available": true }]Classes (/api/classes)
| Method | Path | Purpose |
|---|---|---|
GET | /api/classes | List classes (?academic_year_id, grade_id, search) |
POST | /api/classes | Create class |
GET | /api/classes/<id> | Get class |
PUT | /api/classes/<id> | Update class |
DELETE | /api/classes/<id> | Delete class |
POST | /api/classes/copy | Copy class structure to a new academic year |
GET | /api/classes/<id>/students | Students in class |
POST | /api/classes/<id>/students | Add student ({ "student_id": 5 }) |
DELETE | /api/classes/<id>/students/<student_id> | Remove student from class |
GET | /api/classes/<id>/unassigned-students | Students not in this class |
GET | /api/classes/<id>/teachers | Teachers in class |
POST | /api/classes/<id>/teachers | Assign teacher to class |
DELETE | /api/classes/<id>/teachers/<teacher_id> | Remove teacher from class |
GET | /api/classes/<id>/unassigned-teachers | Teachers not in this class |
POST | /api/classes/subjects/by-grade | Apply standard subject template for a grade |
GET | /api/classes/meta/available-class-teachers | Teachers not yet assigned as class teacher |
Assign teacher:
{ "teacher_id": 3, "subject": "Mathematics", "is_class_teacher": false }Subjects by grade — { "grade_id": 2, "class_ids": [1, 2, 3] }.
Subjects (/api/subjects)
| Method | Path | Purpose |
|---|---|---|
GET | /api/subjects | List subjects (?search, subject_context_id) |
POST | /api/subjects | Create subject ({ "name", "code", "subject_context_id" }) |
GET | /api/subjects/<id> | Get subject |
PUT | /api/subjects/<id> | Update subject |
DELETE | /api/subjects/<id> | Delete subject |
Class Subjects (/api/class-subjects)
| Method | Path | Purpose |
|---|---|---|
GET | /api/class-subjects | List (?class_id, academic_year_id) |
POST | /api/class-subjects | Attach subject to class ({ "class_id", "subject_id", "periods_per_week" }) |
DELETE | /api/class-subjects/<id> | Detach subject from class |
Attendance (/api/attendance)
| Method | Path | Auth | Purpose |
|---|---|---|---|
POST | /api/attendance/mark | attendance.mark | Mark attendance for a class on a date |
GET | /api/attendance/my-classes | required | Classes the current user can mark |
GET | /api/attendance/class/<class_id> | required | Class attendance (?date, from_date, to_date, page) |
GET | /api/attendance/student/<student_id> | required | Student attendance (?from_date, to_date, academic_year_id) |
GET | /api/attendance/me | student role | Current user’s own attendance |
GET | /api/attendance/calendar-holidays | required | Attendance merged with holiday calendar (?from_date, to_date) |
Mark attendance — status values: present, absent, late.
{
"class_id": 5,
"date": "2025-01-15",
"records": [
{ "student_id": 1, "status": "present" },
{ "student_id": 2, "status": "absent" },
{ "student_id": 3, "status": "late" }
]
}Academics (/api/academics)
| Method | Path | Purpose |
|---|---|---|
GET | /api/academics/years | List academic years |
POST | /api/academics/years | Create academic year |
GET | /api/academics/years/<id> | Get academic year |
PUT | /api/academics/years/<id> | Update academic year |
DELETE | /api/academics/years/<id> | Delete academic year |
GET | /api/academics/overview | Counts overview (?academic_year_id) |
Academic Terms (/api/academic-terms)
| Method | Path | Purpose |
|---|---|---|
GET | /api/academic-terms | List terms (?academic_year_id) |
POST | /api/academic-terms | Create term |
GET | /api/academic-terms/<id> | Get term |
PUT | /api/academic-terms/<id> | Update term |
DELETE | /api/academic-terms/<id> | Delete term |
Finance (/api/finance)
| Method | Path | Purpose |
|---|---|---|
GET | /api/finance/fee-structures | List fee structures (?academic_year_id) |
POST | /api/finance/fee-structures | Create fee structure |
GET | /api/finance/fee-structures/<id> | Get fee structure |
PUT | /api/finance/fee-structures/<id> | Update fee structure |
DELETE | /api/finance/fee-structures/<id> | Delete fee structure |
POST | /api/finance/fee-structures/<id>/components | Add a fee component |
DELETE | /api/finance/fee-structures/<id>/components/<component_id> | Remove a fee component |
POST | /api/finance/fee-structures/<id>/assign-classes | Assign structure to classes |
GET | /api/finance/student-fees | List student fees (?student_id, class_id, status) |
POST | /api/finance/student-fees/generate | Generate fees from a structure |
GET | /api/finance/student-fees/<id> | Get a student fee |
POST | /api/finance/payments | Record a payment |
GET | /api/finance/summary | Totals (?academic_year_id) |
Add fee component — { "name": "Tuition Fee", "amount": 5000, "frequency": "quarterly" }.
Record payment:
{
"student_fee_id": 5,
"amount": 2000,
"payment_date": "2025-01-15",
"payment_method": "cash",
"reference_number": "TXN001"
}Fees (/api/fees)
Invoice-based billing (distinct from /api/finance fee structures).
| Method | Path | Purpose |
|---|---|---|
GET | /api/fees/invoices | List invoices (?student_id, status, page) |
POST | /api/fees/invoices | Create invoice with line items |
GET | /api/fees/invoices/<id> | Get invoice |
PUT | /api/fees/invoices/<id> | Update invoice |
DELETE | /api/fees/invoices/<id> | Delete invoice |
GET | /api/fees/invoices/<id>/download | Download PDF receipt (WeasyPrint) |
POST | /api/fees/invoices/<id>/send-reminder | Send payment reminder |
GET | /api/fees/payments | List payments (?student_id, from_date, to_date) |
POST | /api/fees/payments | Record payment against an invoice |
Create invoice:
{
"student_id": 3,
"due_date": "2025-02-01",
"items": [
{ "description": "Tuition Fee", "amount": 5000, "quantity": 1 },
{ "description": "Activity Fee", "amount": 500, "quantity": 1 }
]
}Record payment — { "invoice_id": 5, "amount": 5500, "method": "online", "reference_number": "UPI123" }.
Timetable (/api/timetable)
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/timetable/config | required | Get timetable config |
PUT | /api/timetable/config | required | Update config (total_periods, lunch_start_period, period_duration, start_time) |
POST | /api/timetable/generate | require_setup_complete, require_active_subscription | Auto-generate timetable |
GET | /api/timetable/slots | required | List slots (?class_id, teacher_id, academic_year_id) |
POST | /api/timetable/slots | required | Create a slot |
PUT | /api/timetable/slots/<id> | required | Update a slot |
DELETE | /api/timetable/slots/<id> | required | Delete a slot |
PATCH | /api/timetable/slots/<id>/move | required | Move slot ({ "day_of_week", "period" }) |
POST | /api/timetable/check-conflicts | required | Detect class/teacher conflicts |
Create slot — { "class_id": 1, "subject_id": 3, "teacher_id": 2, "day_of_week": 0, "period": 1 }.
Check conflicts:
{ "class_id": 1, "teacher_id": 2, "day_of_week": 0, "period": 1, "exclude_slot_id": null }{ "has_conflict": false, "conflicts": [] }Schedule (/api/schedule)
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/schedule/today | required | Today’s slots for the current user (teacher’s classes / student’s class) |
GET | /api/schedule/class/<class_id> | required | Slots for a specific date (?date) |
Notifications (/api/notifications)
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/notifications | required | List notifications (?is_read, page) |
DELETE | /api/notifications/<id> | required | Delete notification |
POST | /api/notifications/<id>/read | required | Mark one read |
POST | /api/notifications/read-all | required | Mark all read |
POST | /api/notifications/send | notification.send | Send to users/roles/all |
GET | /api/notifications/stream | required | SSE stream (long-lived connection) |
GET | /api/notifications/templates | required | List templates |
POST | /api/notifications/templates | required | Create template |
PUT | /api/notifications/templates/<id> | required | Update template |
DELETE | /api/notifications/templates/<id> | required | Delete template |
Send — target with user_ids, or role_ids, or all: true:
{
"user_ids": [1, 2, 3],
"title": "Exam Schedule",
"message": "Final exams start from 15th January",
"type": "info",
"action_url": "/schedule"
}Stream — the SSE endpoint emits events shaped like data: {"id": 1, "title": "...", "message": "..."}.
Holidays (/api/holidays)
| Method | Path | Purpose |
|---|---|---|
GET | /api/holidays | List holidays (?academic_year_id, from_date, to_date) |
POST | /api/holidays | Create holiday ({ "name", "date", "is_recurring" }) |
PUT | /api/holidays/<id> | Update holiday |
DELETE | /api/holidays/<id> | Delete holiday |
Transport (/api/transport)
Buses
| Method | Path | Purpose |
|---|---|---|
GET | /api/transport/buses | List buses |
POST | /api/transport/buses | Create bus |
GET | /api/transport/buses/<id> | Get bus |
GET | /api/transport/buses/<id>/details | Bus with route + enrolled student count |
PUT | /api/transport/buses/<id> | Update bus |
DELETE | /api/transport/buses/<id> | Delete bus |
Drivers
| Method | Path | Purpose |
|---|---|---|
GET | /api/transport/drivers | List drivers |
POST | /api/transport/drivers | Create driver |
PUT | /api/transport/drivers/<id> | Update driver |
DELETE | /api/transport/drivers/<id> | Delete driver |
Routes & stops
| Method | Path | Purpose |
|---|---|---|
GET | /api/transport/routes | List routes |
POST | /api/transport/routes | Create route |
GET | /api/transport/routes/<id> | Get route |
PUT | /api/transport/routes/<id> | Update route |
DELETE | /api/transport/routes/<id> | Delete route |
GET | /api/transport/routes/<id>/stops | List stops on a route |
POST | /api/transport/routes/<id>/stops/reorder | Reorder route stops |
GET | /api/transport/stops | List stops |
POST | /api/transport/stops | Create stop |
PUT | /api/transport/stops/<id> | Update stop |
DELETE | /api/transport/stops/<id> | Delete stop |
Enrollments
| Method | Path | Purpose |
|---|---|---|
GET | /api/transport/enrollments | List enrollments (?route_id, student_id) |
POST | /api/transport/enroll | Enroll student ({ "student_id", "route_id", "stop_id", "enrollment_type" }) |
DELETE | /api/transport/enroll/<id> | Remove enrollment |
Staff, schedules & operations
| Method | Path | Purpose |
|---|---|---|
GET | /api/transport/staff | List transport staff |
POST | /api/transport/staff | Create staff |
GET | /api/transport/staff/<id>/workload | Staff workload |
GET | /api/transport/schedules | List schedules |
POST | /api/transport/schedules/exceptions | Create schedule exception |
GET | /api/transport/schedules/conflict-check | Check schedule conflicts |
GET | /api/transport/bus-assignments | List bus assignments |
POST | /api/transport/bus-assignments | Create bus assignment |
GET | /api/transport/dashboard | Transport dashboard |
GET | /api/transport/fee-plans | Transport fee plans |
GET | /api/transport/export/contact-sheet | Export contact sheet (CSV/Excel) |
Dashboard (/api/dashboard)
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/dashboard | auth_required, tenant_required | Aggregate tenant dashboard |
{
"success": true,
"data": {
"total_students": 450,
"total_teachers": 32,
"total_classes": 18,
"attendance_today": { "present": 420, "absent": 30 },
"fee_summary": { "collected_this_month": 120000, "pending": 45000 },
"recent_notifications": []
}
}RBAC (/api/rbac)
| Method | Path | Purpose |
|---|---|---|
GET | /api/rbac/roles | List roles |
POST | /api/rbac/roles | Create role ({ "name", "description", "permission_ids" }) |
GET | /api/rbac/roles/<id> | Get role |
PUT | /api/rbac/roles/<id> | Update role |
DELETE | /api/rbac/roles/<id> | Delete role |
GET | /api/rbac/permissions | List all permission strings |
POST | /api/rbac/users/<user_id>/roles | Assign role ({ "role_id": 2 }) |
DELETE | /api/rbac/users/<user_id>/roles/<role_id> | Revoke role |
GET | /api/rbac/users/<user_id>/roles | List a user’s roles |
Users (/api/users)
| Method | Path | Purpose |
|---|---|---|
GET | /api/users | List users (?search, role_id) |
POST | /api/users | Create user |
GET | /api/users/<id> | Get user |
PUT | /api/users/<id> | Update user |
DELETE | /api/users/<id> | Delete user |
Platform (/api/platform)
Super-admin only. Not tenant-scoped.
| Method | Path | Purpose |
|---|---|---|
GET | /api/platform/tenants | List tenants |
POST | /api/platform/tenants | Create tenant |
GET | /api/platform/tenants/<id> | Get tenant |
PUT | /api/platform/tenants/<id> | Update tenant |
DELETE | /api/platform/tenants/<id> | Delete tenant |
POST | /api/platform/tenants/<id>/suspend | Suspend tenant |
POST | /api/platform/tenants/<id>/activate | Activate tenant |
GET | /api/platform/plans | List plans |
POST | /api/platform/plans | Create plan |
PUT | /api/platform/plans/<id> | Update plan |
DELETE | /api/platform/plans/<id> | Delete plan |
GET | /api/platform/notification-settings | Get notification settings |
PUT | /api/platform/notification-settings | Update notification settings |
GET | /api/platform/audit-logs | Audit logs (?tenant_id, action, from_date, to_date) |
School setup (/api/school-setup)
| Method | Path | Purpose |
|---|---|---|
GET | /api/school-setup/status | Setup progress ({ is_complete, steps_completed, ... }) |
POST | /api/school-setup/complete | Mark setup complete |
POST | /api/school-setup/school-info | Save school info ({ name, address, phone, logo }) |
POST | /api/school-setup/academic-year | Create first academic year ({ name, start_date, end_date }) |
POST | /api/school-setup/grades | Seed grades ({ grades: [{ name, sequence }] }) |
Master data
These modules share standard CRUD: GET (list), POST (create), PUT /<id> (update), DELETE /<id> (delete).
| Base path | Resource |
|---|---|
/api/grades | Grades |
/api/school-units | School units |
/api/programmes | Academic programmes |
/api/mediums | Mediums of instruction |
/api/religions | Religions |
/api/subject-contexts | Subject contexts |
Devices (/api/devices)
Push-notification device registration.
| Method | Path | Purpose |
|---|---|---|
POST | /api/devices/register | Register device ({ "token": "fcm-token", "platform": "android" }) |
DELETE | /api/devices/<token> | Deregister device |
Subscription (/api/subscription)
| Method | Path | Purpose |
|---|---|---|
GET | /api/subscription/status | Current subscription status |
POST | /api/subscription/upgrade | Upgrade plan ({ "plan_id": 3 }) |