Skip to main content

What You Can Build

  • Media Management: Upload, organize, and manage content libraries
  • Content Embedding: Display OnlyFans media on your platform
  • Backup Tools: Download and archive creator content
  • Cross-Platform Sync: Manage media across multiple accounts

Quick Example

List media from the vault:
const response = await fetch("https://api.ofauth.com/v2/access/vault/media", {
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123"
  }
})

const { list, hasMore } = await response.json()
console.log(`Found ${list.length} media items`)

Common Operations

List Vault Media

Get media from the vault with optional filters:
const response = await fetch("https://api.ofauth.com/v2/access/vault/media?" + new URLSearchParams({
  limit: "24",
  offset: "0",
  sortBy: "recent",         // "recent" | "most-liked" | "highest-tips"
  sortDirection: "desc",    // "asc" | "desc"
  mediaType: "photo"        // "photo" | "video" | "audio" | "gif"
}), {
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123"
  }
})

const { list, hasMore } = await response.json()

Get Vault Lists (Folders)

OnlyFans organizes vault media into lists/folders:
const response = await fetch("https://api.ofauth.com/v2/access/vault/lists", {
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123"
  }
})

const { list, all, hasMore } = await response.json()
// list: array of vault folders
// all: summary with total counts by type

Get Media in a Specific List

const response = await fetch("https://api.ofauth.com/v2/access/vault/lists/LIST_ID/media", {
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123"
  }
})

const { list, hasMore } = await response.json()

Create a Vault List

const response = await fetch("https://api.ofauth.com/v2/access/vault/lists", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    name: "My Custom Folder"
  })
})

const newList = await response.json()

Add Media to a List

const response = await fetch("https://api.ofauth.com/v2/access/vault/lists/LIST_ID/media", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    mediaIds: [123, 456, 789]
  })
})

Uploading Media

The /uploads/init response determines whether you need single-part or multi-part upload:
HeaderMeaning
x-ofauth-upload-total-parts: 1Single-part upload (auto-completes)
x-ofauth-upload-total-parts: NMulti-part upload (requires /complete)

Single-Part Upload (Small Files)

For small files where x-ofauth-upload-total-parts is 1, upload completes automatically:
// Step 1: Initialize
const initResponse = await fetch("https://api.ofauth.com/v2/access/uploads/init", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    filename: "photo.jpg",
    filesize: 1024000,
    mimeType: "image/jpeg"
  })
})

const { mediaUploadId } = await initResponse.json()
const totalParts = initResponse.headers.get("x-ofauth-upload-total-parts")

// Step 2: Upload file (auto-completes for single-part)
const uploadResponse = await fetch(
  `https://api.ofauth.com/v2/access/uploads/${mediaUploadId}`,
  {
    method: "PUT",
    headers: {
      apikey: "YOUR_API_KEY",
      "x-connection-id": "conn_abc123",
      "Content-Type": "image/jpeg"
    },
    body: fileBuffer
  }
)

// Done! Response contains the media info directly
const { media } = await uploadResponse.json()
console.log("Uploaded media ID:", media.id)

Multi-Part Upload (Large Files)

For larger files where x-ofauth-upload-total-parts is greater than 1, upload in chunks and call /complete:
// Step 1: Initialize
const initResponse = await fetch("https://api.ofauth.com/v2/access/uploads/init", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    filename: "video.mp4",
    filesize: 50000000,  // 50MB
    mimeType: "video/mp4"
  })
})

const { mediaUploadId } = await initResponse.json()
const totalParts = parseInt(initResponse.headers.get("x-ofauth-upload-total-parts"))
const partSize = parseInt(initResponse.headers.get("x-ofauth-upload-part-size"))

// Step 2: Upload each chunk
for (let partNumber = 1; partNumber <= totalParts; partNumber++) {
  const start = (partNumber - 1) * partSize
  const end = Math.min(start + partSize, fileBuffer.length)
  const chunk = fileBuffer.slice(start, end)

  await fetch(
    `https://api.ofauth.com/v2/access/uploads/${mediaUploadId}/parts/${partNumber}`,
    {
      method: "PUT",
      headers: {
        apikey: "YOUR_API_KEY",
        "x-connection-id": "conn_abc123",
        "Content-Type": "video/mp4"
      },
      body: chunk
    }
  )
}

// Step 3: Complete upload (required for multi-part only)
const completeResponse = await fetch("https://api.ofauth.com/v2/access/uploads/complete", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ mediaUploadId })
})

const { media } = await completeResponse.json()
console.log("Uploaded media ID:", media.id)
Single-part: No /complete call needed—the PUT response returns the media directly. Multi-part: Must call /complete after all chunks are uploaded.

Media Storage Options

OFAuth provides two complementary solutions for handling OnlyFans media:
FeatureMedia ProxyVault Cache
PurposeDisplay current contentBuild media libraries
AccessVia API response URLsBy media ID directly
StorageTemporary (edge cache)Persistent storage
SetupAutomaticRequires enabling
BillingPer KB bandwidthPer GB/month storage
Best forImmediate displayPPV features, offline access

