Skip to main content
DocsAPI ReferenceCollections API
Back to docs

Collections API

Collection CRUD, items, reorder, smart suggestions

api
collections

Collections API Reference

Base path: /api/collections

Collections organize H5P content items into ordered groups with optional curriculum metadata. Each collection supports Bloom's Taxonomy gap analysis to suggest content that fills cognitive-level gaps.


Endpoints

POST /api/collections

Create a new collection.

Auth: Teacher (JWT, teacherAuthMiddleware)

Request Body:

{
  "title": "Algebra Fundamentals",
  "description": "Core algebra exercises for Grade 8",
  "frameworkCode": "TR-MEB-2024",
  "frameworkName": "MEB 2024",
  "gradeCode": "grade-8",
  "gradeName": "8th Grade",
  "subjectCode": "math",
  "subjectName": "Mathematics",
  "topicCodes": ["algebra-basics", "equations"],
  "topicNames": ["Algebra Basics", "Equations"],
  "difficulty": "medium",
  "language": "tr"
}
FieldTypeRequiredConstraints
titlestringYes1-500 chars
descriptionstringNomax 2000 chars
frameworkCodestringNomax 50 chars
frameworkNamestringNomax 255 chars
gradeCodestringNomax 50 chars
gradeNamestringNomax 255 chars
subjectCodestringNomax 100 chars
subjectNamestringNomax 255 chars
topicCodesstring[]Noeach max 100 chars
topicNamesstring[]Noeach max 255 chars
difficultyenumNoeasy, medium, hard
languagestringNomax 10 chars

Response (201):

{
  "success": true,
  "data": {
    "id": "uuid",
    "userId": "uuid",
    "title": "Algebra Fundamentals",
    "description": "Core algebra exercises for Grade 8",
    "coverImageUrl": null,
    "visibility": "private",
    "frameworkCode": "TR-MEB-2024",
    "frameworkName": "MEB 2024",
    "gradeCode": "grade-8",
    "gradeName": "8th Grade",
    "subjectCode": "math",
    "subjectName": "Mathematics",
    "topicCodes": ["algebra-basics", "equations"],
    "topicNames": ["Algebra Basics", "Equations"],
    "difficulty": "medium",
    "language": "tr",
    "itemCount": 0,
    "createdAt": "2025-01-15T10:00:00.000Z",
    "updatedAt": "2025-01-15T10:00:00.000Z"
  }
}

Errors:

StatusErrorCause
400Validation error: ...Invalid request body
401User not foundJWT valid but user not in DB
500Failed to create collectionInternal error

GET /api/collections

List the authenticated user's collections with pagination.

Auth: Authenticated user (JWT, authMiddleware)

Query Parameters:

ParamTypeDefaultConstraints
offsetinteger0min 0
limitinteger201-50

Response (200):

{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "userId": "uuid",
      "title": "Algebra Fundamentals",
      "description": "Core algebra exercises for Grade 8",
      "coverImageUrl": null,
      "visibility": "private",
      "frameworkCode": "TR-MEB-2024",
      "frameworkName": "MEB 2024",
      "gradeCode": "grade-8",
      "gradeName": "8th Grade",
      "subjectCode": "math",
      "subjectName": "Mathematics",
      "topicCodes": ["algebra-basics"],
      "topicNames": ["Algebra Basics"],
      "difficulty": "medium",
      "language": "tr",
      "itemCount": 5,
      "createdAt": "2025-01-15T10:00:00.000Z",
      "updatedAt": "2025-01-15T12:00:00.000Z"
    }
  ],
  "total": 12
}

Collections are ordered by updatedAt DESC. The server-side limit cap is 100.

Errors:

StatusErrorCause
400Validation error: ...Invalid query parameters
401User not foundJWT valid but user not in DB
500Failed to list collectionsInternal error

GET /api/collections/:id

Get collection detail with enriched items. Items include H5P metadata, curriculum data, quality scores, ownership, and access status.

Auth: Authenticated user (JWT, authMiddleware)

Access rules: Owner can always view. Non-owners can view only if collection visibility is public.

Response (200):

