Core Capabilities
Media
Upload photos and videos to OnlyFans programmatically with the OFManager API. One call per upload, deduplication built in, ready to attach to messages and posts.
Attach a photo or video to a message or post in a single call. You pass in a source, you get back a reference. The SDK handles deduplication and processing end-to-end.
Setup
import { OfApiClient } from "@betterfans/link-sdk"
import { media } from "@betterfans/link-sdk/plugins/media"
const client = new OfApiClient({
apiKey: process.env.OFM_API_KEY,
plugins: [media()],
})
const account = client.for("123456789")Upload and attach
const result = await account.plugin.media.upload({
source: "https://cdn.example/photo.jpg",
})
await account.request("POST /chats/:id/messages", {
pathParams: { id: "98765" },
body: {
text: "here you go",
mediaFiles: result.kind === "existing" ? [result.mediaId] : [result.ref],
},
})source accepts any of:
- a URL string (fetched on your behalf),
- a
Blob, - an
ArrayBufferorUint8Array.
The result discriminates on kind:
existing: a byte-identical file already lived in the account's library;mediaIdis ready to attach.new: a freshly-processed upload; attach the wholerefobject as a singlemediaFilesentry.
Mixed attachments
mediaFiles accepts a mix of both shapes in one request:
const a = await account.plugin.media.upload({ source: videoUrl })
const b = await account.plugin.media.upload({ source: photoUrl, avoidWatermark: true })
await account.request("POST /posts", {
body: {
text: "new drop",
mediaFiles: [
...(a.kind === "existing" ? [a.mediaId] : [a.ref]),
...(b.kind === "existing" ? [b.mediaId] : [b.ref]),
11111, // existing vault id you already know about
],
price: 15,
},
})Options
| Option | Type | Description |
|---|---|---|
source | string | Blob | ArrayBuffer | Uint8Array | URL, Blob, or raw bytes to upload. |
filename | string (optional) | Display name. Inferred from the URL when omitted. |
contentType | string (optional) | MIME type. Inferred from the source when omitted. |
avoidWatermark | boolean (optional) | Skip watermarking (if the account has it enabled). |
Result
| Option | Type | Description |
|---|---|---|
kind | "existing" | "new" | existing for a library hit, new for a fresh upload. |
mediaId | number | Library id (only when kind === "existing"). Attach directly. |
ref | MediaRef | Opaque reference (only when kind === "new"). Attach as a single mediaFiles entry. |
Refreshing cached account state
The plugin caches a small amount of per-account state to keep repeat uploads fast. If an account's profile settings change out of band and you want the next upload to pick them up immediately rather than waiting for the internal TTL:
client.plugin.media.invalidateCache("123456789")