ofapis vs OFAuth
If you are shipping a chat bot, a mass-DM tool or an agency dashboard, ofapis and OFAuth land on the same shortlist — and they are not the same kind of product. One is a connection layer: it establishes a creator's session and hands it to you. The other is a metered REST surface that owns the session and exposes the workflow sitting on top of it. The question is not which is better — it is how much of the layer above the session you intend to write yourself.
Everything below about ofapis is checkable against the live API. Everything about OFAuth is a pointer to a question you should put to them directly; their own site is the only current source for their numbers.
The short version
- OFAuth positions itself as an SDK-first, auth-focused layer — often described as "Plaid for OnlyFans." Their own site is the source for what it covers and what it costs. Strong if your main need is connecting accounts cleanly and you will build the rest of the workflow yourself.
- ofapis is a metered REST surface over an already-connected account:
https://api.ofapis.com/api/public/v1, one Bearer token, no request signing. Chats, mass mailings, scheduling, lists, vault media, notifications and mentions are endpoints rather than things you assemble.
What sits above a session broker
A broker's output is an authenticated session. That is the hardest single piece, and it is also a small fraction of a production integration. The rest is what decides your delivery date.
| Job you inherit with a raw session | What it actually involves | How ofapis exposes it |
|---|---|---|
| Pagination | Each collection pages differently; concurrent writes shift offsets | limit (default 20, clamped 1–100) + offset; /lists and /lists/{listId}/users default to 10; message history uses the olderThanMessageId cursor |
| Fan-out | Enumerate, throttle, track partial failure, resume after a crash | POST /accounts/{id}/mailings then /preview, /trigger, /runs; dispatch throttles at 500 ms per message and the run survives a restart |
| Write safety | Dedupe retries so a timeout does not double-send to a real fan | Any POST accepts Idempotency-Key; a replay returns the original response with Idempotency-Replayed: true, a concurrent duplicate gets 409 |
| Inbound events | Poll, or build a signed receiver | message.received deliveries carrying X-Ofapis-Event, X-Ofapis-Delivery and X-Ofapis-Signature |
| Media | Signed upload handshake, type and size validation | POST /accounts/{id}/media, 50 MB max, image/jpeg, image/png, image/webp, video/mp4 |
| Error taxonomy | Sort upstream HTML, timeouts and session death into retryable and not | The HTTP status is the contract: 424 a dead OnlyFans session (retry), 422 an account that is not linked or whose stored authorisation is invalid (re-link, do not retry), 409 an inactive account |
| Cost accounting | Your own ledger, if you want to know what a campaign cost | Per-call debit with weights, plus recipientCount and estimatedCost from the mailing preview |
Two of those rows are worth dwelling on, because they are where self-built layers usually leak.
Events first. Exactly one event type exists — message.received — so anything else is still a poll. What you get is the delivery contract: the signature is t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">, retries run at 1m, 5m, 30m, 2h and 6h for six attempts, and an endpoint is auto-disabled after ten consecutive failures. The payload carries no event id and no account id, so you dedupe on the X-Ofapis-Delivery header and route multi-creator traffic on data.message.toUser.id. Details in webhook setup.
Then fan-out, which is not one call: it is enumeration, throttling, per-recipient state and refunding the ones that bounce. The ofapis equivalent is four calls and a polled run — see the mass DM API. One sharp edge: the double-launch 409 only covers a run that is still IN_PROGRESS. Re-trigger a mailing whose run has COMPLETED and it recounts the audience, debits again and sends again. Guard that in your own code.
Side by side
| Criterion | ofapis | OFAuth |
|---|---|---|
| Primary focus | Full workflow REST API | Account connection / auth layer |
| Auth model | Bearer token; account connected once, session kept alive | SDK-driven account connection |
| Surface after auth | Messaging, mass DM, scheduling, segments, vault, profile | You build workflow calls on top |
| Webhooks | HMAC-signed, one event type (message.received), delivery retries |
Verify on their site |
| Pricing model | Metered credits, weighted per endpoint; free tier | Usage-based; verify on their site |
| OpenAPI / SDK | OpenAPI 3.0 spec, live playground, MCP-ready | SDK-first |
| Rate limit | 60 / 100 / 500 requests per minute per token (Free / Starter / Pro) | Verify on their site |
| Account egress | Encrypted sessions; shared proxy pool on Free, dedicated per account on Starter, dedicated per creator on Pro | Verify on their site |
Cells marked "verify on their site" are deliberately not quoted — those figures change, and a stale table is worse than none.
The metering question a broker never has to answer
Charge per connection and billing is simple. Charge per call and you owe the buyer the awkward details.
Credit weights are not flat. The default is 1, but POST /accounts/{id}/media is 5, both scheduled-creation endpoints are 3, and POST /accounts/{id}/chats/{chatId}/messages is 2. A mailing trigger is 0 at the call and the run then debits recipientCount × perRecipientWeight — that weight is 1 today. Skipped recipients are refunded when the run completes.
Failures are not uniformly free. Credits are debited before the handler runs, so a request refused at the gate — 401, 402, 403, 429 — never reaches metering and costs nothing, and a 409, 424 or any 5xx is debited then refunded. But 400, 404, 413, 415 and 422 are charged and not refunded: a malformed body, an unknown account id, an oversized file or an account that is not linked yet each cost the weight of the endpoint you aimed at.
Only the five gate rejections carry a JSON envelope (UNAUTHENTICATED, INSUFFICIENT_CREDITS, NO_ACTIVE_SUBSCRIPTION, RATE_LIMIT_EXCEEDED, IDEMPOTENCY_CONFLICT); past the gate the body is a plain-text message, so branch on the status code rather than on a string. Budget for your own bugs, and read the error reference before writing a retry loop.
A 60-minute bake-off you can run yourself
Connect one real account to each candidate and run the same four probes. They are plain requests, so the cURL quickstart is enough to get the ofapis side answered before you pick a language.
export TOKEN=sk_live_xxx
BASE=https://api.ofapis.com/api/public/v1
# 1. Headers — does the platform tell you about your own budget?
curl -sS -D - -o /dev/null "$BASE/me" -H "Authorization: Bearer $TOKEN"
# X-RateLimit-Limit / -Remaining / -Reset on every response; X-Request-Id echoed back
# 2. Shape — is the envelope stable enough to type once?
curl -sS "$BASE/chats?limit=1" -H "Authorization: Bearer $TOKEN"
# {"data":{"list":[...],"hasMore":true,"nextOffset":20}}
# 3. Failure billing — the probe vendors do not advertise
curl -sS -o /dev/null -w '%{http_code}\n' "$BASE/accounts/999999999/me" \
-H "Authorization: Bearer $TOKEN"
# 404 with a plain-text body — now check the ledger; this one is charged
# 4. Replay safety
KEY=$(uuidgen)
for i in 1 2; do
curl -sS -D - -o /dev/null -X POST "$BASE/chats/123456/messages" \
-H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: $KEY" \
-H 'Content-Type: application/json' -d '{"text":"probe"}'
done
# second response carries Idempotency-Replayed: true, not charged twice
Probe 3 separates vendors. Ask any provider what a 404 costs, then check your ledger against the answer.
When OFAuth is the better choice
Pick the broker if the session is the product. That is the right call for a developer building a product; if you are instead choosing between finished tools, neither of these is your layer and the automation tool categories is the page you want. If you want control of every upstream request — your own retry policy, your own request shapes, access to endpoints no wrapper has wrapped — then a workflow API is a ceiling, not a floor, and a fixed set of wrapped routes will eventually stop where your product needs to keep going.
Two other cases point the same way: breadth ofapis does not cover today, and a codebase where you have already written the enumeration, throttling and idempotency logic for another platform.
When ofapis is the better choice
Pick the metered surface if the session is plumbing and the workflow is the product. One token, one base URL, and mass DM, scheduling, subscriber reads and signed inbound events arrive already built and priced per unit. The OpenAPI spec also feeds MCP and GPT Actions directly, which is awkward to retrofit onto a hand-rolled client. The free tier is 250 credits, one account, 60 rpm — enough for all four probes above. Start free; tiers on pricing.
FAQ
Are the numbers on this page guaranteed?
No — provider features and pricing change, so verify current details on each provider's own site. This page deliberately avoids quoting volatile figures and compares on stable criteria instead.
Is OFAuth a full OnlyFans API or just authentication?
OFAuth emphasises the authentication and account-connection layer. If you need messaging, mailings, scheduling and segmentation out of the box, a full workflow API like ofapis covers that surface directly. The gap between the two is the code you would otherwise write above the session.
Can I use an auth layer and ofapis together?
Not usefully, in practice. ofapis connects the account itself and keeps the session alive server-side, so a second broker in front of it would be solving a problem the API has already solved. If you want a broker's session, you want its raw surface too — see authentication for how the ofapis side works.
Does ofapis charge for failed calls?
It depends on the failure. Calls refused before metering — 401, 402, 403 and 429 — are free, and 409, 424 and 5xx responses are debited then refunded automatically. Requests that reach the handler and fail on your input — 400, 404, 413, 415 and 422 — are charged at the endpoint's weight and not refunded.
What happens when the creator's OnlyFans session dies?
An expired session returns 424 and the credits for that call are refunded; the session is re-established on the ofapis side rather than in your code, so the correct client behaviour is to back off and retry. A 422 is different: the stored authorisation is no longer usable, or the account was never linked, the call is charged, and retrying will not fix it — the creator has to re-link.
See also: how to compare OnlyFans APIs · alternatives