Media Storage Guide

Learn when to use Media Proxy vs Vault Cache with detailed examples

Media Proxy

OFAuth automatically proxies OnlyFans CDN URLs, making media embeddable on your platform.
Automatic: API responses already contain proxied media.ofauth.com URLs. No extra configuration needed.

Why Media Proxy?

OnlyFans CDNOFAuth Media Proxy
URLs expire quicklyExtended validity
CORS blockedCORS enabled
No caching controlEdge-cached globally
Cannot embedEmbeddable in <img> / <video>

Using Proxied URLs

// API responses automatically include proxied URLs in files.full.url
const media = list[0]

// Use directly in HTML
const imgUrl = media.files.full.url
// https://media.ofauth.com/v1/abc123/photo.jpg
<!-- Embed in your app -->
<img src="https://media.ofauth.com/v1/abc123/photo.jpg" alt="Content" />
<video src="https://media.ofauth.com/v1/xyz789/video.mp4" controls />

Trigger Persistent Caching

You can trigger persistent caching of a specific media item by sending a POST request to its media proxy URL:
await fetch("https://media.ofauth.com/abc123...", { method: "POST" })
// Response: { "success": true, "mediaId": "123456", "status": "queued" }

Purge Cached Media

Remove a specific media item from persistent cache with a DELETE request:
await fetch("https://media.ofauth.com/abc123...", { method: "DELETE" })
// Response: { "success": true, "mediaId": "123456", "freedBytes": 1048576 }

Billing

Media Proxy

Billed per KB of bandwidth transferred. Cache hits (within 7 days) are free.

Vault Cache

Billed per GB/month of storage. Persistent storage for media you need long-term access to.
Monitor usage in your dashboard. Media Proxy is best for temporary display; Vault Cache is best for building permanent media libraries.

API Endpoints

EndpointMethodDescription
/v2/access/vault/mediaGETList all vault media
/v2/access/vault/listsGETGet vault lists/folders
/v2/access/vault/listsPOSTCreate a vault list
/v2/access/vault/lists/{listId}PATCHUpdate a vault list
/v2/access/vault/lists/{listId}DELETEDelete a vault list
/v2/access/vault/lists/{listId}/mediaGETGet media in a list
/v2/access/vault/lists/{listId}/mediaPOSTAdd media to a list
/v2/access/uploads/initPOSTInitialize media upload
/v2/access/uploads/{mediaUploadId}PUTUpload single-part file
/v2/access/uploads/{mediaUploadId}/parts/{partNumber}PUTUpload chunk
/v2/access/uploads/completePOSTComplete upload

Full API Reference

See complete endpoint documentation

Query Parameters

Vault Media Query

ParameterTypeDefaultDescription
limitnumber24Results per page (1-40)
offsetnumber0Pagination offset
sortBystring”recent”Sort by: recent, most-liked, highest-tips
sortDirectionstring”desc”Sort direction: asc, desc
mediaTypestring-Filter by type: photo, video, audio, gif
querystring-Search query

Media Data Structure

Each media item includes:
{
  "id": 123456,
  "type": "photo",
  "canView": true,
  "hasError": false,
  "isReady": true,
  "createdAt": "2024-01-15T10:30:00Z",
  "files": {
    "full": {
      "url": "https://media.ofauth.com/v1/abc123/photo.jpg",
      "width": 1920,
      "height": 1080,
      "size": 245000
    },
    "thumb": {
      "url": "https://media.ofauth.com/v1/abc123/thumb.jpg",
      "width": 200,
      "height": 200
    },
    "preview": {
      "url": "https://media.ofauth.com/v1/abc123/preview.jpg",
      "width": 480,
      "height": 480
    }
  },
  "counters": {
    "likesCount": 42,
    "tipsSumm": 25.00
  }
}
For videos, additional fields:
{
  "type": "video",
  "duration": 120,
  "videoSources": {
    "240": "https://media.ofauth.com/v1/xyz789/240p.mp4",
    "720": "https://media.ofauth.com/v1/xyz789/720p.mp4"
  }
}

Vault List Structure

{
  "id": 12345,
  "type": "custom",
  "name": "My Photos",
  "hasMedia": true,
  "canUpdate": true,
  "canDelete": true,
  "medias": [
    { "type": "photo", "url": "https://..." }
  ]
}
List types: custom, messages, posts, stories, streams, media_stickers

Tips & Best Practices

Upload First: Always upload media to the vault before referencing it in posts or messages. You can’t upload inline.
Supported Formats: Images (JPEG, PNG, GIF, WebP), Videos (MP4, MOV), Audio (MP3, M4A). Check OnlyFans’ guidelines for size limits.
Bandwidth Costs: Frequently accessed media (profile pictures, popular posts) may generate significant bandwidth charges. Monitor usage in your dashboard.