read:media.
Two rules shape everything below:
- Variant URLs are short-lived. Re-fetch a URL before you use it.
- List endpoints return media without URLs unless you ask for variants, so resolve in batches rather than one lookup per item.
How media and variants work
A media item has a stableuuid and one or more variants. A variant is one rendition of the item at one size or treatment, each with its own URL.
Variant URLs appear only when you ask for them. List endpoints return a minimal shape (
uuid, status) by default. Pass the variants query parameter to get the full object, including a variants array where each entry has url, variantType, width, height and displayPosition.
Filter to ready media with status=ready, because an item that is still processing has no usable variant URLs.
Treat media URLs as short-lived
Variant URLs are signed and expire, so fetch them when you need them. Store the stable identifiers instead (mediaUuid, and for chat media the messageUuid), then resolve a fresh URL at display time:
1
Store IDs, not URLs
Persist
mediaUuid (and messageUuid for chat attachments). These never change.2
Resolve on demand
When something scrolls into view, request the variants you need for those IDs.
3
Cache in memory, briefly
Hold the resolved URL in memory for the current view. Do not write it to durable storage.
4
Refetch on failure
If a render fails with
403 or 404, resolve the URL again rather than retrying the dead one.Age verification for media access
In regions where Fanvue must verify age, a user completes age verification before your app can read their media. Until then, the media read endpoints return403:
GET /mediaGET /media/{uuid}GET /media/bulkGET /vault/folders/{folderName}/media
403 body tells you where to send the user:
ageVerificationUrl points to the Fanvue-hosted verification the user completes themselves. Once they have verified, the media endpoints return normally. The check applies only to users whose region requires age verification, and only until they have verified, so creators and already-verified users are not affected.
Display Vault media efficiently
GET /vault/folders/{folderName}/media lists a folder’s items without variant URLs, and resolving each one by scanning the full media list costs hundreds of calls per folder view. Use GET /media with a folderName filter, a variants list and status instead:
data carries its variants array, so one paged response gives you every URL you need. Page through with page and size.
Pick the smallest variant that fits the surface. Render grids and lists with thumbnail, and resolve main only when the user opens an item full-screen.
The {folderName} path segment is a name, not an ID
On the folder-scoped endpoints, {folderName} is the folder’s exact display name, URL-encoded:
GET /vault/folders/{folderName}/medialists a folder’s mediaDELETE /vault/folders/{folderName}/media/{mediaUuid}detaches one media item from a folder
Folder 1 becomes Folder%201. A Folder not found 404 means no folder with that exact name exists for that creator, so check the casing and encoding of the name, and don’t send a folder ID.
Resolve specific media by ID
When you hold a set of media UUIDs, resolve them in one request.GET /media/bulk takes a comma-separated mediaUuids list of 1 to 20 UUIDs and an optional variants list:
results maps each requested UUID to its item, or null when it couldn’t be resolved. errors lists one entry per unresolved UUID with code NOT_FOUND or INTERNAL. One missing item never fails the request.
Check processing status
GET /media/{uuid} returns one item. Its status is created, processing, ready or error. When status is error, errorReason names the cause:
Poll
GET /media/{uuid} after an upload until status is ready or error.
Upload media
Media enters Fanvue through a multipart upload session. You create the session withPOST /media/uploads, PUT each part to a signed URL, complete the session and poll GET /media/{uuid} until ready. Upload media in parts has the full sequence, limits and SDK helpers.
Display chat media reliably
Chat attachments follow the same short-lived URL rule. Store each message’s stable IDs (messageUuid, mediaUuid), then resolve fresh URLs for the media a user is viewing.
GET /chats/{userUuid}/messages/{messageUuid}/media resolves attachments for one message. It takes mediaUuids (comma-separated, up to 20) and an optional variants list:
Pricing fields on chat media
Chat media items carrypricing, purchasedAt and amountPaid, which describe the pay-to-view message the item came from rather than the item itself. The two kinds of media on a paid message report them differently:
- Body media, the items being sold, carry the message’s price.
pricingis the listed price in USD cents, andpurchasedAtandamountPaidfill in once the fan unlocks the message.pricingdoesn’t reflect discounts, soamountPaidis what the fan paid. - The free preview, the item shown before the paywall, reports all three as
null, even on a priced message the fan has bought.
uuid matches the message’s mediaPreviewUuid, which is null when the sender configured no preview.
Putting it together
- Store IDs, never signed URLs.
- Ask for the
variantsyou need, and filter withstatus=ready. - Load a Vault folder with
folderNameonGET /media, one call per page. - Re-resolve URLs on demand with
GET /media/bulkor the per-message media endpoint. - Treat
403and404on a media URL as a signal to resolve again.