Layouts API

REST API reference for page layouts, assignments, resolution, and entity listing

Overview

The Layouts API lets you manage page layouts, assign them to users/roles/groups, and resolve which layout applies for a given user. All endpoints require authentication.

Endpoints

MethodPathDescription
GET/api/settings/layoutsList all layouts
POST/api/settings/layoutsCreate a layout
GET/api/settings/layouts/{id}Get a single layout
PATCH/api/settings/layouts/{id}Update a layout
DELETE/api/settings/layouts/{id}Delete a layout
GET/api/settings/layouts/resolveResolve the best layout for the current user
POST/api/settings/layouts/defaultsSeed default form layouts for standard entities
GET/api/settings/layout-assignmentsList all assignments
POST/api/settings/layout-assignmentsCreate an assignment
DELETE/api/settings/layout-assignmentsDelete an assignment
GET/api/settings/entitiesList all registered entities
POST/api/admin/seed-better-layoutsRegenerate multi-section default layouts

List Layouts

GET /api/settings/layouts

Query Parameters:

ParamTypeDescription
entitystringFilter by target entity (e.g., Student)
typestringFilter by layout type (e.g., LT_FORM)

Response:

{
  "data": [
    {
      "id": "clx...",
      "name": "Student Form",
      "targetType": "STATIC_ENTITY",
      "targetEntity": "Student",
      "layoutType": "LT_FORM",
      "isDefault": true,
      "isActive": true,
      "config": { "sections": [...] },
      "folderId": null,
      "createdBy": { "name": "Admin", "email": "admin@school.com" },
      "assignmentCount": 3,
      "createdAt": "2026-04-13T...",
      "updatedAt": "2026-04-13T..."
    }
  ]
}

Create Layout

POST /api/settings/layouts

Request Body:

{
  "name": "Student Admissions Form",
  "targetType": "STATIC_ENTITY",
  "targetEntity": "Student",
  "layoutType": "LT_FORM",
  "folderId": null
}
FieldTypeRequiredDescription
namestringYesDisplay name for the layout
targetTypestringYesSTATIC_ENTITY or DYNAMIC_OBJECT
targetEntitystringYesEntity API name (e.g., Student, Vehicle)
layoutTypestringYesLT_DETAIL, LT_LIST, LT_FORM, LT_DASHBOARD, or LT_PORTAL
folderIdstringNoFolder ID for organization

Response: 201 Created with the created layout object.

The layout is created with an empty config ({ sections: [] }). Use the designer or PATCH to add sections.


Get Layout

GET /api/settings/layouts/{id}

Returns the full layout object including the config JSON.


Update Layout

PATCH /api/settings/layouts/{id}

Request Body (all fields optional):

{
  "name": "Updated Name",
  "config": {
    "sections": [
      {
        "id": "personal",
        "title": "Personal Information",
        "columns": 2,
        "collapsible": false,
        "isCollapsed": false,
        "widgets": [
          {
            "id": "personal_fields",
            "type": "FIELD_GROUP",
            "config": {
              "fields": ["firstName", "lastName", "dob", "gender"]
            }
          }
        ]
      }
    ]
  },
  "isDefault": true,
  "folderId": "clx..."
}

Config Structure:

The config object follows this schema:

interface LayoutConfig {
  sections: Section[];
}
 
interface Section {
  id: string;           // Unique section ID
  title: string;        // Display title
  columns: 1 | 2;      // Column layout
  collapsible: boolean; // Can be expanded/collapsed
  isCollapsed: boolean; // Default collapsed state
  widgets: Widget[];    // Widgets in this section
}
 
interface Widget {
  id: string;           // Unique widget ID
  type: "FIELD_GROUP" | "ATTACHMENTS" | "NOTES";
  config: {
    fields?: string[];  // Field API names (for FIELD_GROUP)
  };
}

Delete Layout

DELETE /api/settings/layouts/{id}

Returns { success: true }. Cascade deletes related layout assignments.


Resolve Layout

GET /api/settings/layouts/resolve?entity=Student&type=LT_FORM

Resolves the best-matching layout for the authenticated user.

Query Parameters:

ParamTypeRequiredDescription
entitystringYesEntity API name
typestringYesLayout type

Response:

{
  "layout": {
    "id": "clx...",
    "name": "Student Form",
    "config": { "sections": [...] },
    "layoutType": "LT_FORM",
    "targetEntity": "Student"
  },
  "reason": "ROLE"
}

Resolution Priority:

PriorityReasonDescription
1USERLayout assigned directly to this user
2GROUPLayout assigned to a group the user belongs to
3ROLELayout assigned to the user's role
4PROFILE_TYPELayout assigned to the user's profile type
5DEFAULTLayout marked as default for this entity + type
6NONENo layout found — client renders fallback

Results are cached in Redis for 5 minutes. NONE results are never cached.


Seed Default Form Layouts

POST /api/settings/layouts/defaults

