OnlyFans API Python SDK
Full Python integration for the OnlyFans API using the requests library. Revenue tracking, fan analytics, payout reconciliation, and messaging automation — all in clean, idiomatic Python.
On This Page
Installation
The OnlyFans API Python SDK uses the requests library — the most widely used HTTP client in the Python ecosystem. No other dependencies are required. Python 3.8 or later is recommended.
# Install the requests library
pip install requests python -m venv .venv) to keep dependencies isolated per project.
Configuration
Create a shared ofapi.py module in your project. This sets up the base URL, injects the X-API-Key header on every request, and provides a single ofapi() function all your scripts import.
# ofapi.py — shared client config
import requests
import os
BASE_URL = "http://157.180.79.226:4024/api/v1/onlyfans"
HEADERS = {
"X-API-Key": os.environ["OFAPI_KEY"],
"Content-Type": "application/json",
}
def ofapi(path, method="GET", **kwargs):
url = f"{BASE_URL}{path}"
resp = requests.request(method, url, headers=HEADERS, **kwargs)
resp.raise_for_status()
return resp.json() OFAPI_KEY=your_api_key_here Get Revenue Statistics
Pull a complete earnings breakdown for any creator on your account — subscriptions, tips, PPV messages, PPV posts, referrals, and chargebacks. Use this to build P&L dashboards and automate commission calculations.
GET /models/:id/statistics/overview
from ofapi import ofapi
def get_revenue_stats(creator_id):
data = ofapi(f"/models/{creator_id}/statistics/overview")
return data
stats = get_revenue_stats("creator_abc123")
print(f"Total earnings: ${stats['totalEarned']}")
print(f"Subscriptions: ${stats['subscriptions']}")
print(f"Tips: ${stats['tips']}")
print(f"PPV: ${stats['ppv_messages'] + stats['ppv_posts']}") {
"creator_id": "creator_abc123",
"totalEarned": 12847.50,
"subscriptions": 4200.00,
"tips": 3100.25,
"ppv_messages": 3847.00,
"ppv_posts": 1200.25,
"referrals": 500.00,
"chargebacks": 0.00,
"period": "all_time",
"currency": "USD"
} List Top Fans
Retrieve a ranked list of fans sorted by total lifetime spend. Use this to power VIP identification, prioritize outreach sequences, and flag high-value fans at churn risk.
GET /models/:id/stats/fans/top
from ofapi import ofapi
def get_top_fans(creator_id, limit=10):
data = ofapi(
f"/models/{creator_id}/stats/fans/top",
params={"limit": limit}
)
return data["fans"]
fans = get_top_fans("creator_abc123", limit=5)
for i, fan in enumerate(fans, 1):
print(f"#{i} {fan['username']} — ${fan['total_spent']}") {
"fans": [
{
"user_id": "fan_001",
"username": "bigspender99",
"total_spent": 3420.00,
"tips_total": 1800.00,
"ppv_total": 1420.00,
"subscriptions_total": 200.00,
"subscriber_since": "2024-03-15",
"is_active": true
}
],
"total_count": 847
} Track Payouts
Retrieve full payout transaction history for a creator. Paginate through all records to reconcile earnings, automate agency commission splits, and build payout forecasting tools.
GET /models/:id/payouts/transactions
from ofapi import ofapi
from datetime import datetime
def get_payouts(creator_id, page=1, limit=20):
data = ofapi(
f"/models/{creator_id}/payouts/transactions",
params={"page": page, "limit": limit}
)
return data
result = get_payouts("creator_abc123")
now = datetime.now()
# Sum payouts for the current month
this_month = [
t for t in result["transactions"]
if datetime.fromisoformat(t["date"].replace("Z", "+00:00")).month == now.month
]
total = sum(t["amount"] for t in this_month)
print(f"Paid out this month: ${total}") {
"transactions": [
{
"id": "txn_8f3a91",
"amount": 3240.00,
"status": "completed",
"method": "bank_transfer",
"date": "2026-03-03T09:00:00Z",
"period_start": "2026-02-24",
"period_end": "2026-03-02"
}
],
"page": 1,
"total_pages": 8
} Get Subscriber Data
Pull ranked subscriber data sorted by total lifetime spend. Combine with fan behavior signals to identify high-LTV profiles and build automated retention and re-engagement workflows.
GET /models/:id/subscribers/top
from ofapi import ofapi
def get_top_subscribers(creator_id, limit=20):
data = ofapi(
f"/models/{creator_id}/subscribers/top",
params={"limit": limit}
)
return data["subscribers"]
subs = get_top_subscribers("creator_abc123")
# Flag high-value subs with no recent activity
from datetime import datetime, timezone, timedelta
cutoff = datetime.now(timezone.utc) - timedelta(days=14)
at_risk = [
s for s in subs
if s["total_spent"] > 200
and datetime.fromisoformat(
s["last_purchase_at"].replace("Z", "+00:00")
) < cutoff
]
print(f"{len(at_risk)} high-value subs at churn risk") {
"subscribers": [
{
"user_id": "fan_001",
"username": "bigspender99",
"total_spent": 3420.00,
"subscription_price": 14.99,
"subscribed_since": "2024-03-15",
"last_purchase_at": "2026-03-01T14:22:10Z",
"rebill_count": 24,
"is_active": true
}
],
"total": 847
} Send a Message
Send a direct message to a specific fan — optionally with a PPV price lock and media attachments. Use this to power chatting team automation, drip sequences, mass PPV blasts, and re-engagement campaigns.
POST /messages/send
from ofapi import ofapi
def send_message(creator_id, fan_id, text, ppv_price=None, media_ids=None):
body = {
"creator_id": creator_id,
"fan_id": fan_id,
"text": text,
}
if ppv_price is not None:
body["ppv_price"] = ppv_price
if media_ids:
body["media_ids"] = media_ids
result = ofapi("/messages/send", method="POST", json=body)
return result
# Send a PPV re-engagement message
result = send_message(
creator_id="creator_abc123",
fan_id="fan_001",
text="Hey! Made something special just for you 🔥",
ppv_price=12,
media_ids=["media_xyz789"],
)
print(f"Message sent: {result['message_id']}") {
"message_id": "msg_4d9f2a",
"status": "sent",
"creator_id": "creator_abc123",
"fan_id": "fan_001",
"ppv_price": 12,
"has_media": true,
"sent_at": "2026-03-05T11:42:00Z"
} Error Handling
The raise_for_status() call in the shared client raises a requests.exceptions.HTTPError for any 4xx or 5xx response. Catch it and branch on e.response.status_code for retries, alerting, and graceful degradation.
import requests
from ofapi import ofapi
try:
stats = ofapi(f"/models/creator_abc123/statistics/overview")
except requests.exceptions.HTTPError as e:
status = e.response.status_code
if status == 401:
print("Invalid API key — check OFAPI_KEY env var")
elif status == 403:
print("Creator not linked to your account")
elif status == 429:
retry_after = e.response.headers.get("Retry-After", "5")
print(f"Rate limited — retry after {retry_after}s")
else:
print(f"API error {status}: {e.response.text}")
except requests.exceptions.ConnectionError:
print("Network error — API unreachable") | Status | Meaning | Action |
|---|---|---|
| 200 | OK | Parse and use the response body |
| 400 | Bad Request | Check required params; read message |
| 401 | Unauthorized | Verify X-API-Key header is present and correct |
| 403 | Forbidden | Creator not linked to your API account |
| 429 | Rate Limited | Back off using Retry-After header |
| 500 | Server Error | Retry with exponential backoff; contact support |