Files Handling API (NEW)
Author : Josh S. Sakweli, Backend Lead Team
Last Updated : 2026-06-21
Version : v1.0
Base URL : https://your-api-domain.com/api/v1
Short Description : This document covers everything a frontend developer needs to handle files on the NexGate/Veepii platform — uploading, tracking processing progress, reading variant URLs from entity responses, and downloading private files. Files are managed by an internal service called FileThunder ; the frontend never talks to FileThunder directly. All file-related operations go through the main backend endpoints documented here.
Hints :
All upload endpoints require a valid Bearer token
Files are never uploaded through the backend server — you upload directly to object storage using a time-limited presigned URL returned by the backend
The backend stores only object key paths; full CDN/MinIO URLs are assembled at response time — always use the URLs in entity responses as-is
Processing is asynchronous — after uploading, you track progress via SSE or polling, then the entity response will include the resolved variant map once processing is complete
Private files (digital products, DM documents) are never served via CDN — always request a fresh download URL before initiating a download
How File Handling Works — Big Picture
Understanding this flow will save you from confusion. There are two separate progress concepts :
Upload progress — bytes travelling from the client to object storage. You can show a progress bar for this using XMLHttpRequest .
Processing progress — FileThunder processing those bytes into variants (WebP images, transcoded video resolutions, virus scans). You track this via SSE or polling.
┌─────────┐ Step 1: Request presigned URL ┌──────────────┐
│ Client │ ──────────────────────────────────────► │ Main Backend │
│ │ ◄────────────────────────────────────── │ │
│ │ { fileId, presignedUrl, expiresIn } └──────────────┘
│ │
│ │ Step 2: PUT file bytes directly ┌─────────┐
│ │ ────────────────────────────────────────► │ MinIO │
│ │ ◄──────────────────────────────────────── │ │
│ │ HTTP 200 (upload complete) └────┬────┘
│ │ │ MinIO fires event
│ │ Step 3: Open SSE stream ▼
│ │ ──────────────────────────────────────► ┌──────────────┐
│ │ ◄── status events (PROCESSING, READY) ── │ Main Backend │
└─────────┘ └──────────────┘
│ on READY
▼
Variants saved to entity in DB
Entity response includes variant URLs
Standard Response Format
Success Response Structure
{
"success": true,
"httpStatus": "OK",
"message": "Operation completed successfully",
"action_time": "2025-09-23T10:30:45",
"data": {}
}
Error Response Structure
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Error description",
"action_time": "2025-09-23T10:30:45",
"data": "Error description"
}
Standard Response Fields
Field
Type
Description
success
boolean
true for success, false for errors
httpStatus
string
HTTP status name (OK, BAD_REQUEST, NOT_FOUND, etc.)
message
string
Human-readable result description
action_time
string
ISO 8601 timestamp of the response
data
object/string
Response payload or error details
HTTP Method Badge Standards
GET — GET
POST — POST
PUT — PUT
File Contexts
Every upload must declare a context . Context tells FileThunder what this file is for, which determines how it is processed, what variants are generated, and how it is stored.
Context
Domain
What it is
Who uploads it
SOCIAL_IMAGE
Posts
Image attached to a post or story
Authenticated user
SOCIAL_VIDEO
Posts
Video attached to a post or story
Authenticated user
PROFILE_PICTURE
Profiles
User avatar / profile photo
Authenticated user
COVER_PHOTO
Profiles
Profile cover / banner image
Authenticated user
DM_IMAGE
Messages
Image sent in a direct message
Authenticated user
DM_VIDEO
Messages
Video sent in a direct message
Authenticated user
DM_DOCUMENT
Messages
Document sent in a direct message
Authenticated user
PRODUCT_IMAGE
Products
Product listing photo
Shop owner
PRODUCT_VIDEO
Products
Product demo/preview video
Shop owner
DIGITAL_PRODUCT
Products
Purchasable digital file (PDF, ZIP, software, etc.)
Shop owner
SHOP_BANNER
Shops
Shop header banner image
Shop owner
SHOP_LOGO
Shops
Shop logo / avatar
Shop owner
EVENT_COVER
Events
Event banner/hero image
Event organiser
EVENT_GALLERY
Events
Additional event gallery image
Event organiser
File Format & Size Constraints
These are the accepted formats and recommended limits per context. FileThunder enforces the actual limits server-side — passing incorrect mimeType or oversized files will result in a rejection at the presigned URL stage.
Images
Context
Accepted MIME Types
Max Size
Min Dimensions
Recommended Dimensions
SOCIAL_IMAGE
image/jpeg , image/png , image/webp , image/gif
20 MB
200 × 200 px
1080 × 1080 px (square) or 1080 × 1920 px (portrait)
PROFILE_PICTURE
image/jpeg , image/png , image/webp
10 MB
100 × 100 px
400 × 400 px square
COVER_PHOTO
image/jpeg , image/png , image/webp
15 MB
600 × 200 px
1500 × 500 px
DM_IMAGE
image/jpeg , image/png , image/webp , image/gif
20 MB
—
—
PRODUCT_IMAGE
image/jpeg , image/png , image/webp
20 MB
400 × 400 px
1000 × 1000 px square
SHOP_BANNER
image/jpeg , image/png , image/webp
15 MB
800 × 200 px
1200 × 400 px
SHOP_LOGO
image/jpeg , image/png , image/webp
5 MB
100 × 100 px
400 × 400 px square
EVENT_COVER
image/jpeg , image/png , image/webp
15 MB
800 × 400 px
1200 × 630 px
EVENT_GALLERY
image/jpeg , image/png , image/webp
20 MB
200 × 200 px
1080 × 1080 px
Videos
Context
Accepted MIME Types
Max Size
Max Duration
Notes
SOCIAL_VIDEO
video/mp4 , video/quicktime , video/webm , video/x-msvideo , video/x-matroska
100 MB
60 min
Videos ≥ 3 min get HLS adaptive streaming
DM_VIDEO
video/mp4 , video/quicktime , video/webm
100 MB
60 min
Always sequential MP4 transcoding
PRODUCT_VIDEO
video/mp4 , video/quicktime , video/webm , video/x-msvideo , video/x-matroska
100 MB
60 min
Videos ≥ 3 min get HLS adaptive streaming
Other
Context
Accepted MIME Types
Max Size
Notes
DM_DOCUMENT
application/pdf , application/msword , application/vnd.openxmlformats-officedocument.wordprocessingml.document , application/vnd.ms-excel , application/vnd.openxmlformats-officedocument.spreadsheetml.sheet , application/zip , text/plain
50 MB
ClamAV scanned; no variants generated
DIGITAL_PRODUCT
Any — PDF, ZIP, EXE, APK, MP3, etc.
5 GB
ClamAV dual-scan + SHA-256 deduplication; never CDN served; always presigned download
Processing Status Lifecycle
After the file reaches object storage, FileThunder processes it through these states. You will receive these values from both the SSE stream and the status polling endpoint.
PENDING ──► UPLOADING ──► UPLOADED ──► SCANNING ──► PROCESSING ──► READY
└──► FAILED
│
LIVE_PARTIAL
(video 360p is done,
higher resolutions
still processing)
Status
Meaning
UI suggestion
PENDING
Upload slot created, waiting for file bytes
Show spinner
UPLOADING
File bytes are being received by storage
Show upload progress bar (XHR)
UPLOADED
All bytes received, handing off to processing
Show spinner
SCANNING
ClamAV virus scan in progress (digital products / DM docs only)
"Scanning for safety..."
PROCESSING
Transcoding / image variant generation in progress
"Processing..."
LIVE_PARTIAL
Videos only — 360p variant is ready, higher resolutions still processing
Show video with 360p, overlay "HD processing" badge
READY
All variants generated and available
Dismiss progress UI, display media
FAILED
Processing failed
Show error, offer re-upload option
Variant Keys
When a file reaches READY , its variants are stored in the entity's database record and returned in entity API responses. Here are all possible variant keys and what they contain.
Image Variants
Key
Format
Typical Use
large
WebP URL
Full-size display, lightbox, detail view
medium
WebP URL
Feed cards, grid thumbnails
thumb
WebP URL
Tiny previews, avatar chips, comment icons
og
WebP URL
Open Graph tag
blurhash
String (e.g. LGF5?xYk^6... )
CSS blur placeholder while image loads
lqip
data:image/webp;base64,... inline data URI
Inline
placeholder, no extra request
dominant_color
Hex string (e.g. #F06023 )
Background color while loading, skeleton screen tint
Not every key is present for every context. blurhash and lqip are always generated. large , medium , og , and dominant_color depend on the context — see the Context → Variants Cheat Sheet at the bottom of this document for the exact set per context.
Usage priority : Render lqip or apply blurhash immediately. Swap in medium or large once loaded. Use thumb for tiny contexts. Always include og in page meta where available.
Video Watermarking
Video processing produces two separate sets of variants : clean variants for streaming, and a watermarked variant for download. They are different keys in the variants map.
Context
Clean variants
Watermarked variant
Watermark style
Cycle
SOCIAL_VIDEO
360p_clean , 720p_clean , 1080p_clean
720p_watermarked (or 360p_watermarked )
Diagonal 2-point: NexGate logo + @username overlay
Every 5 seconds, alternates between upper-left and lower-right
PRODUCT_VIDEO
360p_clean , 720p_clean , 1080p_clean
720p_watermarked (or 360p_watermarked )
Text-only ( NexGate label) cycling all 4 corners
Every 3 seconds
DM_VIDEO
360p_clean , 720p_clean
None
No watermark
—
Which watermarked key do you get?
If the source video is tall/wide enough for 720p → key is 720p_watermarked
If the source is smaller (e.g. a 360p source) → key is 360p_watermarked
Always check which key is present rather than assuming 720p
When to use which :
Use 360p_clean / 720p_clean / 1080p_clean for in-app streaming and playback
Use 720p_watermarked / 360p_watermarked when you want to offer a download of the video — the watermark protects the content
Social video outro : SOCIAL_VIDEO files have a personalized branded outro clip appended (username + orange accent, no re-encode). The outro is baked into the 720p_watermarked variant only, not the clean variants.
The authenticated user's username is passed to FileThunder automatically by the backend — you send nothing extra for this.
Video Variants — Short Clips (< 3 minutes)
Key
Format
Typical Use
360p_clean
MP4 URL
First available at LIVE_PARTIAL — use for in-app streaming immediately
720p_clean
MP4 URL
Standard quality in-app streaming
1080p_clean
MP4 URL
HD in-app streaming (only present if source is 1080p-capable)
720p_watermarked
MP4 URL
Watermarked download variant — offer this for user downloads
360p_watermarked
MP4 URL
Watermarked download fallback — present instead of 720p_watermarked when source is too small
preview
MP4 URL
Auto-generated 3-second silent preview clip (speed-doubled from 6s of footage at ~5% into the video) — use for hover previews on cards
poster
WebP URL
Best auto-selected frame — show as video thumbnail before play
thumb
WebP URL
Small thumbnail for cards and grids
og
WebP URL
1200×630 Open Graph image
blurhash
String
BlurHash string for placeholder
lqip
data URI
Inline WebP placeholder, no extra request
dominant_color
Hex string
Background tint for skeleton screens
Video Variants — Long Form (≥ 3 minutes, HLS)
Key
Format
Typical Use
master
HLS master playlist URL
Default — use this for all playback. Plug into HLS.js or native