{
  "success": true,
  "data": {
    "collection": {
      "id": "uuid",
      "userId": "uuid",
      "title": "Algebra Fundamentals",
      "visibility": "private",
      "itemCount": 2,
      "...": "..."
    },
    "items": [
      {
        "id": "uuid",
        "collectionId": "uuid",
        "contentId": "42",
        "position": 0,
        "addedAt": "2025-01-15T10:30:00.000Z",
        "title": "Quadratic Equations Quiz",
        "mainLibrary": "H5P.QuestionSet",
        "contentTypeSlug": "question-set",
        "authorId": "uuid",
        "authorName": "Teacher A",
        "status": "available",
        "curriculum": {
          "frameworkCode": "TR-MEB-2024",
          "frameworkName": "MEB 2024",
          "gradeCode": "grade-8",
          "gradeName": "8th Grade",
          "subjectCode": "math",
          "subjectName": "Mathematics",
          "topicCodes": ["equations"],
          "topicNames": ["Equations"],
          "difficulty": "medium",
          "language": "tr"
        },
        "quality": {
          "overallScore": 85,
          "dimensions": {}
        }
      }
    ]
  }
}

Item status values:

StatusMeaning
availableContent exists and is accessible to the requesting user
unavailableContent has been deleted or cannot be read from H5P storage
restrictedContent is private and belongs to another user

Errors:

StatusErrorCause
401User not foundJWT valid but user not in DB
404Collection not foundID does not exist or access denied
500Failed to get collection detailInternal error

PATCH /api/collections/:id

Update collection metadata. Only the owner can update.

Auth: Teacher (JWT, teacherAuthMiddleware)

Request Body: Any subset of the fields below.

{
  "title": "Updated Title",
  "description": "New description",
  "visibility": "public",
  "frameworkCode": "TR-MEB-2024",
  "frameworkName": "MEB 2024",
  "gradeCode": "grade-8",
  "gradeName": "8th Grade",
  "subjectCode": "math",
  "subjectName": "Mathematics",
  "topicCodes": ["algebra-basics"],
  "topicNames": ["Algebra Basics"],
  "difficulty": "hard",
  "language": "en"
}
FieldTypeConstraints
titlestring1-500 chars
descriptionstringmax 2000 chars
visibilityenumprivate, public
frameworkCodestringmax 50 chars
frameworkNamestringmax 255 chars
gradeCodestringmax 50 chars
gradeNamestringmax 255 chars
subjectCodestringmax 100 chars
subjectNamestringmax 255 chars
topicCodesstring[]each max 100 chars
topicNamesstring[]each max 255 chars
difficultyenumeasy, medium, hard
languagestringmax 10 chars

Response (200):

{
  "success": true,
  "message": "Collection updated"
}

Errors:

StatusErrorCause
400Validation error: ...Invalid request body
401User not foundJWT valid but user not in DB
404User does not own collectionNot the collection owner
500Failed to update collectionInternal error

DELETE /api/collections/:id

Delete a collection and all its items. Only the owner can delete.

Auth: Teacher (JWT, teacherAuthMiddleware)

Response (200):

{
  "success": true,
  "message": "Collection deleted"
}

Errors:

StatusErrorCause
401User not foundJWT valid but user not in DB
404User does not own collection / Collection not foundNot owner or does not exist
500Failed to delete collectionInternal error

POST /api/collections/:id/items

Add one or more content items to a collection. Content existence and accessibility are verified via H5P before adding. Items are appended at the end (next available position).

Auth: Teacher (JWT, teacherAuthMiddleware)

Request Body (single item):

{
  "contentId": "42"
}

Request Body (batch):

{
  "contentIds": ["42", "43", "44"]
}

One of contentId or contentIds must be provided.

FieldTypeConstraints
contentIdstringmax 100 chars
contentIdsstring[]each max 100 chars

Response (201, single):

{
  "success": true,
  "data": {
    "id": "uuid",
    "collectionId": "uuid",
    "contentId": "42",
    "position": 5,
    "addedAt": "2025-01-15T11:00:00.000Z"
  }
}

Response (201, batch):

{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "collectionId": "uuid",
      "contentId": "42",
      "position": 5,
      "addedAt": "2025-01-15T11:00:00.000Z"
    },
    {
      "id": "uuid",
      "collectionId": "uuid",
      "contentId": "43",
      "position": 6,
      "addedAt": "2025-01-15T11:00:00.000Z"
    }
  ]
}

Batch add uses ON CONFLICT DO NOTHING for duplicate content IDs within the same collection. The item_count on the collection is incremented only for actually inserted items.

Errors:

StatusErrorCause
400Either contentId or contentIds must be providedMissing both fields
401User not foundJWT valid but user not in DB
404Content {id} not found or not accessibleH5P content does not exist
404User does not own collectionNot the collection owner
409Item already existsDuplicate content in collection (single add)
500Failed to add item to collectionInternal error

DELETE /api/collections/:id/items/:itemId

