ofapisv1
integration

Updated

OnlyFans API for AI Agents (MCP)

ofapis is a plain REST API with a complete OpenAPI 3.0 document at https://api.ofapis.com/v3/api-docs/public. That document is the integration surface. Any generic OpenAPI→MCP bridge reads it and emits a tool catalogue; any assistant that imports OpenAPI schemas does the same thing under a different name. There is no first-party ofapis MCP package, and you do not need one to put an agent in front of your OnlyFans accounts today. This page is the mechanics: how a spec becomes tools, which operations belong in an agent's tool set, and what an agent that misbehaves actually costs you.

What MCP is, in one paragraph

Model Context Protocol is a client/server wire protocol. The client (Claude Desktop, Claude Code, and a growing set of other hosts) connects to a server process, calls tools/list, and receives a catalogue of tool names, descriptions and JSON Schema input shapes. When the model decides to act, the client sends tools/call with a name and arguments, the server does the work, and the result comes back as content the model reads. MCP does not know or care that the work is an HTTPS request — that is the bridge's job.

From OpenAPI document to tool list

A bridge walks the paths object. Each path + method pair becomes one tool, named from operationId, with an input schema assembled from path parameters, query parameters and request body. Three things about the ofapis document shape the catalogue you get:

Most operations declare an explicit operationId — getChats, getChatMessages, sendMessage, getSubscribers, uploadMedia, createList, addUsersToList, createScheduledPost and their siblings. The mailing operations do not, so your bridge derives names for them however it likes. Read the generated catalogue before writing an allowlist by name.

Endpoints come in two families. The token-default family (/chats, /subscribers, /notifications) acts on whichever OnlyFans account the token resolves to. The account-scoped family takes an explicit id and carries a Scoped suffix — getChatsScoped, getSubscribersScoped. On a Pro plan with five linked accounts only the scoped family is unambiguous, and a model that invents an accountId gets a 404 ACCOUNT_NOT_FOUND.

uploadMedia is multipart/form-data. Every other write takes JSON. Bridges that only generate JSON-body tools skip it or emit something unusable, so check whether it survived translation before designing a loop that uploads vault media.

A worked tool definition

This is roughly what a bridge advertises for one read operation, and what you would hand-write instead of generating — a few dozen lines of a hand-rolled client in Node behind it is often less work than taming a generated catalogue. Pinning accountId with const is the cheapest way to stop a multi-account token touching the wrong creator:

{
  "name": "list_subscribers",
  "description": "List subscribers for ofapis account 42. Returns {id, username, name, avatar, subscribedOn} per fan. There is no spend field.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "accountId": { "type": "integer", "const": 42 },
      "type": { "type": "string", "enum": ["active", "expired", "all"], "default": "active" },
      "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 },
      "offset": { "type": "integer", "minimum": 0, "default": 0 }
    },
    "required": ["accountId"],
    "additionalProperties": false
  }
}

The description field is load-bearing. A model told there is no spend field will not try to rank fans by spend and then invent numbers when the field comes back missing — the subscribers endpoint returns only {id, username, name, avatar, subscribedOn}.

What belongs in an agent's tool set

Split operations by what happens if the model calls one at the wrong moment.

Tier Operations Why
Expose freely getMe, getChats, getChatMessages, getSubscribers, getNotifications, getNotificationsCount, getMentions, getLists, getListUsers, getVaultMedia Reads. Worst case is a wasted credit and a confused summary.
Expose behind approval sendMessage, createScheduledPost, createScheduledMessage, uploadMedia, createList, addUsersToList Each one is visible to a real person or costs real money.
Never generate automatically the mailing trigger, deleteList, deleteScheduledPost, removeUserFromList Irreversible, or fans out to an audience.

The mailing trigger deserves its own warning. Its duplicate guard only rejects a second trigger while a run is IN_PROGRESS. Trigger a mailing that already COMPLETED and ofapis recounts the audience, debits again and sends again — every recipient gets the message twice. An agent retrying after a slow response does exactly this. Keep the trigger out of the catalogue and run it from a script that checks GET .../runs first; the full flow is on the mass DM page.

What a runaway agent actually costs

Credits are not flat per call, and failures are not all free. Credits are debited before the handler runs.

Outcome Charged?
401, 402, 403, 429 Free — refused before metering
409, 424, any 5xx Debited, then refunded
400, 404, 413, 415, 422 Charged, no refund

That last row is the one that bites agents. A model that calls getScheduledPosts without publishDate and publishDateEnd — both required — gets a 400 and pays for it. A model that guesses an account id gets a 404 and pays for it. Ten malformed retries is ten credits gone, and a tool that returns only a bare message will see the model retry the same malformed call. Surface error.code verbatim so it can tell "fix your arguments" from "wait and try again" — the error code reference maps each one to a status and says whether it refunds.

Weights above 1: media upload 5, scheduled post or scheduled message 3, account-scoped chat send 2. A mailing trigger is 0 at the call and then debits recipientCount × 1 inside the run. The cost breakdown has the rest.

Rate limits are a natural brake

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (unix seconds); a 429 adds Retry-After. The ceiling is per token per minute — 60 on Free, 100 on Starter, 500 on Pro, in a fixed one-minute window — so a looping agent hits 429 long before it drains a credit balance, and 429s are free. Pass Retry-After through as the tool error text rather than swallowing it. More on rate limits.

One nuance before you issue a key "for the agent": a token is scoped to your ofapis user, not to one OnlyFans account. A separate token gets its own rate-limit bucket and can be revoked independently, but it draws on the same credit balance as everything else you run. Account scoping happens in the tool layer — the const above, or your bridge's allowlist.

Then pick a client: Claude Desktop and Claude Code, ChatGPT Custom GPT Actions, Manus for long autonomous runs, or the assistant comparison if you have not chosen yet.

FAQ

Is there a first-party ofapis MCP server?

No. ofapis publishes a REST API and an OpenAPI 3.0 document; turning that into MCP tools is done by a generic bridge you run yourself, or by whatever schema import your assistant supports. Nothing on this page depends on a first-party package arriving.

How does the bridge get my token to the API?

You put the ofapis_sk_... value in the bridge process's environment or config file, and the bridge attaches Authorization: Bearer ... to every outbound request. The token never enters the prompt, the tool arguments or the model's context, which also means the model cannot leak it in a transcript.

Can I give an agent read access only?

Yes, and this is the setting to start in. Generate the full catalogue, allowlist the read operations from the tier table above, drop the rest, and stay there until you have watched enough transcripts to know which writes the model gets right. The sends that follow a fixed rule rather than a judgement call do not need the model at all — those belong in a scripted chatbot layer where the text is yours.

What happens if the agent retries a send after a timeout?

Attach an Idempotency-Key header to the POST. A replay of the same key returns the original response with Idempotency-Replayed: true and is not charged twice; a genuinely concurrent duplicate gets a 409, which is refunded. Without a key, two POSTs are two messages and two charges.

Does the catalogue update when ofapis adds an endpoint?

Yes — the tools are generated from the live spec, not hand-maintained, so restarting the bridge picks up a new operation. That is also the argument for an explicit allowlist: a tool you never reviewed should not silently become callable.

Related guides

All guides
Start free — 250 credits, no card
Generate a token and make your first call in minutes.
Get started