Skip to main content
Learn how to create posts on OnlyFans using the OFAuth API, including adding media, scheduling, and PPV pricing.

Prerequisites

You have a connected OnlyFans account with a valid connectionId
Media uploaded to vault (see Upload Media) if including images/videos

Create a Simple Text Post

const response = await fetch("https://api.ofauth.com/v2/access/posts", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    text: "Just posted something new! 🔥"
  })
})

const post = await response.json()
console.log("Post created! ID:", post.id)

Create Post with Media

Include images or videos in your post:
const response = await fetch("https://api.ofauth.com/v2/access/posts", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    text: "New content just dropped! 📸",
    mediaItems: [12345, 12346, 12347]  // Media IDs from vault
  })
})

What You Can Pass in mediaItems

The mediaItems array accepts several formats:
FormatExampleDescription
Vault Media ID12345Direct OnlyFans vault media ID (number)
Vault Media ID (string)"12345"Same as above, auto-converted to number
Upload Reference"ofauth_upload_abc123..."The mediaUploadId from upload flow
URL"https://example.com/image.jpg"External HTTP/HTTPS URL
Recommended: Use the upload reference (mediaUploadId) directly! After completing an upload, pass the mediaUploadId string to mediaItems - the system resolves it to the vault ID automatically.
// Option 1: Use upload reference directly (recommended)
const { mediaUploadId } = await initUpload(...)
await uploadFile(mediaUploadId, fileBuffer)
await completeUpload({ mediaUploadId })

body: JSON.stringify({
  text: "New post!",
  mediaItems: [mediaUploadId]  // "ofauth_upload_abc123..."
})

// Option 2: Use vault IDs if you already have them
body: JSON.stringify({
  text: "New post!",
  mediaItems: [12345, 67890]  // Direct vault media IDs
})
Upload references are single-use. Once used in a post or message, they’re consumed and cannot be reused.

Create a PPV (Pay-Per-View) Post

Lock content behind a paywall:
const response = await fetch("https://api.ofauth.com/v2/access/posts", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    text: "Exclusive content! 🔒 Unlock to see more...",
    mediaItems: [12345, 12346],
    price: 14.99,             // Price in USD ($3-$200)
    previewMediaCount: 1      // Show 1 item as preview
  })
})

PPV Options

OptionTypeDescription
pricenumberPPV price in USD (3min,3 min, 200 max)
previewMediaCountnumberNumber of media items visible before unlock
isLockedTextbooleanAlso hide the caption until purchased

Schedule a Post

Create a post to publish later:
const response = await fetch("https://api.ofauth.com/v2/access/posts", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    text: "This will go live tomorrow! 🎉",
    mediaItems: [12345],
    scheduledDate: "2024-12-25T12:00:00Z"  // ISO 8601 format
  })
})

const post = await response.json()
console.log("Scheduled for:", post.scheduledDate)
Scheduled posts are stored in OnlyFans’ queue. Use an ISO 8601 date string for scheduledDate.

Create Expiring Post

Post that auto-deletes after a set period:
const response = await fetch("https://api.ofauth.com/v2/access/posts", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    text: "Limited time only! ⏰",
    mediaItems: [12345],
    expireAfter: 7  // Days until post expires (1-30)
  })
})

Create Fundraising Post

Create a post with fundraising goal:
const response = await fetch("https://api.ofauth.com/v2/access/posts", {
  method: "POST",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    text: "Help me reach my goal! 🎯",
    fundRaisingTargetAmount: 500,       // Target in USD (min $10)
    fundRaisingTipsPresets: [5, 10, 25, 50]  // Suggested tip amounts (max 4)
  })
})

Text Formatting

Posts support markdown formatting:
{
  "text": "**Bold headline**\n\n*Italic text* and regular text.\n\nNew paragraph here!",
  "isMarkdown": true  // Default
}
Supported:
  • **bold**bold
  • *italic*italic
  • \n\n → New paragraph

Edit an Existing Post

Update a post’s content:
const response = await fetch("https://api.ofauth.com/v2/access/posts/POST_ID", {
  method: "PUT",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    text: "Updated caption! ✨",
    mediaItems: [12345, 12346]  // Can add/remove media
  })
})

Delete a Post

const response = await fetch("https://api.ofauth.com/v2/access/posts/POST_ID", {
  method: "DELETE",
  headers: {
    apikey: "YOUR_API_KEY",
    "x-connection-id": "conn_abc123"
  }
})

if (response.ok) {
  console.log("Post deleted!")
}

Complete Example

Full workflow: upload media, then create post:
const API_KEY = "YOUR_API_KEY"
const CONNECTION_ID = "conn_abc123"

const headers = {
  apikey: API_KEY,
  "x-connection-id": CONNECTION_ID,
  "Content-Type": "application/json"
}

async function createPostWithMedia(imageBuffer, caption) {
  // Step 1: Initialize upload
  const initResponse = await fetch("https://api.ofauth.com/v2/access/uploads/init", {
    method: "POST",
    headers,
    body: JSON.stringify({
      filename: "photo.jpg",
      filesize: imageBuffer.length,
      mimeType: "image/jpeg"
    })
  })
  
  const { mediaUploadId } = await initResponse.json()
  
  // Step 2: Upload the file
  await fetch(`https://api.ofauth.com/v2/access/uploads/${mediaUploadId}`, {
    method: "PUT",
    headers: {
      ...headers,
      "Content-Type": "image/jpeg"
    },
    body: imageBuffer
  })
  
  // Step 3: Complete upload
  const completeResponse = await fetch("https://api.ofauth.com/v2/access/uploads/complete", {
    method: "POST",
    headers,
    body: JSON.stringify({ mediaUploadId })
  })
  
  const { media } = await completeResponse.json()
  console.log("Media uploaded! ID:", media.id)
  
  // Step 4: Create post with the uploaded media
  const postResponse = await fetch("https://api.ofauth.com/v2/access/posts", {
    method: "POST",
    headers,
    body: JSON.stringify({
      text: caption,
      mediaItems: [media.id]
    })
  })
  
  const post = await postResponse.json()
  console.log("Post created! ID:", post.id)
  
  return post
}

// Usage
const imageBuffer = fs.readFileSync("photo.jpg")
createPostWithMedia(imageBuffer, "New photo! 📸")

All Post Options

OptionTypeDescription
textstringPost caption (supports markdown)
mediaItemsnumber[]Array of media IDs from vault
pricenumberPPV price (33-200)
isLockedTextbooleanLock caption behind paywall
previewMediaCountnumberPreview items before paywall
scheduledDatestringISO date for scheduled posting
expireAfternumberDays until auto-delete (1-30)
fundRaisingTargetAmountnumberFundraising goal (min $10)
fundRaisingTipsPresetsnumber[]Suggested tip amounts (max 4)
isMarkdownbooleanParse text as markdown (default: true)
userTagsnumber[]Tag users in post
releaseFormsobjectRelease form attachments

Next Steps