Curriculum Management

Define and manage curriculum structures within TimeBack using the CASE (Competency and Academic Standards Exchange) framework — enabling learning app developers to create subjects, documents, competency items, and hierarchical relationships that power outcomes-based education.

Note: This guide covers common patterns and the integration workflow. For complete endpoint documentation, all parameters, and example requests, see the API Reference.

What Is CASE?

CASE is a 1EdTech standard for exchanging competency and curriculum frameworks. TimeBack implements the CASE 1.1 specification, providing a RESTful API at the /case/1.1/ path prefix for defining and querying curriculum structures.

CASE provides the curriculum layer that other TimeBack features build on. For example, the Competency Track feature references CASE CFItems as the competencies students must master to earn credentials.

Key Concepts

A CASE curriculum framework is built from a hierarchy of entities:

Entity Role
CFSubject A subject area (e.g., "Mathematics", "English Language Arts"). Shared across apps — browse existing subjects before creating curriculum.
CFDocument The root of a curriculum framework. Typically one per app or curriculum standard. Creating a document automatically creates its containing CFPackage.
CFPackage A read-only container that holds a document plus all of its items, associations, definitions, and rubrics. Retrieved via GET /case/1.1/CFPackages/{sourcedId}.
CFDefinition A read-only catalog of the concepts, subjects, licenses, item types, and association groupings available within a package. Populated automatically as you create and associate entities.
CFItem An individual competency or learning statement within a document (e.g., "Solve linear equations in one variable").
CFItemType A classification for items (e.g., "Unit", "Lesson", "Standard"). Optional — use when you need to distinguish item granularity.
CFItemAssociation A typed relationship between two items — used to build hierarchy (isChildOf), sequencing (precedes), equivalence (exactMatchOf), and more.

Typical flow: Browse subjects → Create a document (and its package) → Optionally define custom item types → Create items → Link items into a hierarchy via associations.

Prerequisites

Before integrating with the CASE API:

  1. Register your app with TimeBack (see Level 0: Registration)
  2. Obtain OAuth credentials with CASE-specific scopes (see Authentication)

Authentication Scopes

CASE endpoints require Cognito authorization with one or more of these scopes:

Scope Grants
https://purl.imsglobal.org/spec/case/v1p0/scope/case.readonly Read access to all CASE entities
https://purl.imsglobal.org/spec/case/v1p0/scope/case.createput Create or update documents, items, item types, and associations
https://purl.imsglobal.org/spec/case/v1p0/scope/case.delete Delete item associations

Include your access token in all requests:

const response = await fetch('https://platform.timeback.com/case/1.1/...', {
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${accessToken}`,
  },
});

Browsing Existing Subjects

Subjects are shared across all apps on the platform. Before creating curriculum, browse existing subjects to find relevant subject areas.

List all subjects

GET /case/1.1/CFSubjects?limit=20&offset=0
const response = await fetch('https://platform.timeback.com/case/1.1/CFSubjects?limit=20&offset=0', {
  headers: { Authorization: `Bearer ${accessToken}` },
});

const data = await response.json();
// data.CFSubjects — array of subject objects
// data.total — total number of available subjects
// data.offset, data.limit — pagination info

Get a specific subject

GET /case/1.1/CFSubjects/{sourcedId}
const response = await fetch(`https://platform.timeback.com/case/1.1/CFSubjects/${subjectId}`, {
  headers: { Authorization: `Bearer ${accessToken}` },
});

const data = await response.json();
// data.CFSubjects — array containing the subject and its children

Creating a Curriculum Framework

A curriculum framework starts with a CFDocument. When you create a document, TimeBack automatically creates the associated CFPackage using the CFPackageURI you provide. There is no separate endpoint for creating packages — they are always co-created with their document.

Create a document (and its package)

PUT /case/1.1/CFDocuments/{sourcedId}

All PUT endpoints are idempotent upserts — if a document with the given sourcedId already exists, it is updated. The identifier in the request body must match the sourcedId in the path.

const documentId = 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d';
const packageId = 'b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e';

const response = await fetch(`https://platform.timeback.com/case/1.1/CFDocuments/${documentId}`, {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    identifier: documentId,
    uri: `urn:uuid:${documentId}`,
    creator: 'My Learning App',
    title: 'Grade 3 Mathematics Curriculum',
    caseVersion: '1.1',
    lastChangeDateTime: new Date().toISOString(),
    subject: ['Mathematics'],
    subjectURI: [
      {
        title: 'Mathematics',
        identifier: 'c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f',
        uri: 'urn:uuid:c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f',
      },
    ],
    CFPackageURI: {
      title: 'Grade 3 Mathematics Curriculum',
      identifier: packageId,
      uri: `urn:uuid:${packageId}`,
    },
  }),
});
// Returns 201 with no body

