Campus One

Academic Reference Data

Resolve the faculty_id and department_id claims you receive at sign-in to human-readable names by reading Campus One's faculty and department catalog.

Academic Reference Data API

When a student signs in with the academic scope, Campus One returns faculty_id and department_id claims. These are stable Campus One identifiers — not display names. To show "Faculty of Engineering" instead of fac_eng, or to match the student into your own faculties / departments tables, you need the catalog those IDs come from.

These two read-only endpoints expose that catalog so your app can map the IDs once and keep its own tables in sync.

  • GET /api/apps/faculties — every faculty, each with its departments nested.
  • GET /api/apps/departments — a flat list of every department, each carrying its facultyId and facultyName.

Authentication & Authorization

These are standard Connected App API routes and use the same Bearer auth as every other /api/apps/* endpoint.

  • Required scope: academic
  • Method: Bearer Token Authentication
  • Header format: Authorization: Bearer <access_token>
  • Admin prerequisite: the permAcademic flag must be enabled for your app (it is on by default) under Permissions in the developer dashboard.

The token must carry the academic scope — the same scope that delivers the faculty_id / department_id claims you are resolving. A token without it returns 403. See Permissions & Scopes.

[!NOTE] This catalog is platform-wide reference data, not per-student data, so the response is identical for every authorized user. The response is cached server-side for one hour, so changes to the catalog (rare) may take up to an hour to appear.


REST API Reference

List faculties

GET /api/apps/faculties

Returns every faculty ordered by name, each with its departments nested (also ordered by name). Use this when you want the faculty → department hierarchy in a single call.

Headers

HeaderTypeDescription
AuthorizationstringRequired. Bearer <access_token> containing the academic scope.

List departments

GET /api/apps/departments

Returns a flat list of every department ordered by name. Each row includes facultyId and facultyName, so you can resolve a student's department_id to a name (and its parent faculty) without joining anything client-side.

Headers

HeaderTypeDescription
AuthorizationstringRequired. Bearer <access_token> containing the academic scope.

Example Integration

A typical flow: at sign-in you receive department_id in the claims; you call GET /api/apps/departments once, build a Map<id, name>, and cache it.

# Faculties with nested departments
curl https://auth.campusone.com.ng/api/apps/faculties \
  -H "Authorization: Bearer c1_act_abc123xyz"

# Flat department list
curl https://auth.campusone.com.ng/api/apps/departments \
  -H "Authorization: Bearer c1_act_abc123xyz"
// Build a lookup from department_id -> { name, faculty } once, then reuse it
// to resolve the `department_id` claim you get at sign-in.
const loadDepartments = async (accessToken) => {
  const response = await fetch(
    'https://auth.campusone.com.ng/api/apps/departments',
    { headers: { Authorization: `Bearer ${accessToken}` } }
  );

  if (!response.ok) {
    const err = await response.json();
    throw new Error(`Failed to load departments: ${err.message ?? err.error}`);
  }

  const departments = await response.json();
  return new Map(
    departments.map((d) => [d.id, { name: d.name, faculty: d.facultyName }])
  );
};

const byId = await loadDepartments(accessToken);
const dept = byId.get(claims.department_id); // { name, faculty }
import requests

headers = {"Authorization": "Bearer c1_act_abc123xyz"}

res = requests.get(
    "https://auth.campusone.com.ng/api/apps/departments",
    headers=headers,
)
res.raise_for_status()

# department_id -> { "name", "faculty" }
by_id = {
    d["id"]: {"name": d["name"], "faculty": d["facultyName"]}
    for d in res.json()
}

dept = by_id.get(claims["department_id"])

Response Schemas

[!NOTE] The live, always-accurate schemas are published at the interactive API reference. The examples below are illustrative.

GET /api/apps/faculties → 200 OK

An array of faculties, each with its departments nested.

[
  {
    "id": "fac_eng",
    "name": "Faculty of Engineering",
    "slug": "engineering",
    "createdAt": "2026-01-10T08:00:00.000Z",
    "departments": [
      {
        "id": "dept_cs",
        "name": "Computer Science",
        "slug": "computer-science",
        "maxLevel": 400,
        "facultyId": "fac_eng",
        "createdAt": "2026-01-10T08:00:00.000Z"
      }
    ]
  }
]

GET /api/apps/departments → 200 OK

A flat array of departments, each carrying its parent faculty.

[
  {
    "id": "dept_cs",
    "name": "Computer Science",
    "slug": "computer-science",
    "maxLevel": 400,
    "facultyId": "fac_eng",
    "facultyName": "Faculty of Engineering"
  }
]

[!TIP] maxLevel is the highest level a student in that department can reach (e.g. 400 or 500). The final_year claim is true once a student's level equals their department's maxLevel.

Error responses

A 401 (authentication) is rejected at the gateway and returns { "error": "..." }. A 403 (authorization) comes from the endpoint and returns the richer { code, status, message } object. See Status Codes & Errors for the canonical reference.

{ "defined": false, "code": "FORBIDDEN", "status": 403, "message": "Token lacks 'academic' scope" }
StatusBodyCause
200arrayRequest succeeded; body is the faculty or department list.
401{ error }Bearer token missing, malformed, expired, revoked, or not bound to a user.
403{ code, status, message }Token lacks the academic scope, or the app's permAcademic flag is disabled.

On this page