Creates default form layouts for standard entities (Student, Staff, Enquiry, User) if they don't already exist. Skips entities that already have a form layout.

Response:

{
  "success": true,
  "created": ["Student", "User"],
  "skipped": ["Staff", "Enquiry"],
  "message": "Created 2 default form layout(s). Skipped 2 (already exist)."
}

List Assignments

GET /api/settings/layout-assignments

Returns all layout assignments for the current institution.

Response:

{
  "data": [
    {
      "id": "clx...",
      "layoutId": "clx...",
      "entity": "Student",
      "layoutType": "LT_FORM",
      "assignmentType": "ASSIGN_ROLE",
      "profileType": null,
      "isActive": true,
      "priorityOverride": null,
      "layout": { "id": "clx...", "name": "Admissions Form", "layoutType": "LT_FORM", "targetEntity": "Student" },
      "role": { "id": "clx...", "name": "Admissions Counsellor" },
      "group": null,
      "user": null,
      "createdBy": { "name": "Admin" }
    }
  ]
}

Create Assignment

POST /api/settings/layout-assignments

Request Body:

{
  "layoutId": "clx...",
  "entity": "Student",
  "layoutType": "LT_FORM",
  "assignmentType": "ASSIGN_ROLE",
  "roleId": "clx..."
}
FieldTypeRequiredDescription
layoutIdstringYesLayout to assign
entitystringYesEntity API name
layoutTypestringYesLayout type
assignmentTypestringYesASSIGN_PROFILE_TYPE, ASSIGN_ROLE, ASSIGN_GROUP, or ASSIGN_USER
profileTypestringConditionalRequired if assignmentType is ASSIGN_PROFILE_TYPE. Values: PROFILE_STUDENT, PROFILE_PARENT, PROFILE_STAFF, PROFILE_ADMIN, PROFILE_SUPER_ADMIN
roleIdstringConditionalRequired if assignmentType is ASSIGN_ROLE
groupIdstringConditionalRequired if assignmentType is ASSIGN_GROUP
userIdstringConditionalRequired if assignmentType is ASSIGN_USER
priorityOverridenumberNoOverride the default priority ordering

Duplicate Check: Returns 409 Conflict if an assignment already exists for the same entity + layoutType + assignmentType + target.

Cache: Automatically invalidates layout resolution cache for the affected entity.


Delete Assignment

DELETE /api/settings/layout-assignments?id={assignmentId}

Returns { success: true }. Invalidates layout resolution cache.


List All Entities

GET /api/settings/entities

Returns all registered ObjectDefinition records (both standard and dynamic), ordered by section and display order. Used by the Layout Manager UI for entity dropdowns.

Response:

{
  "data": [
    {
      "id": "clx...",
      "name": "Student",
      "apiName": "Student",
      "pluralName": "Students",
      "icon": "GraduationCap",
      "color": "#3b82f6",
      "section": "CORE",
      "isStandard": true,
      "displayOrder": 10
    },
    {
      "id": "clx...",
      "name": "Vehicle",
      "apiName": "Vehicle",
      "pluralName": "Vehicles",
      "icon": "Bus",
      "color": "#0284c7",
      "section": "OPERATIONS",
      "isStandard": false,
      "displayOrder": 11
    }
  ]
}

Sections: CORE, ADMIN, OPERATIONS, FINANCE


Seed Better Default Layouts

POST /api/admin/seed-better-layouts

Requires: SUPER_ADMIN or INSTITUTION_ADMIN role.

Replaces single-section default layouts with properly grouped multi-section layouts for all ~40 entities. Safe to call multiple times — updates existing defaults without duplicating.

What it does:

  • Updates existing default Form and Detail layouts with multi-section configs
  • Creates missing default layouts if they don't exist
  • Never touches non-default layouts (custom layouts are safe)

Response:

{
  "success": true,
  "updated": ["Student Form", "Student Detail", "Vehicle Form", "..."],
  "created": ["Concession Form", "Concession Detail"],
  "skipped": [],
  "message": "Updated 78, created 4, skipped 0 layouts."
}

Example layout structure after seeding:

Vehicle Form:

{
  "sections": [
    { "id": "basic", "title": "Vehicle Information", "columns": 2, "fields": ["registrationNo", "type", "make", "model", "capacity"] },
    { "id": "personnel", "title": "Personnel", "columns": 2, "fields": ["driverId", "conductorId"] },
    { "id": "compliance", "title": "Compliance & Expiry", "columns": 2, "fields": ["insuranceExpiry", "fitnessExpiry", "permitExpiry", "pucExpiry"] },
    { "id": "tracking", "title": "Tracking", "columns": 2, "fields": ["gpsDeviceId", "isActive"] }
  ]
}

Error Codes

StatusMeaning
401Not authenticated
403Insufficient permissions (admin-only endpoints)
404Layout or assignment not found
409Duplicate assignment — one already exists for this target