All Docs
FeaturesCSI Teachable Replacement AppUpdated March 13, 2026

Lesson Attachment Upload & Management

Lesson Attachment Upload & Management

Instructors can enrich lessons by attaching downloadable files — PDFs, images, and other documents — directly to any lesson. The platform handles secure upload URL generation, metadata persistence, and deletion through a straightforward API.


Overview

The attachment workflow has four stages:

StageDescription
1. Request presigned URLAsk the API for a short-lived URL scoped to a specific lesson and file.
2. Upload to storagePUT the file binary directly to the presigned URL (no platform server in the data path).
3. Confirm attachmentNotify the API that the upload is complete; metadata is persisted and the attachment becomes visible to learners.
4. Delete attachmentRemove an attachment; both the stored object and its metadata record are deleted.

Supported File Types

  • PDF documents (.pdf)
  • Images (.png, .jpg, .gif, .webp, etc.)
  • General downloadable files

Workflow

Step 1 — Request a Presigned Upload URL

Before uploading, request a presigned URL from the platform. Provide the target lesson ID, the intended filename, and the MIME type.

POST /api/lessons/{lessonId}/attachments/presigned-url
Content-Type: application/json
Authorization: Bearer <token>

{
  "filename": "module-1-workbook.pdf",
  "contentType": "application/pdf",
  "fileSize": 204800
}

Response

{
  "uploadUrl": "https://storage.example.com/...",
  "attachmentId": "att_01HXZ...",
  "expiresAt": "2025-01-01T12:05:00Z"
}
  • uploadUrl — The presigned URL. Use this in Step 2.
  • attachmentId — The pending attachment identifier. Use this in Step 3.
  • expiresAt — The URL expires at this time; request a new one if the upload is delayed.

Step 2 — Upload the File

Send the file binary directly to the presigned URL using an HTTP PUT request. Set the Content-Type header to match the value provided in Step 1.

PUT {uploadUrl}
Content-Type: application/pdf

<binary file content>

A 200 OK response from storage confirms the upload succeeded.

Note: Do not include your platform Authorization header when calling the presigned URL — it is pre-authenticated.


Step 3 — Confirm and Persist the Attachment

Once the upload to storage succeeds, confirm the attachment with the platform API. This persists the metadata and makes the attachment accessible to learners.

POST /api/lessons/{lessonId}/attachments/{attachmentId}/confirm
Authorization: Bearer <token>

Response

{
  "id": "att_01HXZ...",
  "lessonId": "les_01ABC...",
  "filename": "module-1-workbook.pdf",
  "contentType": "application/pdf",
  "fileSize": 204800,
  "createdAt": "2025-01-01T12:01:30Z"
}

Step 4 — Delete an Attachment

To remove an attachment, call the delete endpoint. This deletes both the file from storage and the metadata record.

DELETE /api/lessons/{lessonId}/attachments/{attachmentId}
Authorization: Bearer <token>

Response

204 No Content

Listing Attachments

Retrieve all attachments for a given lesson:

GET /api/lessons/{lessonId}/attachments
Authorization: Bearer <token>

Response

[
  {
    "id": "att_01HXZ...",
    "filename": "module-1-workbook.pdf",
    "contentType": "application/pdf",
    "fileSize": 204800,
    "createdAt": "2025-01-01T12:01:30Z"
  }
]

Error Handling

StatusMeaning
400 Bad RequestMissing or invalid fields (e.g. no filename or unsupported contentType).
401 UnauthorizedMissing or invalid bearer token.
403 ForbiddenAuthenticated user does not have instructor access to this lesson.
404 Not FoundLesson or attachment ID does not exist.
410 GonePresigned URL has expired — request a new one.

Notes

  • Presigned URLs are short-lived. Complete the upload promptly after requesting the URL.
  • Confirming an upload that was never completed will result in a broken attachment record; always verify the storage PUT succeeded before calling confirm.
  • Deleting a lesson also removes all of its attachments.