API Overview

This document describes the conventions and patterns used throughout the B12 SIS API.

Base URL

Production: https://api.yourschool.edu/api
Development: http://localhost:8080/api

HTTP Methods

Method

Usage

GET

Retrieve a single resource

POST

Create resource(s) or list with filters

PUT

Update a resource

DELETE

Soft-delete a resource

Request Headers

Required Headers

Header

Description

Example

Authorization

JWT Bearer token

Bearer eyJhbGci...

X-Team-ID

Current team/campus UUID

550e8400-e29b-41d4-a716-446655440000

Content-Type

Request content type

application/json

Optional Headers

Header

Description

X-Academic-Session-ID

Current academic session UUID

Accept-Language

Preferred language (en, vi)

Response Format

Success Response

{
  "success": true,
  "message": "Operation description",
  "data": { ... }
}

Error Response

{
  "success": false,
  "message": "Error description",
  "errors": "Detailed error information"
}

List Response

{
  "success": true,
  "message": "Records retrieved successfully",
  "data": {
    "list": [ ... ],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 100
    },
    "metadata": {
      "field_definitions": { ... }
    }
  }
}

Standard CRUD Endpoints

Every module follows this endpoint pattern:

Endpoint

Method

Description

/{module}

POST

Create a single record

/{module}/bulk

POST

Create multiple records

/{module}/list

POST

List records with pagination/filtering

/{module}/:id

GET

Get a single record by ID

/{module}/:id

PUT

Update a record

/{module}/:id

DELETE

Soft-delete a record

/{module}/bulk

DELETE

Bulk soft-delete records

/{module}/export

POST

Export records to Excel

/{module}/import

POST

Import records from Excel

Relationship Endpoints

Endpoint

Method

Description

/{module}/list_relate/:id/:field/:relatedModule

POST

List related records

/{module}/list_relate/:id/:field/:relatedModule

PUT

Add relationships

/{module}/list_relate/:id/:field/:relatedModule

DELETE

Remove relationships

List Request Format

All list endpoints accept a POST request with this body:

{
  "page": 1,
  "limit": 20,
  "search": "search term",
  "sort_field": "created_at",
  "sort_direction": "desc",
  "filter": {
    "group": "AND",
    "conditions": [
      {"field": "status", "operator": "=", "value": "active"}
    ]
  },
  "preloads": ["Class", "Program"]
}

Parameters

Parameter

Type

Default

Description

page

int

1

Page number

limit

int

20

Records per page (max 100)

search

string

“”

Full-text search across searchable fields

sort_field

string

“created_at”

Field to sort by

sort_direction

string

“desc”

Sort direction: asc or desc

filter

object

null

Filter conditions (see Filter System)

preloads

array

[]

Related data to include

Filter System

The filter system supports complex queries with AND/OR grouping:

Simple Filter

{
  "filter": {
    "group": "AND",
    "conditions": [
      {"field": "status", "operator": "=", "value": "active"}
    ]
  }
}

Nested Filter (AND + OR)

{
  "filter": {
    "group": "AND",
    "conditions": [
      {"field": "status", "operator": "=", "value": "active"},
      {
        "group": "OR",
        "conditions": [
          {"field": "grade_level", "operator": "=", "value": "10"},
          {"field": "grade_level", "operator": "=", "value": "11"}
        ]
      }
    ]
  }
}

Filter Operators

Operator

Description

Example

=

Equals

{"field": "status", "operator": "=", "value": "active"}

!=

Not equals

{"field": "status", "operator": "!=", "value": "inactive"}

>

Greater than

{"field": "age", "operator": ">", "value": 18}

<

Less than

{"field": "age", "operator": "<", "value": 65}

>=

Greater than or equal

{"field": "score", "operator": ">=", "value": 60}

<=

Less than or equal

{"field": "score", "operator": "<=", "value": 100}

contains

Contains substring

{"field": "name", "operator": "contains", "value": "john"}

starts_with

Starts with

{"field": "code", "operator": "starts_with", "value": "STD"}

ends_with

Ends with

{"field": "email", "operator": "ends_with", "value": "@school.edu"}

is_null

Is NULL

{"field": "deleted_at", "operator": "is_null", "value": true}

is_not_null

Is not NULL

{"field": "assigned_to", "operator": "is_not_null", "value": true}

in

In array

{"field": "status", "operator": "in", "value": ["active", "pending"]}

not_in

Not in array

{"field": "status", "operator": "not_in", "value": ["deleted"]}

Pagination

List responses include pagination metadata:

{
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "total_pages": 8
  }
}

Field Definitions

List responses include field definitions for dynamic form generation:

{
  "metadata": {
    "field_definitions": {
      "name": {
        "type": "text",
        "label": "Name",
        "required": true
      },
      "status": {
        "type": "enum",
        "label": "Status",
        "options": ["active", "inactive"]
      },
      "class_id": {
        "type": "relate",
        "label": "Class",
        "module": "Class"
      }
    }
  }
}

Field Types

Type

Description

text

Single-line text input

textarea

Multi-line text input

html

Rich text editor

int

Integer number

float

Decimal number

bool

Boolean checkbox

date

Date picker

datetime

Date and time picker

enum

Single select dropdown

multienum

Multi-select dropdown

relate

Foreign key relation (single)

multirelate

Many-to-many relation

image

Image upload

file

File upload

email

Email input

phone

Phone number input

address

Address input with autocomplete

password

Password input

Error Codes

HTTP Code

Description

200

Success

201

Created

400

Bad Request - Invalid input

401

Unauthorized - Invalid or expired token

403

Forbidden - Insufficient permissions

404

Not Found - Resource doesn’t exist

409

Conflict - Duplicate entry

422

Unprocessable Entity - Validation failed

429

Too Many Requests - Rate limited

500

Internal Server Error

Rate Limiting

API requests are rate limited:

  • Default: 100 requests per minute per user

  • Bulk operations: 10 requests per minute

When rate limited, you’ll receive:

{
  "error": "Rate limit exceeded",
  "retry_after": 60
}

Soft Delete

All records use soft delete. Deleted records:

  • Have deleted_at timestamp set

  • Are excluded from normal queries

  • Can be restored by admin

  • Are permanently purged after retention period

Audit Trail

All create, update, and delete operations are logged with:

  • User ID who performed the action

  • Timestamp

  • Before/after data snapshots

  • IP address and user agent

Multi-tenancy

Data is isolated by team (organization/campus):

  1. X-Team-ID header identifies the current team

  2. All queries automatically filter by team

  3. New records inherit the team ID

  4. Child teams can access parent team data

Preloading Relations

Request related data using the preloads parameter:

{
  "preloads": ["Class", "Class.GradeLevel", "Program"]
}

This returns nested related objects:

{
  "id": "student-id",
  "name": "John Doe",
  "class": {
    "id": "class-id",
    "name": "Class 10A",
    "grade_level": {
      "id": "grade-id",
      "name": "Grade 10"
    }
  },
  "program": {
    "id": "program-id",
    "name": "Academic Program"
  }
}