ofapisv1
quickstart

OnlyFans API with Ruby

ofapis is a plain REST API with Bearer auth, so you can call the OnlyFans API from Ruby with the standard-library Net::HTTP — no gem required. If you already use Faraday in your app, a variant is shown at the end. Every request goes to https://api.ofapis.com/api/public/v1.

ofapis is an independent, unofficial API for OnlyFans — not affiliated with OnlyFans. Accounts are connected once in the dashboard and the session is kept alive server-side, so your Ruby code only ever deals with your own ofapis_sk_... token.

1. Get a token

Create a key in the dashboard (start free) and read it from the environment rather than committing it. See authentication.

2. Setup

net/http and json ship with Ruby, so no install is needed. For a project, pin them in a Gemfile so bundle exec is reproducible:

# Gemfile
source "https://rubygems.org"
gem "json"        # stdlib, but explicit for bundler
gem "faraday"     # optional, only if you prefer Faraday

Then bundle install.

3. Verify the token — GET /me

A tiny wrapper keeps the Authorization header on every call and reuses one connection:

require "net/http"
require "json"

BASE  = URI("https://api.ofapis.com/api/public/v1")
TOKEN = ENV.fetch("OFAPIS_KEY")

$http = Net::HTTP.new(BASE.host, BASE.port).tap { |h| h.use_ssl = true }

def call(req)
  req["Authorization"] = "Bearer #{TOKEN}"
  req["Content-Type"]  = "application/json"
  $http.request(req)
end

res = call(Net::HTTP::Get.new("#{BASE.path}/me"))
raise "GET /me failed: #{res.code} #{res.body}" unless res.code == "200"
me = JSON.parse(res.body)
puts "connected as #{me["username"]}"

4. List chats

res  = call(Net::HTTP::Get.new("#{BASE.path}/chats?limit=50"))
data = JSON.parse(res.body).fetch("data", [])
data.each { |c| puts c["id"] }

5. Send a message

req = Net::HTTP::Post.new("#{BASE.path}/chats/123/messages")
req.body = { text: "Thanks for subscribing!" }.to_json
res = call(req)

case res.code
when "200" then puts "delivered — 1 credit spent"
when "401" then abort "bad or revoked token"
when "429" then warn "rate limited — back off and retry"
else            abort "send failed: #{res.code} #{res.body}"
end

A 200 means delivered and one credit spent. Failed calls — an expired session, a 429, or an upstream 5xx — are never charged, so retrying after a failure costs nothing.

Faraday variant

If your codebase already uses Faraday, build a connection once and lean on raise_error:

require "faraday"

conn = Faraday.new(url: "https://api.ofapis.com/api/public/v1") do |f|
  f.request :json
  f.response :json
  f.response :raise_error
  f.headers["Authorization"] = "Bearer #{ENV.fetch("OFAPIS_KEY")}"
end

puts conn.get("/me").body["username"]
conn.post("/chats/123/messages", { text: "Hi!" })

raise_error turns any non-2xx into a Faraday::Error you can rescue — pair it with a retry on Faraday::ServerError and 429.

Agencies: scope by account

Managing several creators? Address each by id under scoped routes, e.g. call(Net::HTTP::Get.new("#{BASE.path}/accounts/42/chats")). See agency automation.

FAQ

Is there an official Ruby gem for the OnlyFans API?

No. ofapis is a standard REST API, so Net::HTTP or Faraday is enough. You can also generate a client from the OpenAPI spec linked in the docs.

How do I handle rate limits in Ruby?

Watch for HTTP 429 and retry after a short backoff. Plan ceilings run from 60 rpm on Free to 500 rpm on Pro — see pricing.

Does a failed request cost a credit?

No. Billing is metered per successful call: one 2xx equals one credit. Network errors, 429s and upstream 5xx responses are not charged.

Should I reuse the Net::HTTP connection?

Yes. Create one Net::HTTP (or one Faraday connection) and reuse it so TLS handshakes and sockets are pooled instead of reopened per request.

Next steps

Related guides

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