Finish a video upload (step 3 of 3)
API reference

Finish a video upload (step 3 of 3)

Registers a finished TUS upload as a vault item and kicks moderation.

View as MarkdownUpdated Aug 19, 2026
POST/api/external/vault/video-upload/complete

Registers a finished TUS upload as a vault item and kicks moderation.

Idempotent: a retried completion for an already-registered video returns the existing item instead of creating a duplicate — retry freely. 409 means "not finished yet, retry": the CDN can lag a few seconds after the TUS client reports done, so on a 409 back off (2s, 5s, 10s, 30s) and call again with the same body.

The item starts PENDING and finalizes asynchronously (the NSFW pipeline plus transcoding). Poll video-status with the bunnyStreamId to know when the video is playable, and the vault list for moderation.

Authentication

Send the creator's API key as a bearer token: Authorization: Bearer dpfn_…. See Authentication & API keys.

Request body

Content type: application/json

NameTypeRequiredDescription
videoIdstringRequiredThe videoId from step 1.
originalNamestringRequiredSame file name you sent in step 1.
completionTokenstringRequiredThe token from step 1 (valid 8h). Proves this key started the upload.
folderIdstring | nullOptionalOptional folder — silently ignored if you don’t own it.
Register the uploaded video
{
  "videoId": "c2f7f9e2-1111-4222-b333-4d55e6f7a8b9",
  "originalName": "teaser.mp4",
  "completionToken": "eyJ…"
}

Responses

200Registered (or already registered — idempotent).
NameTypeDescription
successbooleanAlways true.
itemVideoVaultItemThe new video vault item, starting PENDING.
Show child attributes
idstringThe new vault item id.
fileNamestringThe originalName you sent.
filePathstringSigned playback URL, valid ~1 hour. For a long-lived URL, re-list the vault later.
thumbnailPathstring | nullSigned Stream thumbnail (600px wide).
fileTypestringAlways "video" here.
One of: video
fileSizeinteger | nullByte count Bunny reported for the finished upload.
bunnyStreamIdstring | nullThe Stream GUID — poll POST /api/external/vault/video-status with it while the video transcodes.
moderationStatusstringStarts PENDING — the NSFW pipeline finalizes it asynchronously. The item only appears in the default vault list once APPROVED.
One of: PENDING, APPROVED, REJECTED, FLAGGED
moderationTagsstring[]Always empty at creation (moderation has not run yet).
createdAtstringCreation time.
Format: date-time
aiEnhancedbooleanTrue when the account is AI-labelled — every upload from such an account is force-marked AI.
Example response
{
  "success": true,
  "item": {
    "id": "clxv9z8y70002item",
    "fileName": "teaser.mp4",
    "filePath": "https://vz-example.b-cdn.net/c2f7f9e2-…/playlist.m3u8?token=…",
    "thumbnailPath": "https://vz-example.b-cdn.net/c2f7f9e2-…/thumbnail.jpg?token=…",
    "fileType": "video",
    "fileSize": 52428800,
    "bunnyStreamId": "c2f7f9e2-1111-4222-b333-4d55e6f7a8b9",
    "moderationStatus": "PENDING",
    "moderationTags": [],
    "createdAt": "2026-08-01T10:20:00.000Z",
    "aiEnhanced": false
  }
}

Errors

StatusBodyWhen
400{"error":"Missing required fields: videoId and originalName"}Either field absent or blank.
401{"error":"Unauthorized","code":"unauthorized"}Missing or invalid API key.
403{"error":"Invalid or expired upload token — please retry the upload"}The completionToken is wrong, for another key, or older than 8h — start over from step 1.
409{"error":"The video upload has not finished — please retry."}The CDN has not finished receiving the bytes — back off and retry the same call.
413{"error":"Video too large. Max 500MB."}The stored byte count exceeds the cap — the upload is discarded.
500{"error":"Failed to register the uploaded video"}Registration failed — retry later.

Rate limiting

Every response carries the X-RateLimit-Tier header and, on limited tiers, the per-minute and per-day trios — read X-RateLimit-Remaining and X-RateLimit-Reset instead of hardcoding limits. Details in Rate limits.

Code samples

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": "c2f7f9e2-1111-4222-b333-4d55e6f7a8b9",
  "originalName": "teaser.mp4",
  "completionToken": "eyJ…"
}'

Notes

This item shape adds moderationStatus, moderationTags and aiEnhanced (and omits durationSeconds) compared to the plain upload endpoint. filePath here is signed for ~1 hour only.

Questions? [email protected]