Uploads
Upload media files (images and videos) to use in your posts. Media must be uploaded before creating a post.
Supported Formats
| Type | Formats | Max Size |
|---|---|---|
| Images | image/jpeg, image/png | 25 MB |
| Videos | video/mp4, video/quicktime (MOV) | 500 MB |
Each platform has additional size and format constraints. For example, Instagram images max at 8 MB and TikTok images max at 5 MB. These are validated when you create a post, not at upload time. See the Platform Settings pages for full details.
Security: Uploaded files are validated by sniffing the actual bytes (not the client-supplied Content-Type). Polyglot files / MIME-spoofed payloads are rejected. The detected MIME type is what gets stored. Never the client's claim.
Upload File
Upload a media file directly via multipart form data. Returns a media object with an id you can reference when creating posts.
/v1/uploadUpload a media fileRequest Body (multipart/form-data)
| Parameter | Type | Description |
|---|---|---|
file | binary | The media file to upload (image or video) |
thumbnail | binary | Optional poster image (JPEG/PNG, max 10 MB) for a video. Used as the dashboard preview tile. Ignored for images. |
Headers
| Parameter | Type | Description |
|---|---|---|
X-Workspace-Id | string | Required when using an all-scope API key. The workspace this media belongs to. |
curl -X POST https://api.quegly.com/v1/upload \
-H "Authorization: qgl_your_api_key" \
-F "file=@/path/to/room-photo.jpg"curl -X POST https://api.quegly.com/v1/upload \
-H "Authorization: qgl_your_api_key" \
-F "file=@/path/to/video.mp4"Response
{
"id": "e639003b-f727-4a1e-87bd-74a2c48ae41e",
"filename": "room-photo.jpg",
"url": "https://media.quegly.com/workspace-123/room-photo.jpg",
"media_type": "image",
"file_size": 2048576,
"thumbnail_url": null,
"width": null,
"height": null,
"created_at": "2026-05-15T12:00:00.000Z"
}Response Fields
| Parameter | Type | Description |
|---|---|---|
id | string | Unique media file ID. Use this in the media_ids array when creating posts. |
filename | string | Original filename |
url | string | Direct URL to the uploaded file |
media_type | string | "image" or "video" |
file_size | number | File size in bytes |
thumbnail_url | string | null | Video poster image URL (from an uploaded thumbnail or auto-generation). null for images and for videos with no poster. |
width | number | Width in pixels (may be null at upload time) |
height | number | Height in pixels (may be null at upload time) |
created_at | string | ISO 8601 timestamp |
Video thumbnails: the dashboard generates a poster frame in the browser before upload, which a server can't do. So for video uploaded via the API, either send a thumbnail image with the request (reliable, matches the dashboard), or, if the workspace has Cloudflare Media Transformations enabled, a poster is generated automatically from the first frame. Otherwise thumbnail_url is null and the tile is blank until played. Cosmetic only. Publishing is unaffected.
Upload from URL
Upload a media file by providing a publicly accessible URL. Quegly downloads the file server-side via an SSRF-safe fetcher (private IPs / loopback / non-http schemes are rejected) and stores it. Useful for AI agents that produce URLs but not bytes (e.g. OpenAI image generation).
/v1/upload-from-urlUpload a file from a URLRequest Body (JSON)
| Parameter | Type | Description |
|---|---|---|
url | string | Publicly accessible URL of the media file to download |
filename | string | Optional filename. If not provided, extracted from the URL. |
curl -X POST https://api.quegly.com/v1/upload-from-url \
-H "Authorization: qgl_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://oaidalleapiprodscus.blob.core.windows.net/generated-image.png",
"filename": "ai-room-design.png"
}'Response
Returns the same MediaFile object as the Upload File endpoint.
The URL must be publicly accessible (no authentication required). Pre-signed URLs from S3 / R2 / OpenAI work well. The fetcher rejects non-http(s) schemes, embedded credentials, and private/loopback IPs to prevent SSRF abuse.
Update Video Thumbnail
Set or replace the poster image of an already-uploaded video. {id} is the media ID returned by the Upload endpoints. The thumbnail becomes the cover used on Instagram and YouTube (TikTok picks its own), and the preview tile in the dashboard. Any post referencing this media that is still scheduled or incomplete gets the new cover too; already-published posts keep the cover they went out with.
/v1/media/{id}/thumbnailSet or replace a video's thumbnailRequest Body (multipart/form-data)
| Parameter | Type | Description |
|---|---|---|
thumbnail | binary | JPEG or PNG poster image, max 5 MB |
Or a link (application/json)
| Parameter | Type | Description |
|---|---|---|
url | string | A public link to a JPEG or PNG, max 5 MB. Downloaded the same SSRF-safe way as Upload from URL; the bytes decide its type. This is how AI agents and the MCP server set a cover. |
curl -X POST https://api.quegly.com/v1/media/MEDIA_ID/thumbnail \
-H "Authorization: qgl_your_api_key" \
-F "thumbnail=@/path/to/poster.jpg"curl -X POST https://api.quegly.com/v1/media/MEDIA_ID/thumbnail \
-H "Authorization: qgl_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "url": "https://example.com/poster.jpg" }'Response
{
"id": "e639003b-f727-4a1e-87bd-74a2c48ae41e",
"thumbnail_url": "https://media.quegly.com/thumbnails/...jpg",
"posts_updated": 2
}Response Fields
| Parameter | Type | Description |
|---|---|---|
id | string | The media file ID |
thumbnail_url | string | Public URL of the new thumbnail |
posts_updated | number | How many still-pending (scheduled/draft) posts had their cover refreshed |
/v1/media/{id}/thumbnailRemove a video's thumbnailRemoves the poster and clears it from still-pending posts. Idempotent: deleting a thumbnail that isn't there returns success. Constraints for both endpoints: videos only (images are their own preview), the media file must still exist in storage, and the per-key upload rate limit applies to the POST.
Media Lifecycle
Uploaded media files are stored in object storage until the post is published. After successful publishing, files are cleaned up to keep storage costs predictable. The media metadata and IDs remain in the system for analytics and history.
| Stage | Media Status |
|---|---|
| Uploaded | File stored, ready to attach to posts |
| Attached to post | Referenced by a post's media_ids |
| Post published | File delivered to platforms, then cleaned up from storage |
| Post failed | File retained for retry attempts |