Upload images, audio and video
Guides

Upload images, audio and video

Small files go through one multipart call; videos go straight to the CDN with a three-step TUS flow.

View as MarkdownUpdated Aug 19, 2026

Three media types, two paths: images and audio go through one multipart request; video is too big for that and uploads straight to the CDN.

Images — one multipart call#

Send fileType=image, originalName, and both an original (displayFile) and a thumbnail (thumbnailFile) part. The whole multipart body must stay under 4 MB — compress client-side before sending.

curl -X POST "https://www.dropfans.io/api/external/vault" \
  -H "Authorization: Bearer $DROPFANS_API_KEY" \
  -F "fileType=image" \
  -F "originalName=beach.jpg" \
  -F "[email protected]" \
  -F "thumbnailFile=@beach_thumb.jpg"

The response is { "success": true, "item": { … } }. The item starts PENDING — see Moderation & statuses.

Audio — same call, one file part#

Send fileType=audio with a single file part (≤ 20 MB, else 413) and an optional durationSeconds (capped at 3600 seconds):

curl -X POST "https://www.dropfans.io/api/external/vault" \
  -H "Authorization: Bearer $DROPFANS_API_KEY" \
  -F "fileType=audio" \
  -F "originalName=voice-note.ogg" \
  -F "durationSeconds=42" \
  -F "[email protected]"

Video — three steps via TUS#

Videos (up to 500 MB) never touch our servers directly — you upload straight to the Bunny CDN with the resumable TUS protocol.

Step 1 — start#

curl -X POST "https://www.dropfans.io/api/external/vault/video-upload" \
  -H "Authorization: Bearer $DROPFANS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "originalName": "clip.mp4", "fileSize": 104857600 }'
{
  "videoId": "9f2c…",
  "tusEndpoint": "https://video.bunnycdn.com/tusupload",
  "libraryId": 572783,
  "signature": "…",
  "expires": 1755640000000,
  "completionToken": "…"
}

Keep completionToken — it is valid for 8 hours and step 3 requires it.

Step 2 — TUS upload to the CDN#

Send the file to tusEndpoint with these TUS metadata headers: AuthorizationSignature (= signature), AuthorizationExpire (= expires), VideoId (= videoId), LibraryId (= libraryId). With tus-js-client:

import * as tus from 'tus-js-client';
import fs from 'node:fs';

await new Promise((resolve, reject) => {
  const upload = new tus.Upload(fs.createReadStream('clip.mp4'), {
    endpoint: creds.tusEndpoint,
    chunkSize: 50 * 1024 * 1024, // 50 MB chunks
    retryDelays: [0, 1500, 4000, 8000, 15000],
    headers: {
      AuthorizationSignature: creds.signature,
      AuthorizationExpire: String(creds.expires),
      VideoId: creds.videoId,
      LibraryId: String(creds.libraryId),
    },
    metadata: { filetype: 'video/mp4', title: 'clip.mp4' },
    uploadSize: fs.statSync('clip.mp4').size,
    onError: reject,
    onSuccess: resolve,
  });
  upload.start();
});

Step 3 — complete#

curl -X POST "https://www.dropfans.io/api/external/vault/video-upload/complete" \
  -H "Authorization: Bearer $DROPFANS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "videoId": "9f2c…", "originalName": "clip.mp4", "completionToken": "…" }'

A 409 means the CDN has not surfaced the finished upload yet — this is expected, retry on a ladder of roughly 2 s, 4 s, 6 s, 10 s, 15 s, 20 s, 30 s (give up after ~8 attempts). Retry 409 and 5xx only; a 403 means the completion token expired (restart from step 1) and a 413 means the file was over the cap. The call is idempotent — completing twice returns the same item.

Then poll processing#

POST /vault/video-status (up to 50 ids) reports { isReady, isProcessing, isFailed } per video. Poll every 10–15 seconds until isReady or isFailed. Processing is separate from moderation — after isReady, the item still clears review like everything else.

Folders and tags#

  • Create folders with POST /vault/folders ({ "name": … }, ≤ 50 chars, duplicate names 409); move items with PATCH /vault/{id}/folder; pass folderId at upload time to file directly.
  • Tag items with PATCH /vault/{id}/tags{ "contentTags": [ … ] }, up to 50 tags of ≤ 64 characters each.

Next: Sell a drop end-to-end or Moderation & statuses.

Questions? [email protected]