onlyfans-sdk 2.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- onlyfans_sdk-2.2.2/.gitignore +20 -0
- onlyfans_sdk-2.2.2/PKG-INFO +323 -0
- onlyfans_sdk-2.2.2/README.md +310 -0
- onlyfans_sdk-2.2.2/examples/.env.example +8 -0
- onlyfans_sdk-2.2.2/examples/README.md +94 -0
- onlyfans_sdk-2.2.2/examples/access_api.py +83 -0
- onlyfans_sdk-2.2.2/examples/basic.py +56 -0
- onlyfans_sdk-2.2.2/examples/error_handling.py +67 -0
- onlyfans_sdk-2.2.2/examples/import_connection.py +75 -0
- onlyfans_sdk-2.2.2/examples/pagination.py +75 -0
- onlyfans_sdk-2.2.2/examples/proxy.py +67 -0
- onlyfans_sdk-2.2.2/examples/requirements.txt +2 -0
- onlyfans_sdk-2.2.2/examples/sandbox_comprehensive.py +594 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/__init__.py +60 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/_client.py +302 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/account.py +220 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/analytics.py +568 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/dynamic_rules.py +53 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/earnings.py +192 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/link.py +53 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/messages.py +438 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/models.py +6330 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/posts.py +139 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/promotions.py +547 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/self.py +293 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/subscribers.py +156 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/subscriptions.py +143 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/upload.py +98 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/user_lists.py +275 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/users.py +242 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/vault.py +98 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/vault_cache.py +22 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/vault_lists.py +241 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/vault_media.py +104 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/vault_stats.py +38 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/vault_store.py +22 -0
- onlyfans_sdk-2.2.2/onlyfans_sdk/webhooks.py +399 -0
- onlyfans_sdk-2.2.2/pyproject.toml +21 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Build artifacts
|
|
5
|
+
packages/*/dist/
|
|
6
|
+
packages/*/node_modules/
|
|
7
|
+
packages/python/onlyfans_sdk/__pycache__/
|
|
8
|
+
|
|
9
|
+
# OS files
|
|
10
|
+
.DS_Store
|
|
11
|
+
|
|
12
|
+
# IDE
|
|
13
|
+
.idea/
|
|
14
|
+
.vscode/
|
|
15
|
+
|
|
16
|
+
# Downloaded schemas are now tracked to monitor API changes
|
|
17
|
+
# schemas/openapi.json
|
|
18
|
+
|
|
19
|
+
# Lock files (each SDK has its own)
|
|
20
|
+
package-lock.json
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: onlyfans-sdk
|
|
3
|
+
Version: 2.2.2
|
|
4
|
+
Summary: OFAuth Python SDK v2 - Type-safe API client with Pydantic models
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: httpx>=0.24.0
|
|
8
|
+
Requires-Dist: pydantic>=2.0.0
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
11
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# OFAuth Python SDK
|
|
15
|
+
|
|
16
|
+
Type-safe Python client for the OFAuth API with Pydantic models.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install ofauth
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from onlyfans_sdk import OFAuthClient, account
|
|
28
|
+
|
|
29
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
30
|
+
|
|
31
|
+
result = account.whoami(client)
|
|
32
|
+
print(result)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- Type safety with generated Pydantic v2 models
|
|
38
|
+
- Functional API design (module-level functions, pass client as first arg)
|
|
39
|
+
- Built-in pagination iterators (generators)
|
|
40
|
+
- Proxy support for direct OnlyFans API access
|
|
41
|
+
- Media upload with automatic chunked uploads
|
|
42
|
+
- Webhook verification and routing (Svix-compatible, Flask + FastAPI helpers)
|
|
43
|
+
- Context manager support (`with` statement)
|
|
44
|
+
- httpx-powered HTTP client
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from onlyfans_sdk import OFAuthClient
|
|
50
|
+
|
|
51
|
+
# Basic
|
|
52
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
53
|
+
|
|
54
|
+
# With default connection ID (for access API calls)
|
|
55
|
+
client = OFAuthClient(
|
|
56
|
+
api_key="your-api-key",
|
|
57
|
+
connection_id="conn_xxx",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Full configuration
|
|
61
|
+
client = OFAuthClient(
|
|
62
|
+
api_key="your-api-key",
|
|
63
|
+
connection_id="conn_xxx",
|
|
64
|
+
base_url="https://api-next.ofauth.com",
|
|
65
|
+
timeout=30.0,
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Context manager support:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
with OFAuthClient(api_key="your-api-key") as client:
|
|
73
|
+
result = account.whoami(client)
|
|
74
|
+
# client.close() called automatically
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Usage Examples
|
|
78
|
+
|
|
79
|
+
### Account Operations
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from onlyfans_sdk import OFAuthClient, account
|
|
83
|
+
|
|
84
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
85
|
+
|
|
86
|
+
# Get account info
|
|
87
|
+
info = account.whoami(client)
|
|
88
|
+
print(info["id"], info["permissions"])
|
|
89
|
+
|
|
90
|
+
# List connections
|
|
91
|
+
connections = account.list_connections(client, status="active", limit=10)
|
|
92
|
+
for conn in connections["list"]:
|
|
93
|
+
print(f"{conn['id']}: {conn['userData']['username']} ({conn['status']})")
|
|
94
|
+
|
|
95
|
+
# Get connection settings
|
|
96
|
+
settings = account.get_connection_settings(client, connection_id="conn_xxx")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Access API (OnlyFans Data)
|
|
100
|
+
|
|
101
|
+
Access endpoints require a `connection_id`, set on the client or per-call:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from onlyfans_sdk import OFAuthClient, posts, earnings, subscribers
|
|
105
|
+
from onlyfans_sdk import self as self_module # 'self' is a Python keyword
|
|
106
|
+
|
|
107
|
+
client = OFAuthClient(api_key="your-api-key", connection_id="conn_xxx")
|
|
108
|
+
|
|
109
|
+
# Get creator profile
|
|
110
|
+
profile = self_module.list_selfs(client)
|
|
111
|
+
print(profile["username"])
|
|
112
|
+
|
|
113
|
+
# List posts
|
|
114
|
+
my_posts = posts.list_posts(client, limit=20, sort_by="publish_date")
|
|
115
|
+
for post in my_posts["list"]:
|
|
116
|
+
print(post["id"], post["text"])
|
|
117
|
+
|
|
118
|
+
# Get earnings data
|
|
119
|
+
chart = earnings.list_charts(
|
|
120
|
+
client,
|
|
121
|
+
start_date="2024-01-01",
|
|
122
|
+
end_date="2024-01-31",
|
|
123
|
+
by="total",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# List active subscribers
|
|
127
|
+
subs = subscribers.list_subscribers(client, type="active", limit=50)
|
|
128
|
+
for sub in subs["list"]:
|
|
129
|
+
print(sub)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Pagination
|
|
133
|
+
|
|
134
|
+
Paginated endpoints have `iter_*` generator variants that handle pagination automatically:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from onlyfans_sdk import OFAuthClient, account, subscribers
|
|
138
|
+
|
|
139
|
+
client = OFAuthClient(api_key="your-api-key", connection_id="conn_xxx")
|
|
140
|
+
|
|
141
|
+
# Iterate over all connections
|
|
142
|
+
for connection in account.iter_connections(client):
|
|
143
|
+
print(connection["id"])
|
|
144
|
+
|
|
145
|
+
# With limits
|
|
146
|
+
for subscriber in subscribers.iter_subscribers(client, max_items=100, page_size=20):
|
|
147
|
+
print(subscriber)
|
|
148
|
+
|
|
149
|
+
# Iterate transactions
|
|
150
|
+
from onlyfans_sdk import earnings
|
|
151
|
+
|
|
152
|
+
for tx in earnings.iter_transactions(client, type="tips"):
|
|
153
|
+
print(tx)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Proxy Requests
|
|
157
|
+
|
|
158
|
+
Call any OnlyFans API endpoint through the OFAuth proxy:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
162
|
+
|
|
163
|
+
# GET request
|
|
164
|
+
user = client.proxy("/users/me", connection_id="conn_xxx")
|
|
165
|
+
|
|
166
|
+
# POST request with body
|
|
167
|
+
response = client.proxy(
|
|
168
|
+
"/messages/queue",
|
|
169
|
+
method="POST",
|
|
170
|
+
connection_id="conn_xxx",
|
|
171
|
+
body={"text": "Hello!", "lockedText": False},
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# With query parameters
|
|
175
|
+
subs = client.proxy(
|
|
176
|
+
"/subscriptions/subscribers",
|
|
177
|
+
connection_id="conn_xxx",
|
|
178
|
+
query={"limit": 10},
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Media Upload
|
|
183
|
+
|
|
184
|
+
Handles single-part and multi-part uploads automatically:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
188
|
+
|
|
189
|
+
with open("video.mp4", "rb") as f:
|
|
190
|
+
result = client.upload_media(
|
|
191
|
+
connection_id="conn_xxx",
|
|
192
|
+
filename="video.mp4",
|
|
193
|
+
file=f,
|
|
194
|
+
mime_type="video/mp4",
|
|
195
|
+
on_progress=lambda uploaded, total: print(f"{uploaded}/{total}"),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
print(result["mediaId"])
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Error Handling
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from onlyfans_sdk import OFAuthClient, OFAuthError, account
|
|
205
|
+
|
|
206
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
result = account.whoami(client)
|
|
210
|
+
except OFAuthError as e:
|
|
211
|
+
print(f"API Error {e.status}: {e}")
|
|
212
|
+
print(f"Error code: {e.code}")
|
|
213
|
+
print(f"Details: {e.details}")
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Webhooks
|
|
217
|
+
|
|
218
|
+
Svix-compatible HMAC-SHA256 webhook verification with built-in routing:
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
from onlyfans_sdk.webhooks import create_webhook_router
|
|
222
|
+
|
|
223
|
+
router = create_webhook_router(secret="whsec_...")
|
|
224
|
+
|
|
225
|
+
def handle_connection_created(event):
|
|
226
|
+
conn = event["data"]["connection"]
|
|
227
|
+
print(f"New connection: {conn['id']} ({conn['userData']['username']})")
|
|
228
|
+
|
|
229
|
+
def handle_connection_expired(event):
|
|
230
|
+
print(f"Connection expired: {event['data']['connection']['id']}")
|
|
231
|
+
|
|
232
|
+
router.on("connection.created", handle_connection_created)
|
|
233
|
+
router.on("connection.expired", handle_connection_expired)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Flask Integration
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
from flask import Flask
|
|
240
|
+
from onlyfans_sdk.webhooks import create_webhook_router, create_flask_webhook_handler
|
|
241
|
+
|
|
242
|
+
app = Flask(__name__)
|
|
243
|
+
router = create_webhook_router(secret="whsec_...")
|
|
244
|
+
# ... register handlers ...
|
|
245
|
+
|
|
246
|
+
handler = create_flask_webhook_handler(router)
|
|
247
|
+
app.add_url_rule("/webhooks", view_func=handler, methods=["POST"])
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### FastAPI Integration
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
from fastapi import FastAPI, Request
|
|
254
|
+
from onlyfans_sdk.webhooks import create_webhook_router, create_fastapi_webhook_handler
|
|
255
|
+
|
|
256
|
+
app = FastAPI()
|
|
257
|
+
router = create_webhook_router(secret="whsec_...")
|
|
258
|
+
# ... register handlers ...
|
|
259
|
+
|
|
260
|
+
handle_webhook = create_fastapi_webhook_handler(router)
|
|
261
|
+
|
|
262
|
+
@app.post("/webhooks")
|
|
263
|
+
async def webhook(request: Request):
|
|
264
|
+
return await handle_webhook(request)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Manual Verification
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
from onlyfans_sdk.webhooks import verify_webhook_payload
|
|
271
|
+
|
|
272
|
+
event = verify_webhook_payload(
|
|
273
|
+
payload=request_body,
|
|
274
|
+
headers=request_headers,
|
|
275
|
+
secret="whsec_...",
|
|
276
|
+
)
|
|
277
|
+
print(event["eventType"], event["data"])
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Type Safety with Pydantic Models
|
|
281
|
+
|
|
282
|
+
All response types are available as generated Pydantic v2 models:
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
from onlyfans_sdk import models
|
|
286
|
+
|
|
287
|
+
# Models are generated from the OpenAPI spec:
|
|
288
|
+
# models.V2AccountWhoamiGetResponse
|
|
289
|
+
# models.V2AccountConnectionsGetResponse
|
|
290
|
+
# models.V2AccessPostsGetResponse
|
|
291
|
+
# models.V2AccessEarningsChartGetResponse
|
|
292
|
+
# models.V2AccessSubscribersGetResponse
|
|
293
|
+
# etc.
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Available API Modules
|
|
297
|
+
|
|
298
|
+
| Module | Description |
|
|
299
|
+
|--------|-------------|
|
|
300
|
+
| `account` | Account info, connections, organization settings |
|
|
301
|
+
| `self` | Creator profile, notifications, release forms |
|
|
302
|
+
| `earnings` | Earnings charts, transactions, chargebacks |
|
|
303
|
+
| `analytics` | Posts, stories, streams analytics |
|
|
304
|
+
| `posts` | Post management (CRUD) |
|
|
305
|
+
| `messages` | Chat and messaging |
|
|
306
|
+
| `subscribers` | Subscriber data, notes, discounts |
|
|
307
|
+
| `subscriptions` | Subscription management |
|
|
308
|
+
| `promotions` | Promotions and tracking links |
|
|
309
|
+
| `users` | User operations |
|
|
310
|
+
| `user_lists` | User list management |
|
|
311
|
+
| `vault` | Vault media management |
|
|
312
|
+
| `vault_lists` | Vault list management |
|
|
313
|
+
| `vault_store` | Vault+ (store) |
|
|
314
|
+
| `vault_stats` | Vault statistics |
|
|
315
|
+
| `vault_media` | Vault media operations |
|
|
316
|
+
| `upload` | Media upload (init, chunk, complete) |
|
|
317
|
+
| `link` | Link management |
|
|
318
|
+
| `dynamic_rules` | Dynamic rules |
|
|
319
|
+
| `webhooks` | Webhook verification and routing |
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
Apache-2.0
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# OFAuth Python SDK
|
|
2
|
+
|
|
3
|
+
Type-safe Python client for the OFAuth API with Pydantic models.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install ofauth
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from onlyfans_sdk import OFAuthClient, account
|
|
15
|
+
|
|
16
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
17
|
+
|
|
18
|
+
result = account.whoami(client)
|
|
19
|
+
print(result)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- Type safety with generated Pydantic v2 models
|
|
25
|
+
- Functional API design (module-level functions, pass client as first arg)
|
|
26
|
+
- Built-in pagination iterators (generators)
|
|
27
|
+
- Proxy support for direct OnlyFans API access
|
|
28
|
+
- Media upload with automatic chunked uploads
|
|
29
|
+
- Webhook verification and routing (Svix-compatible, Flask + FastAPI helpers)
|
|
30
|
+
- Context manager support (`with` statement)
|
|
31
|
+
- httpx-powered HTTP client
|
|
32
|
+
|
|
33
|
+
## Configuration
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from onlyfans_sdk import OFAuthClient
|
|
37
|
+
|
|
38
|
+
# Basic
|
|
39
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
40
|
+
|
|
41
|
+
# With default connection ID (for access API calls)
|
|
42
|
+
client = OFAuthClient(
|
|
43
|
+
api_key="your-api-key",
|
|
44
|
+
connection_id="conn_xxx",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Full configuration
|
|
48
|
+
client = OFAuthClient(
|
|
49
|
+
api_key="your-api-key",
|
|
50
|
+
connection_id="conn_xxx",
|
|
51
|
+
base_url="https://api-next.ofauth.com",
|
|
52
|
+
timeout=30.0,
|
|
53
|
+
)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Context manager support:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
with OFAuthClient(api_key="your-api-key") as client:
|
|
60
|
+
result = account.whoami(client)
|
|
61
|
+
# client.close() called automatically
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Usage Examples
|
|
65
|
+
|
|
66
|
+
### Account Operations
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from onlyfans_sdk import OFAuthClient, account
|
|
70
|
+
|
|
71
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
72
|
+
|
|
73
|
+
# Get account info
|
|
74
|
+
info = account.whoami(client)
|
|
75
|
+
print(info["id"], info["permissions"])
|
|
76
|
+
|
|
77
|
+
# List connections
|
|
78
|
+
connections = account.list_connections(client, status="active", limit=10)
|
|
79
|
+
for conn in connections["list"]:
|
|
80
|
+
print(f"{conn['id']}: {conn['userData']['username']} ({conn['status']})")
|
|
81
|
+
|
|
82
|
+
# Get connection settings
|
|
83
|
+
settings = account.get_connection_settings(client, connection_id="conn_xxx")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Access API (OnlyFans Data)
|
|
87
|
+
|
|
88
|
+
Access endpoints require a `connection_id`, set on the client or per-call:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from onlyfans_sdk import OFAuthClient, posts, earnings, subscribers
|
|
92
|
+
from onlyfans_sdk import self as self_module # 'self' is a Python keyword
|
|
93
|
+
|
|
94
|
+
client = OFAuthClient(api_key="your-api-key", connection_id="conn_xxx")
|
|
95
|
+
|
|
96
|
+
# Get creator profile
|
|
97
|
+
profile = self_module.list_selfs(client)
|
|
98
|
+
print(profile["username"])
|
|
99
|
+
|
|
100
|
+
# List posts
|
|
101
|
+
my_posts = posts.list_posts(client, limit=20, sort_by="publish_date")
|
|
102
|
+
for post in my_posts["list"]:
|
|
103
|
+
print(post["id"], post["text"])
|
|
104
|
+
|
|
105
|
+
# Get earnings data
|
|
106
|
+
chart = earnings.list_charts(
|
|
107
|
+
client,
|
|
108
|
+
start_date="2024-01-01",
|
|
109
|
+
end_date="2024-01-31",
|
|
110
|
+
by="total",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# List active subscribers
|
|
114
|
+
subs = subscribers.list_subscribers(client, type="active", limit=50)
|
|
115
|
+
for sub in subs["list"]:
|
|
116
|
+
print(sub)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Pagination
|
|
120
|
+
|
|
121
|
+
Paginated endpoints have `iter_*` generator variants that handle pagination automatically:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from onlyfans_sdk import OFAuthClient, account, subscribers
|
|
125
|
+
|
|
126
|
+
client = OFAuthClient(api_key="your-api-key", connection_id="conn_xxx")
|
|
127
|
+
|
|
128
|
+
# Iterate over all connections
|
|
129
|
+
for connection in account.iter_connections(client):
|
|
130
|
+
print(connection["id"])
|
|
131
|
+
|
|
132
|
+
# With limits
|
|
133
|
+
for subscriber in subscribers.iter_subscribers(client, max_items=100, page_size=20):
|
|
134
|
+
print(subscriber)
|
|
135
|
+
|
|
136
|
+
# Iterate transactions
|
|
137
|
+
from onlyfans_sdk import earnings
|
|
138
|
+
|
|
139
|
+
for tx in earnings.iter_transactions(client, type="tips"):
|
|
140
|
+
print(tx)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Proxy Requests
|
|
144
|
+
|
|
145
|
+
Call any OnlyFans API endpoint through the OFAuth proxy:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
149
|
+
|
|
150
|
+
# GET request
|
|
151
|
+
user = client.proxy("/users/me", connection_id="conn_xxx")
|
|
152
|
+
|
|
153
|
+
# POST request with body
|
|
154
|
+
response = client.proxy(
|
|
155
|
+
"/messages/queue",
|
|
156
|
+
method="POST",
|
|
157
|
+
connection_id="conn_xxx",
|
|
158
|
+
body={"text": "Hello!", "lockedText": False},
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# With query parameters
|
|
162
|
+
subs = client.proxy(
|
|
163
|
+
"/subscriptions/subscribers",
|
|
164
|
+
connection_id="conn_xxx",
|
|
165
|
+
query={"limit": 10},
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Media Upload
|
|
170
|
+
|
|
171
|
+
Handles single-part and multi-part uploads automatically:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
175
|
+
|
|
176
|
+
with open("video.mp4", "rb") as f:
|
|
177
|
+
result = client.upload_media(
|
|
178
|
+
connection_id="conn_xxx",
|
|
179
|
+
filename="video.mp4",
|
|
180
|
+
file=f,
|
|
181
|
+
mime_type="video/mp4",
|
|
182
|
+
on_progress=lambda uploaded, total: print(f"{uploaded}/{total}"),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
print(result["mediaId"])
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Error Handling
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
from onlyfans_sdk import OFAuthClient, OFAuthError, account
|
|
192
|
+
|
|
193
|
+
client = OFAuthClient(api_key="your-api-key")
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
result = account.whoami(client)
|
|
197
|
+
except OFAuthError as e:
|
|
198
|
+
print(f"API Error {e.status}: {e}")
|
|
199
|
+
print(f"Error code: {e.code}")
|
|
200
|
+
print(f"Details: {e.details}")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Webhooks
|
|
204
|
+
|
|
205
|
+
Svix-compatible HMAC-SHA256 webhook verification with built-in routing:
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
from onlyfans_sdk.webhooks import create_webhook_router
|
|
209
|
+
|
|
210
|
+
router = create_webhook_router(secret="whsec_...")
|
|
211
|
+
|
|
212
|
+
def handle_connection_created(event):
|
|
213
|
+
conn = event["data"]["connection"]
|
|
214
|
+
print(f"New connection: {conn['id']} ({conn['userData']['username']})")
|
|
215
|
+
|
|
216
|
+
def handle_connection_expired(event):
|
|
217
|
+
print(f"Connection expired: {event['data']['connection']['id']}")
|
|
218
|
+
|
|
219
|
+
router.on("connection.created", handle_connection_created)
|
|
220
|
+
router.on("connection.expired", handle_connection_expired)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Flask Integration
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from flask import Flask
|
|
227
|
+
from onlyfans_sdk.webhooks import create_webhook_router, create_flask_webhook_handler
|
|
228
|
+
|
|
229
|
+
app = Flask(__name__)
|
|
230
|
+
router = create_webhook_router(secret="whsec_...")
|
|
231
|
+
# ... register handlers ...
|
|
232
|
+
|
|
233
|
+
handler = create_flask_webhook_handler(router)
|
|
234
|
+
app.add_url_rule("/webhooks", view_func=handler, methods=["POST"])
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### FastAPI Integration
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from fastapi import FastAPI, Request
|
|
241
|
+
from onlyfans_sdk.webhooks import create_webhook_router, create_fastapi_webhook_handler
|
|
242
|
+
|
|
243
|
+
app = FastAPI()
|
|
244
|
+
router = create_webhook_router(secret="whsec_...")
|
|
245
|
+
# ... register handlers ...
|
|
246
|
+
|
|
247
|
+
handle_webhook = create_fastapi_webhook_handler(router)
|
|
248
|
+
|
|
249
|
+
@app.post("/webhooks")
|
|
250
|
+
async def webhook(request: Request):
|
|
251
|
+
return await handle_webhook(request)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Manual Verification
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
from onlyfans_sdk.webhooks import verify_webhook_payload
|
|
258
|
+
|
|
259
|
+
event = verify_webhook_payload(
|
|
260
|
+
payload=request_body,
|
|
261
|
+
headers=request_headers,
|
|
262
|
+
secret="whsec_...",
|
|
263
|
+
)
|
|
264
|
+
print(event["eventType"], event["data"])
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Type Safety with Pydantic Models
|
|
268
|
+
|
|
269
|
+
All response types are available as generated Pydantic v2 models:
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
from onlyfans_sdk import models
|
|
273
|
+
|
|
274
|
+
# Models are generated from the OpenAPI spec:
|
|
275
|
+
# models.V2AccountWhoamiGetResponse
|
|
276
|
+
# models.V2AccountConnectionsGetResponse
|
|
277
|
+
# models.V2AccessPostsGetResponse
|
|
278
|
+
# models.V2AccessEarningsChartGetResponse
|
|
279
|
+
# models.V2AccessSubscribersGetResponse
|
|
280
|
+
# etc.
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Available API Modules
|
|
284
|
+
|
|
285
|
+
| Module | Description |
|
|
286
|
+
|--------|-------------|
|
|
287
|
+
| `account` | Account info, connections, organization settings |
|
|
288
|
+
| `self` | Creator profile, notifications, release forms |
|
|
289
|
+
| `earnings` | Earnings charts, transactions, chargebacks |
|
|
290
|
+
| `analytics` | Posts, stories, streams analytics |
|
|
291
|
+
| `posts` | Post management (CRUD) |
|
|
292
|
+
| `messages` | Chat and messaging |
|
|
293
|
+
| `subscribers` | Subscriber data, notes, discounts |
|
|
294
|
+
| `subscriptions` | Subscription management |
|
|
295
|
+
| `promotions` | Promotions and tracking links |
|
|
296
|
+
| `users` | User operations |
|
|
297
|
+
| `user_lists` | User list management |
|
|
298
|
+
| `vault` | Vault media management |
|
|
299
|
+
| `vault_lists` | Vault list management |
|
|
300
|
+
| `vault_store` | Vault+ (store) |
|
|
301
|
+
| `vault_stats` | Vault statistics |
|
|
302
|
+
| `vault_media` | Vault media operations |
|
|
303
|
+
| `upload` | Media upload (init, chunk, complete) |
|
|
304
|
+
| `link` | Link management |
|
|
305
|
+
| `dynamic_rules` | Dynamic rules |
|
|
306
|
+
| `webhooks` | Webhook verification and routing |
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
Apache-2.0
|