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