Skip to content

Commit b8ee283

Browse files
feat(api): api update
1 parent 78fc5ee commit b8ee283

25 files changed

Lines changed: 555 additions & 389 deletions

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 265
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/onlyfansapi/onlyfansapi-0f5b27a377922abdbb2e57feb12601f2d92833cefaad9e301ad09a9972ea72c2.yml
3-
openapi_spec_hash: 57c96cc1e38a5988580696892c0ce585
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/onlyfansapi/onlyfansapi-5b7eaf3aea520bc245be9b93991257f9c1b5ad2ebad57eb17e80ac97fbdc66a4.yml
3+
openapi_spec_hash: c6cfa0dc8655e915bd8f945d84121803
44
config_hash: 397c91e15c0024f8b5bbed9b82c2348c

src/onlyfansapi/resources/data_exports.py

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def create(
7070
"fans",
7171
"followings",
7272
"profile_visitors",
73+
"fansly_chat_messages",
7374
],
7475
account_ids: SequenceNotStr[str] | Omit = omit,
7576
auto_start: bool | Omit = omit,
@@ -91,18 +92,20 @@ def create(
9192
end_date: The end date for the export (ISO 8601 format).
9293
9394
file_type: The output file format. Supported formats vary by export type: `csv` or `xlsx`
94-
for transactions, chat_messages, trial_links, tracking_links, smart_links,
95-
payouts, chargebacks, public_profiles, fans, followings, profile_visitors; `zip`
96-
for media_vault.
95+
for transactions, chat_messages, fansly_chat_messages, trial_links,
96+
tracking_links, smart_links, payouts, chargebacks, public_profiles, fans,
97+
followings, profile_visitors; `zip` for media_vault.
9798
9899
start_date: The start date for the export (ISO 8601 format).
99100
100-
type: The type of data to export. `profile_visitors` returns one row per account per
101-
day, scraped one day at a time so the daily numbers are not aggregated away by
102-
OnlyFans.
101+
type: The type of data to export. Use `fansly_chat_messages` to export Fansly chat
102+
messages (all other types are OnlyFans). `profile_visitors` returns one row per
103+
account per day, scraped one day at a time so the daily numbers are not
104+
aggregated away by OnlyFans.
103105
104106
account_ids: Array of account prefixed IDs to export data from. Not required for
105-
`public_profiles` type.
107+
`public_profiles` type. For `fansly_chat_messages`, pass Fansly account prefixed
108+
IDs (`fansly_acct_...`); all other types take OnlyFans account IDs.
106109
107110
auto_start: When true, automatically starts the export after creation.
108111
@@ -113,20 +116,23 @@ def create(
113116
account, max 10,000,000), `maxChats` (optional per-account chat scrape limit),
114117
`skipMassMessages` (optional, bool), `chatIds` (optional array of numeric
115118
fan/chat IDs; filters output and can drastically reduce totals). For
116-
`media_vault`: `mediaType` (required, one of: `all`, `photo`, `gif`, `video`,
117-
`audio`). For `fans`: `type` (required, one of: `all`, `active`, `expired`,
118-
`latest`). For `followings`: `type` (required, one of: `all`, `active`,
119-
`expired`). For `public_profiles`: `query` (optional, full-text search),
120-
`gender` (optional, filter: male, female, trans, couple), `minSubscribePrice`
121-
(optional, USD), `maxSubscribePrice` (optional, USD), `location` (optional),
122-
`minPostsCount` (optional, minimum posts), `minPhotosCount` (optional, minimum
123-
photos), `minVideosCount` (optional, minimum videos), `minSubscribersCount`
124-
(optional, minimum subscribers), `maxSubscribersCount` (optional, maximum
125-
subscribers), `minJoinDate` (optional, ISO 8601 date), `minLastSeenAt`
126-
(optional, ISO 8601 date), `createdAtFrom` (optional, ISO 8601 date, profile
127-
added to DB after), `createdAtTo` (optional, ISO 8601 date, profile added to DB
128-
before), `instagram` (optional), `twitter` (optional), `tiktok` (optional),
129-
`maxResults` (optional, limit results).
119+
`fansly_chat_messages`: `maxMessages` (required per account, max 10,000,000),
120+
`maxChats` (optional per-account chat scrape limit), `chatIds` (optional array
121+
of Fansly group ID strings; filters output and can drastically reduce totals).
122+
For `media_vault`: `mediaType` (required, one of: `all`, `photo`, `gif`,
123+
`video`, `audio`). For `fans`: `type` (required, one of: `all`, `active`,
124+
`expired`, `latest`). For `followings`: `type` (required, one of: `all`,
125+
`active`, `expired`). For `public_profiles`: `query` (optional, full-text
126+
search), `gender` (optional, filter: male, female, trans, couple),
127+
`minSubscribePrice` (optional, USD), `maxSubscribePrice` (optional, USD),
128+
`location` (optional), `minPostsCount` (optional, minimum posts),
129+
`minPhotosCount` (optional, minimum photos), `minVideosCount` (optional, minimum
130+
videos), `minSubscribersCount` (optional, minimum subscribers),
131+
`maxSubscribersCount` (optional, maximum subscribers), `minJoinDate` (optional,
132+
ISO 8601 date), `minLastSeenAt` (optional, ISO 8601 date), `createdAtFrom`
133+
(optional, ISO 8601 date, profile added to DB after), `createdAtTo` (optional,
134+
ISO 8601 date, profile added to DB before), `instagram` (optional), `twitter`
135+
(optional), `tiktok` (optional), `maxResults` (optional, limit results).
130136
131137
extra_headers: Send extra headers
132138
@@ -230,6 +236,7 @@ def list(
230236
"fans",
231237
"followings",
232238
"profile_visitors",
239+
"fansly_chat_messages",
233240
]
234241
| Omit = omit,
235242
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -428,6 +435,7 @@ async def create(
428435
"fans",
429436
"followings",
430437
"profile_visitors",
438+
"fansly_chat_messages",
431439
],
432440
account_ids: SequenceNotStr[str] | Omit = omit,
433441
auto_start: bool | Omit = omit,
@@ -449,18 +457,20 @@ async def create(
449457
end_date: The end date for the export (ISO 8601 format).
450458
451459
file_type: The output file format. Supported formats vary by export type: `csv` or `xlsx`
452-
for transactions, chat_messages, trial_links, tracking_links, smart_links,
453-
payouts, chargebacks, public_profiles, fans, followings, profile_visitors; `zip`
454-
for media_vault.
460+
for transactions, chat_messages, fansly_chat_messages, trial_links,
461+
tracking_links, smart_links, payouts, chargebacks, public_profiles, fans,
462+
followings, profile_visitors; `zip` for media_vault.
455463
456464
start_date: The start date for the export (ISO 8601 format).
457465
458-
type: The type of data to export. `profile_visitors` returns one row per account per
459-
day, scraped one day at a time so the daily numbers are not aggregated away by
460-
OnlyFans.
466+
type: The type of data to export. Use `fansly_chat_messages` to export Fansly chat
467+
messages (all other types are OnlyFans). `profile_visitors` returns one row per
468+
account per day, scraped one day at a time so the daily numbers are not
469+
aggregated away by OnlyFans.
461470
462471
account_ids: Array of account prefixed IDs to export data from. Not required for
463-
`public_profiles` type.
472+
`public_profiles` type. For `fansly_chat_messages`, pass Fansly account prefixed
473+
IDs (`fansly_acct_...`); all other types take OnlyFans account IDs.
464474
465475
auto_start: When true, automatically starts the export after creation.
466476
@@ -471,20 +481,23 @@ async def create(
471481
account, max 10,000,000), `maxChats` (optional per-account chat scrape limit),
472482
`skipMassMessages` (optional, bool), `chatIds` (optional array of numeric
473483
fan/chat IDs; filters output and can drastically reduce totals). For
474-
`media_vault`: `mediaType` (required, one of: `all`, `photo`, `gif`, `video`,
475-
`audio`). For `fans`: `type` (required, one of: `all`, `active`, `expired`,
476-
`latest`). For `followings`: `type` (required, one of: `all`, `active`,
477-
`expired`). For `public_profiles`: `query` (optional, full-text search),
478-
`gender` (optional, filter: male, female, trans, couple), `minSubscribePrice`
479-
(optional, USD), `maxSubscribePrice` (optional, USD), `location` (optional),
480-
`minPostsCount` (optional, minimum posts), `minPhotosCount` (optional, minimum
481-
photos), `minVideosCount` (optional, minimum videos), `minSubscribersCount`
482-
(optional, minimum subscribers), `maxSubscribersCount` (optional, maximum
483-
subscribers), `minJoinDate` (optional, ISO 8601 date), `minLastSeenAt`
484-
(optional, ISO 8601 date), `createdAtFrom` (optional, ISO 8601 date, profile
485-
added to DB after), `createdAtTo` (optional, ISO 8601 date, profile added to DB
486-
before), `instagram` (optional), `twitter` (optional), `tiktok` (optional),
487-
`maxResults` (optional, limit results).
484+
`fansly_chat_messages`: `maxMessages` (required per account, max 10,000,000),
485+
`maxChats` (optional per-account chat scrape limit), `chatIds` (optional array
486+
of Fansly group ID strings; filters output and can drastically reduce totals).
487+
For `media_vault`: `mediaType` (required, one of: `all`, `photo`, `gif`,
488+
`video`, `audio`). For `fans`: `type` (required, one of: `all`, `active`,
489+
`expired`, `latest`). For `followings`: `type` (required, one of: `all`,
490+
`active`, `expired`). For `public_profiles`: `query` (optional, full-text
491+
search), `gender` (optional, filter: male, female, trans, couple),
492+
`minSubscribePrice` (optional, USD), `maxSubscribePrice` (optional, USD),
493+
`location` (optional), `minPostsCount` (optional, minimum posts),
494+
`minPhotosCount` (optional, minimum photos), `minVideosCount` (optional, minimum
495+
videos), `minSubscribersCount` (optional, minimum subscribers),
496+
`maxSubscribersCount` (optional, maximum subscribers), `minJoinDate` (optional,
497+
ISO 8601 date), `minLastSeenAt` (optional, ISO 8601 date), `createdAtFrom`
498+
(optional, ISO 8601 date, profile added to DB after), `createdAtTo` (optional,
499+
ISO 8601 date, profile added to DB before), `instagram` (optional), `twitter`
500+
(optional), `tiktok` (optional), `maxResults` (optional, limit results).
488501
489502
extra_headers: Send extra headers
490503
@@ -588,6 +601,7 @@ async def list(
588601
"fans",
589602
"followings",
590603
"profile_visitors",
604+
"fansly_chat_messages",
591605
]
592606
| Omit = omit,
593607
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.

src/onlyfansapi/resources/media/vault/lists/lists.py

Lines changed: 78 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
from typing import Any, cast
6+
57
import httpx
68

79
from .media import (
@@ -175,6 +177,7 @@ def list(
175177
self,
176178
account: str,
177179
*,
180+
lightweight: bool | Omit = omit,
178181
limit: int | Omit = omit,
179182
offset: int | Omit = omit,
180183
query: str | Omit = omit,
@@ -188,7 +191,25 @@ def list(
188191
"""
189192
List your Vault lists (categories).
190193
194+
Every response carries an `ETag` computed over the `data` payload. Send it back
195+
as `If-None-Match` on your next call and you will get a `304 Not Modified` with
196+
an empty body when nothing changed, so you can keep serving your cached copy
197+
instead of re-parsing the full list. Credits are debited either way — we still
198+
have to ask OnlyFans for the current state to know whether it changed.
199+
200+
The `ETag` covers `data` only, never `_meta` — your credits balance changes on
201+
every call, so including it would mean the `ETag` never matches. Because a `304`
202+
has no body, it also has no `_meta`: read the current credits and rate-limit
203+
counters from the `X-OFAPI-Credits-Used`, `X-OFAPI-Credits-Balance`,
204+
`X-Rate-Limit-Limit-Minute` and `X-Rate-Limit-Remaining-Minute` response
205+
headers, which are sent on `304` responses too. The `_meta` inside a body you
206+
cached earlier is stale by definition.
207+
191208
Args:
209+
lightweight: Set to `true` to return only `id`, `name`, `type`, `canUpdate` and a rolled-up
210+
`mediaCount` per list, dropping the `medias` previews. Much smaller payload —
211+
ideal for rendering a folder picker. Default: `false`
212+
192213
limit: Number of media to return per page. Default: `24`
193214
194215
offset: The offset used for pagination. Default `0`
@@ -205,23 +226,27 @@ def list(
205226
"""
206227
if not account:
207228
raise ValueError(f"Expected a non-empty value for `account` but received {account!r}")
208-
return self._get(
209-
path_template("/api/{account}/media/vault/lists", account=account),
210-
options=make_request_options(
211-
extra_headers=extra_headers,
212-
extra_query=extra_query,
213-
extra_body=extra_body,
214-
timeout=timeout,
215-
query=maybe_transform(
216-
{
217-
"limit": limit,
218-
"offset": offset,
219-
"query": query,
220-
},
221-
list_list_params.ListListParams,
229+
return cast(
230+
ListListResponse,
231+
self._get(
232+
path_template("/api/{account}/media/vault/lists", account=account),
233+
options=make_request_options(
234+
extra_headers=extra_headers,
235+
extra_query=extra_query,
236+
extra_body=extra_body,
237+
timeout=timeout,
238+
query=maybe_transform(
239+
{
240+
"lightweight": lightweight,
241+
"limit": limit,
242+
"offset": offset,
243+
"query": query,
244+
},
245+
list_list_params.ListListParams,
246+
),
222247
),
248+
cast_to=cast(Any, ListListResponse), # Union types cannot be passed in as arguments in the type system
223249
),
224-
cast_to=ListListResponse,
225250
)
226251

227252
def delete(
@@ -403,6 +428,7 @@ async def list(
403428
self,
404429
account: str,
405430
*,
431+
lightweight: bool | Omit = omit,
406432
limit: int | Omit = omit,
407433
offset: int | Omit = omit,
408434
query: str | Omit = omit,
@@ -416,7 +442,25 @@ async def list(
416442
"""
417443
List your Vault lists (categories).
418444
445+
Every response carries an `ETag` computed over the `data` payload. Send it back
446+
as `If-None-Match` on your next call and you will get a `304 Not Modified` with
447+
an empty body when nothing changed, so you can keep serving your cached copy
448+
instead of re-parsing the full list. Credits are debited either way — we still
449+
have to ask OnlyFans for the current state to know whether it changed.
450+
451+
The `ETag` covers `data` only, never `_meta` — your credits balance changes on
452+
every call, so including it would mean the `ETag` never matches. Because a `304`
453+
has no body, it also has no `_meta`: read the current credits and rate-limit
454+
counters from the `X-OFAPI-Credits-Used`, `X-OFAPI-Credits-Balance`,
455+
`X-Rate-Limit-Limit-Minute` and `X-Rate-Limit-Remaining-Minute` response
456+
headers, which are sent on `304` responses too. The `_meta` inside a body you
457+
cached earlier is stale by definition.
458+
419459
Args:
460+
lightweight: Set to `true` to return only `id`, `name`, `type`, `canUpdate` and a rolled-up
461+
`mediaCount` per list, dropping the `medias` previews. Much smaller payload —
462+
ideal for rendering a folder picker. Default: `false`
463+
420464
limit: Number of media to return per page. Default: `24`
421465
422466
offset: The offset used for pagination. Default `0`
@@ -433,23 +477,27 @@ async def list(
433477
"""
434478
if not account:
435479
raise ValueError(f"Expected a non-empty value for `account` but received {account!r}")
436-
return await self._get(
437-
path_template("/api/{account}/media/vault/lists", account=account),
438-
options=make_request_options(
439-
extra_headers=extra_headers,
440-
extra_query=extra_query,
441-
extra_body=extra_body,
442-
timeout=timeout,
443-
query=await async_maybe_transform(
444-
{
445-
"limit": limit,
446-
"offset": offset,
447-
"query": query,
448-
},
449-
list_list_params.ListListParams,
480+
return cast(
481+
ListListResponse,
482+
await self._get(
483+
path_template("/api/{account}/media/vault/lists", account=account),
484+
options=make_request_options(
485+
extra_headers=extra_headers,
486+
extra_query=extra_query,
487+
extra_body=extra_body,
488+
timeout=timeout,
489+
query=await async_maybe_transform(
490+
{
491+
"lightweight": lightweight,
492+
"limit": limit,
493+
"offset": offset,
494+
"query": query,
495+
},
496+
list_list_params.ListListParams,
497+
),
450498
),
499+
cast_to=cast(Any, ListListResponse), # Union types cannot be passed in as arguments in the type system
451500
),
452-
cast_to=ListListResponse,
453501
)
454502

455503
async def delete(

0 commit comments

Comments
 (0)