Required fields: identifier, uri, creator, title, caseVersion (must be "1.1"), lastChangeDateTime, CFPackageURI

Subject linking: Include subjectURI to associate the document with existing subjects. When you update a document, the subject associations are synced automatically — removed subjects are unlinked, new subjects are added.

Retrieve the full package

Once you've created a document and added items, retrieve the complete package view:

GET /case/1.1/CFPackages/{sourcedId}

The package response includes the document, all items, associations, definitions (concepts, subjects, item types, licenses, association groupings), and rubrics in a single response.

Defining Custom Item Types

Item types let you classify items by granularity — for example, distinguishing "Unit" from "Lesson" from "Standard". This is optional; items work without a type.

Check for existing item types

Before creating a new type, check if a suitable one already exists:

GET /case/1.1/CFItemTypes/{sourcedId}

The response includes the requested item type and any children in its hierarchy.

Create an item type

PUT /case/1.1/CFItemTypes/{sourcedId}
const itemTypeId = 'd4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f80';

const response = await fetch(`https://platform.timeback.com/case/1.1/CFItemTypes/${itemTypeId}`, {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    identifier: itemTypeId,
    uri: `urn:uuid:${itemTypeId}`,
    title: 'Learning Standard',
    description: 'An individual measurable learning standard',
    hierarchyCode: 'LS',
    lastChangeDateTime: new Date().toISOString(),
  }),
});
// Returns 201 with no body

Required fields: identifier, uri, title, description, hierarchyCode, lastChangeDateTime

Defining Items and Building Hierarchy

CFItems are the individual competency statements within a document. After creating items, you connect them into a hierarchy using CFItemAssociations.

Create an item

PUT /case/1.1/CFItems/{sourcedId}
const itemId = 'e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8091';

const response = await fetch(`https://platform.timeback.com/case/1.1/CFItems/${itemId}`, {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    item: {
      identifier: itemId,
      uri: `urn:uuid:${itemId}`,
      fullStatement:
        'Solve linear equations in one variable, including equations with coefficients represented by letters',
      humanCodingScheme: '3.OA.A.1',
      educationLevel: ['03'],
      CFItemType: 'Learning Standard',
      CFItemTypeURI: {
        title: 'Learning Standard',
        identifier: 'd4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f80',
        uri: 'urn:uuid:d4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f80',
      },
      CFDocumentURI: {
        title: 'Grade 3 Mathematics Curriculum',
        identifier: 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d',
        uri: 'urn:uuid:a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d',
      },
      lastChangeDateTime: new Date().toISOString(),
    },
  }),
});
// Returns 201 with no body

Required fields: identifier, fullStatement, uri, lastChangeDateTime, CFDocumentURI

Optional but common: humanCodingScheme (human-readable code), educationLevel, CFItemType/CFItemTypeURI (item classification), subject/subjectURI (subject linking), conceptKeywords/conceptKeywordsURI (keyword tagging)

Like documents, subject associations on items are synced automatically when you update an item with a modified subjectURI array. Keyword associations via conceptKeywordsURI are additive — duplicates are ignored.

Build hierarchy with associations

Use CFItemAssociations to connect items into a tree structure. The isChildOf association type creates parent-child relationships:

PUT /case/1.1/CFItemAssociations/{sourcedId}
const associationId = 'f6a7b8c9-d0e1-4f2a-3b4c-5d6e7f809102';
const childItemId = 'e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8091';
const parentItemId = 'a7b8c9d0-e1f2-4a3b-4c5d-6e7f80910213';

const response = await fetch(`https://platform.timeback.com/case/1.1/CFItemAssociations/${associationId}`, {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    association: {
      identifier: associationId,
      uri: `urn:uuid:${associationId}`,
      associationType: 'isChildOf',
      originNodeURI: {
        title: 'Solve linear equations',
        identifier: childItemId,
        uri: `urn:uuid:${childItemId}`,
      },
      destinationNodeURI: {
        title: 'Operations & Algebraic Thinking',
        identifier: parentItemId,
        uri: `urn:uuid:${parentItemId}`,
      },
      lastChangeDateTime: new Date().toISOString(),
    },
  }),
});
// Returns 201 with no body

Required fields: identifier, uri, associationType, originNodeURI, destinationNodeURI, lastChangeDateTime

