Upload new content to the vault
Add a new photo or video to the OnlyFans vault directly from the panel.
Who this is for: a workspace owner or team member with upload access (the media_upload
grant).
Uploads are byte-less:
the backend only ever brokers an address and a completion signal. Your browser sends the actual
file straight to the address OnlyFans issues. Check first whether uploads are live —
vault_write is gated by two independent switches, and either being off means an honest
{"enabled": false}, not a broken button.
curl "https://app.tease.link/api/admin/vault/upload/enabled" \
-H "Authorization: Bearer $TEASE_API_KEY"{ "enabled": true, "shadow": false, "photo_max_mb": 50, "video_max_gb": 4 }Start the upload
Send the file's name, size, and content type — never the bytes themselves.
curl -X POST "https://app.tease.link/api/admin/vault/upload" \
-H "Authorization: Bearer $TEASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "beach.mp4", "size": 104857600, "content_type": "video/mp4", "export_type": "message"}'| Field | Type | Description |
|---|---|---|
name | string | File name, up to 255 chars. |
size | integer | Declared size in bytes — checked against the ceiling before an address is issued. |
content_type | string | One of image/jpeg, image/png, image/webp, image/heic, video/mp4, video/quicktime, video/webm. Anything else is a 415. |
export_type | string | message (default — headed for a chat/PPV) or post (headed for the wall). |
fan_id | string | Optional; only meaningful for a message upload tied to one fan. |
A photo over 50 MB or a video over 4 GB is rejected with a 413 before anything is requested
from OnlyFans. The response is {"status": "pending", "upload_id": "...", "nonce": "..."} — an
upload_id to poll, never a finished upload.
Poll until an address is ready
curl "https://app.tease.link/api/admin/vault/upload/{upload_id}" \
-H "Authorization: Bearer $TEASE_API_KEY"States: queued → ready → finishing → done, or failed / shadow. Once ready, the
response carries put — the target(s) your browser should PUT the file's bytes to directly
(one part for a small file, several for a large multipart upload).
Complete the upload
After every part has landed on the put target(s), tell the engine to close the upload and mint
a media_id:
curl -X POST "https://app.tease.link/api/admin/vault/upload/{upload_id}/complete" \
-H "Authorization: Bearer $TEASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"parts": [{"part": 1, "e_tag": "\"d41d8...\""}]}'Parts must be numbered 1..N in order with a real ETag from the PUT response — OnlyFans'
CompleteMultipartUpload requires it, and an out-of-order or missing ETag is rejected before it
ever reaches the vendor. On success the file appears in All content immediately — you don't
have to wait for the next scan.
If something goes wrong
- Cancel:
POST /vault/upload/{upload_id}/abortcloses the row and asks the engine to clean up any partial multipart write in the bucket. - No resume. If the tab closes or the connection drops mid-transfer, the upload fails with "start the upload again" — there's no docking back into a partial upload.
- Two-hour window. Once an address is
ready, you have two hours to finish sending bytes before the upload is marked failed on its own.
What's next
See the recent uploads and how they ended with GET /vault/uploads, or read
async engine write gotchas for
what {"enabled": false, "staged": true} means.