Remove a single item from a collection. The itemId is the collection_item UUID, not the H5P content ID.

Auth: Teacher (JWT, teacherAuthMiddleware)

Response (200):

{
  "success": true,
  "message": "Item removed from collection"
}

Errors:

StatusErrorCause
401User not foundJWT valid but user not in DB
404Item not found in collectionItem ID does not exist in this collection
404User does not own collectionNot the collection owner
500Failed to remove item from collectionInternal error

PATCH /api/collections/:id/items/reorder

Reorder items within a collection by specifying new positions.

Auth: Teacher (JWT, teacherAuthMiddleware)

Request Body:

{
  "items": [
    { "id": "item-uuid-1", "position": 0 },
    { "id": "item-uuid-2", "position": 1 },
    { "id": "item-uuid-3", "position": 2 }
  ]
}
FieldTypeConstraints
itemsarraymin 1 element
items[].idstringUUID format
items[].positionintegermin 0

Response (200):

{
  "success": true,
  "message": "Items reordered"
}

Errors:

StatusErrorCause
400Validation error: ...Invalid request body
401User not foundJWT valid but user not in DB
404User does not own collectionNot the collection owner
500Failed to reorder itemsInternal error

GET /api/collections/:id/suggestions

Get smart content suggestions for a collection based on curriculum metadata and Bloom's Taxonomy gap analysis. Returns public content that matches the collection's curriculum filters, sorted so that content filling Bloom's gaps appears first.

Auth: Authenticated user (JWT, authMiddleware)

How it works:

  1. Reads the collection's existing items and resolves each item's H5P content type to a Bloom's level using the CONTENT_TYPE_BLOOMS_MAP.
  2. Computes a Bloom's distribution (percentage per level) and identifies gaps (levels with 0% coverage).
  3. Queries public content matching the collection's curriculum filters (frameworkCode, gradeCode, subjectCode, difficulty, language), excluding content already in the collection and content owned by the requesting user.
  4. Sorts suggestions so that content filling Bloom's gaps ranks first.

Bloom's ideal distribution (target):

LevelTarget %
Remember17.5
Understand17.5
Apply30.0
Analyze11.67
Evaluate11.67
Create11.66

Response (200):

{
  "success": true,
  "data": {
    "matchingContents": [
      {
        "contentId": "55",
        "title": "Interactive Sorting Exercise",
        "mainLibrary": "H5P.DragQuestion",
        "contentTypeSlug": "drag-question",
        "bloomsLevel": "apply",
        "curriculum": {
          "frameworkName": "MEB 2024",
          "stageName": "Middle School",
          "gradeName": "8th Grade",
          "subjectName": "Mathematics",
          "topicNames": ["Equations"],
          "difficulty": "medium",
          "language": "tr"
        }
      }
    ],
    "bloomsAnalysis": {
      "distribution": {
        "remember": 25,
        "understand": 25,
        "apply": 50,
        "analyze": 0,
        "evaluate": 0,
        "create": 0
      },
      "gaps": ["analyze", "evaluate", "create"],
      "score": 50
    }
  }
}

bloomsAnalysis fields:

FieldTypeDescription
distributionobjectPercentage of items at each Bloom's level (summing to ~100)
gapsstring[]Bloom's levels with 0% representation
scoreintegerPercentage of Bloom's levels that have at least one item (0-100)

Errors:

StatusErrorCause
401User not foundJWT valid but user not in DB
404Collection not foundID does not exist or access denied
500Failed to get suggestionsInternal error

Data Model

Collection

FieldTypeDescription
idUUIDAuto-generated primary key
userIdUUIDOwner user ID
titlestringCollection title
descriptionstringOptional description
coverImageUrlstringOptional cover image URL
visibilityenumprivate (default) or public
frameworkCodestringCurriculum framework code
frameworkNamestringCurriculum framework display name
gradeCodestringGrade level code
gradeNamestringGrade level display name
subjectCodestringSubject code
subjectNamestringSubject display name
topicCodesstring[]Topic codes
topicNamesstring[]Topic display names
difficultystringContent difficulty level
languagestringLanguage code
itemCountintegerNumber of items in collection
createdAtISO 8601Creation timestamp
updatedAtISO 8601Last update timestamp

CollectionItem

FieldTypeDescription
idUUIDAuto-generated primary key
collectionIdUUIDParent collection ID
contentIdstringH5P content ID
positionintegerSort order (0-based)
addedAtISO 8601Timestamp when added

Unique constraint: (collectionId, contentId) -- a content item can appear at most once in a collection.

Back to docsdocs/product/api/collections.md