Association types

Type Meaning Example
isChildOf Structural parent-child hierarchy "Solve equations" is a child of "Algebraic Thinking"
isPartOf Inclusion or composition Item is part of a larger concept
isPeerOf Peer relationship Two items at the same level
exactMatchOf Equivalence to another item Cross-framework alignment
precedes Sequential ordering "Addition" precedes "Multiplication"
isRelatedTo Generic relationship Loosely connected items
replacedBy Deprecation or supersession Old standard replaced by new one
exemplar Best-practice example Item exemplifies a concept
hasSkillLevel Skill level definition Item defines a proficiency level
isTranslationOf Translation link English version linked to Spanish version

A unique constraint exists on (originItemId, destinationItemId, associationType) — you cannot create duplicate associations of the same type between the same two items.

Retrieve an item with its associations

GET /case/1.1/CFItemAssociations/{sourcedId}

Returns the item and all of its associations in a single response:

const response = await fetch(`https://platform.timeback.com/case/1.1/CFItemAssociations/${itemId}`, {
  headers: { Authorization: `Bearer ${accessToken}` },
});

const data = await response.json();
// data.CFItem — the item
// data.CFAssociations — array of all associations for this item

Deleting and Inactivating

CASE entities and associations have different deletion semantics:

Entities (soft delete)

CFDocuments, CFItems, CFItemTypes, and other entities use soft deletion. When an entity is deleted, its deletedAt timestamp is set rather than the record being removed from the database. Soft-deleted entities are automatically excluded from query results.

There are no REST endpoints for soft-deleting entities directly — soft deletion is managed internally by the platform (e.g., during sync operations).

Associations (hard delete)

Item associations can be permanently removed via the DELETE endpoint. This is the only DELETE operation available in the CASE API:

DELETE /case/1.1/CFItemAssociations/{sourcedId}
const response = await fetch(`https://platform.timeback.com/case/1.1/CFItemAssociations/${associationId}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${accessToken}` },
});
// Returns 204 with no body
// Returns 404 if the association does not exist

This requires the case.delete scope. The association is permanently removed — this is a hard delete, not a soft delete.

API Endpoints

All CASE endpoints are under the /case/1.1/ path prefix and require Cognito authorization.

Documents

Method Path Scope Description
GET /case/1.1/CFDocuments readonly List all documents (paginated)
GET /case/1.1/CFDocuments/{sourcedId} readonly Get a specific document
PUT /case/1.1/CFDocuments/{sourcedId} createput Create or update a document (and its package)

Items

Method Path Scope Description
GET /case/1.1/CFItems/{sourcedId} readonly Get a specific item
PUT /case/1.1/CFItems/{sourcedId} createput Create or update an item

Packages

Method Path Scope Description
GET /case/1.1/CFPackages/{sourcedId} readonly Get a package (document + items + associations + definitions + rubrics)

Associations

Method Path Scope Description
GET /case/1.1/CFAssociations/{sourcedId} readonly Get a specific association
GET /case/1.1/CFItemAssociations/{sourcedId} readonly Get an item and all of its associations
PUT /case/1.1/CFItemAssociations/{sourcedId} createput Create or update an item association
DELETE /case/1.1/CFItemAssociations/{sourcedId} delete Delete an item association

Definitions

Method Path Scope Description
GET /case/1.1/CFSubjects readonly List all subjects (paginated)
GET /case/1.1/CFSubjects/{sourcedId} readonly Get a specific subject
GET /case/1.1/CFConcepts/{sourcedId} readonly Get a specific concept
GET /case/1.1/CFItemTypes/{sourcedId} readonly Get a specific item type
PUT /case/1.1/CFItemTypes/{sourcedId} createput Create or update an item type
GET /case/1.1/CFLicenses/{sourcedId} readonly Get a specific license
GET /case/1.1/CFAssociationGroupings/{sourcedId} readonly Get a specific association grouping

Rubrics

Method Path Scope Description
GET /case/1.1/CFRubrics/{sourcedId} readonly Get a specific rubric

Authentication

Obtain OAuth client credentials and access tokens required for calling CASE endpoints.

OneRoster API Conventions

Pagination, filtering, sorting, and field selection conventions used by CASE list endpoints (CFDocuments, CFSubjects).

Competency Track

Use CASE CFItems as the competencies in mastery-based learning tracks — define learning blocks, assign them to students, and issue mastery credentials.

Content Ingestion

Publish learning content (QTI assessments, Common Cartridge packages) that can be mapped to curriculum items defined via CASE.