Media
Media
Upload images and video once, then attach them to any number of posts via media_ids.
The media object
| Field | Type | Description |
|---|---|---|
id |
integer | Unique id. Pass to a post's media_ids. |
original_name |
string | The uploaded filename. |
mime_type |
string | e.g. image/jpeg, video/mp4. |
size_bytes |
integer | File size. |
cdn_url |
string | Public URL of the file. |
width / height |
integer|null | Pixel dimensions for images. |
duration |
number|null | Seconds, for video. |
folder |
string|null | Optional organizational folder. |
tags |
string[] | Optional tags. |
alt_text |
string|null | Accessibility text. |
Upload media
POST /api/media
Send as multipart/form-data.
| Field | Type | Required | Notes |
|---|---|---|---|
file |
file | yes | jpg, jpeg, png, gif, mp4, mov, webm. Max 100 MB. |
folder |
string | no | Organizational folder. |
tags |
string[] | no | Each tag ≤ 50 characters. |
alt_text |
string | no | ≤ 500 characters. |
curl -X POST https://schedulenchill.com/api/media \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-F "file=@./launch.png" \
-F "folder=product-launch" \
-F "tags[]=launch" \
-F "alt_text=Product launch screenshot"
Returns 201 Created with the media object. Use its id in a post's media_ids.
Building over MCP or from a server with a public file URL? Use the
upload_mediatool, which ingests media by URL instead of multipart upload.
Upload a video from your own computer
The single-request upload above is capped, and a large video in one request is fragile — one dropped connection and you start over. For anything big, open a resumable session and stream the file in chunks. Nothing is capped by request size, and an interrupted upload picks up where it stopped.
This is what your AI tool does when you say "upload ~/Videos/demo.mp4 and schedule it" —
the MCP upload_media tool with source="local" returns exactly the envelope below.
1. Open a session
POST /api/media/uploads
| Field | Type | Required | Notes |
|---|---|---|---|
filename |
string | yes | Original name, with extension. |
mime_type |
string | yes | e.g. video/mp4. |
size_bytes |
integer | yes | Exact size. Finalize rejects a mismatch. |
sha256 |
string | no | Hex digest. When given, finalize verifies against it. |
curl -X POST https://schedulenchill.com/api/media/uploads \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"filename":"demo.mp4","mime_type":"video/mp4","size_bytes":11402,
"sha256":"86e39c5a..."}'
{
"upload_id": "779b36fd-6d13-4c42-b3e5-c731956b093c",
"chunk_size": 8388608,
"received_bytes": 0,
"size_bytes": 11402,
"expires_at": "2026-08-04T07:35:44+00:00"
}
2. Stream the chunks
PATCH each chunk_size-byte slice as a raw body — not multipart — with offset set
to the running byte count (0, chunk_size, 2 × chunk_size, …).
curl -X PATCH "https://schedulenchill.com/api/media/uploads/UPLOAD_ID?offset=0" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @./chunk-0
{ "received_bytes": 11402, "size_bytes": 11402, "completed": true }
Send chunks one at a time, in order. Parallel PATCHes corrupt the assembled file.
If a chunk fails, re-GET the session to read received_bytes and resume from there —
that number is the source of truth, not your own bookkeeping.
3. Finalize
curl -X POST https://schedulenchill.com/api/media/uploads/UPLOAD_ID/complete \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
Returns the media object. Its id goes in a post's media_ids.
{ "id": 12, "original_name": "demo.mp4", "mime_type": "video/mp4", "size_bytes": 11402 }
Notes
- Use a token with
*abilities (the default). A restricted token 401s on the chunkPATCHes. /mcpand/api/*share one auth guard, so the same bearer works for both.- Sessions expire —
expires_atis in the envelope. Abandoned ones are pruned. DELETE /api/media/uploads/{id}cancels a session you no longer want.
List media
GET /api/media
Paginated, 15 per page. Optional filters:
| Query param | Description |
|---|---|
search |
Match filename. |
type |
image or video. |
folder |
Filter by folder. |
tags |
Filter by tag. |
page |
Page number. |
Retrieve media
GET /api/media/{id}
Update media
PUT /api/media/{id}
Update metadata only — folder, tags, alt_text. The file itself is immutable; upload a new file to replace it.
Delete media
DELETE /api/media/{id}
Returns 204 No Content.