POST /api/v1/lessons/{lessonId}/resources/upload
Deposits a file in the folder of that lesson, adds it to the school's media
library, and returns its mediaId, stored path and URL. No resource is
created: you send the returned mediaId to
Attach a resource when you are ready.
Merging the two would leave a resource attached to a form somebody then
abandons.
The body is multipart/form-data with one part named file.
| Role in the organization | This endpoint |
|---|
OWNER | Allowed |
ADMIN | Allowed |
MEMBER | Refused |
| Requirement | Rule for this endpoint |
|---|
| Business role | None — the permission is that of the lesson |
| Resource scope | Lesson of the school attached to the API key |
| Resource state | An archived program or course answers 403 |
Two things happen before anything reaches storage, and in this order: the
permission is checked, then the file name is validated. A refused caller and a
refused name both leave nothing behind.
| Parameter | Type | Required | Description |
|---|
lessonId | UUID | yes | Lesson visible from the key's school |
| Header | Required | Description |
|---|
x-api-key | yes | API key created for this school |
Content-Type | yes | multipart/form-data |
X-Correlation-Id | no | Caller correlation id, returned or generated |
No Idempotency-Key: a deposit claims no key, and every call writes a new
timestamped file. Requiring the header would promise a replay the storage does
not give.
Request body
| Part | Type | Required | Description |
|---|
file | file | yes | Up to 200 characters of file name. A name containing a path separator or a control character is refused, never rewritten |
curl -X POST "$COHORTE_API_BASE_URL/api/v1/lessons/$LESSON_ID/resources/upload" \
-H "x-api-key: $COHORTE_API_KEY" \
-F "file=@call-grid.pdf"
201 Created — the file is stored and listed in the school's media library.
400 Bad Request — no file part, an empty file, a refused file name, or a file over the size limit.
401 Unauthorized — the key is missing, invalid, or no longer attached to a member.
403 Forbidden — the bearer is not OWNER or ADMIN of this school.
404 Not Found — the lesson is unknown or belongs to another school.
| Field | Type | Nullable | Description |
|---|
success | boolean | no | true for a successful request |
data.mediaId | UUID | no | The media to send back when attaching the resource |
data.url | string | no | Public URL of the stored file |
data.storagePath | string | no | Stored path of the file, still accepted by the attach endpoint |
data.name | string | no | Original file name |
data.size | integer | no | Size in bytes |
data.type | string | no | MIME type |
correlationId | UUID | no | Correlation id for support |
{
"success": true,
"data": {
"mediaId": "1c7e9a35-6b2d-4f8a-8e41-3c4d5e6f7a81",
"url": "https://files.example.com/lessons/5d9f3a60-1c2b-4e7d-8f4a-6b7c8d9e0f1a/resource/48213-call-grid.pdf",
"name": "call-grid.pdf",
"size": 184220,
"type": "application/pdf",
"storagePath": "lessons/5d9f3a60-1c2b-4e7d-8f4a-6b7c8d9e0f1a/resource/48213-call-grid.pdf"
},
"correlationId": "0f6b1d92-5c3e-4a8b-9d71-3e2f4a6b8c10"
}
- Upload the file here.
- Attach it with
resourceType: "file" and the returned mediaId.
- Each lesson gets its own folder, so a file always says which lesson it came
from.
- Detaching a resource later never deletes the stored file.