Models: platform accounts and income¶
A model's page now lists every platform the model is on, income shows up on the roster and on each model, the pay screens say plainly that commission is paid on OnlyFans earnings, and the public API serves models with their platform accounts and income across platforms.
Every platform a model is on, in one place¶
A model's page has a Platform accounts card beside Local controls. OnlyFans is always the first row; Chaturbate, Stripchat, BongaCams, MyFreeCams and SextPanther can be added by hand.
- Click the OnlyFans row to open it: session status, join date, first post, last synced, and Replace / Detach. A model without one shows Not linked, with Attach.
- Each other platform shows Username: …, and the pencil edits it in place. The trash icon removes it after a confirm.
Guide: Platform accounts
Chaturbate username when adding a model¶
Add model asks for the model's Chaturbate username (optional). It becomes the model's Chaturbate account.
Guide: Add a model
Income on the roster and on each model¶
The roster has an Income (cutoff) column. On a model's page, Earnings is split into two tabs: OF holds the OnlyFans refetch and lock controls, and Income records income for other platforms without leaving the page.
Guide: Income
Commission is paid on OnlyFans earnings (CT and TMT managers)¶
Pay Breakdown, the Daily Bonus explainer and Affiliate Mapping now say that they pay on OnlyFans earnings. Income recorded for other platforms doesn't feed CT commission, the bonus pool or affiliate commission. Nothing changed in how anyone is paid.
Guides: CT Pay Breakdown · TMT manager
Also¶
- Each model's OnlyFans profile (join date, first post) refreshes on the nightly sync.
Public API (for integrations)¶
Changes under /api/public/v1/. The full reference is the API's own docs page
at /api/public/v1/docs/.
Models. GET /models/ and GET /models/<model_id>/ are now their own
Models dataset. The paths haven't changed, and the old
/api/public/model-performance/v1/ base still serves them.
- New fields:
aruna_emailcb_username: the Chaturbate username, or nullhas_of_accountaccounts: one entry per platform, withplatform,platform_name,handleandis_active
- New filters:
platform: models with an active account on any of the given platformshas_of_account
qalso matches platform usernames.
Income. GET /income/ (paged, every model) and GET /income/<model_id>/
(one model) are new.
- The shape is models → platforms → income per period, and both endpoints use it.
- Every income entry carries
period,period_start,period_end,net_usd,entry_countandapportioned. detailsholds a platform's own breakdown, tagged byshape. OnlyFans gives gross, subscriptions, tips and messages. Other platforms givenullfor now.- Filters:
cutoff, orstart+endgroup_by:cutoff(default),monthordayplatform, andsource(ingestormanual)- on the list only:
model,status(the model's status, defaultall),q,pageandpage_size
- Income has no payment status yet. It comes once HRIS pays models out itself.
Compatibility.
- The core fields won't change within v1.
- A platform that gains its own breakdown adds a new
detailsshape, so ignore shapes and platforms you don't recognise. - Breaking changes go to
/v2/.
Technical changes¶
For developers and whoever deploys. None of this needs a guide.
Data model
- Platforms are a registry in code (
agency_models/platforms/), not a table. Each platform's earnings have a different shape, so adding one is a code change. The app reads the list fromGET /api/models/platforms/. ModelPlatformAccount(model × platform) is new: a handle, an external id and an active flag. The app manages them through/api/models/<id>/accounts/. OnlyFans accounts are only created by Attach or Add model.- The OnlyFans link has moved off
Modelonto its OnlyFans account.source,of_api_id,of_user_id,email, the join and first-post dates, the upstream status and session flag, the profile snapshot,last_synced_atand the account-change fields now live onModelPlatformAccount. Code reads them throughmodel.of_account. "Manual" now means the model has no active OnlyFans account. - Earnings rows key on the account.
ModelDayStats,ModelTransactionandModelCutoffIngesthave anaccountFK, and their uniqueness is per account.modelstays on each row. - Deleting a model removes its accounts. The account → model FK is CASCADE. It was PROTECT, which made a model with accounts impossible to delete.
Behaviour
- Refetch, lock, retry and freeze on a model with no OnlyFans account return
409with a message, instead of failing silently. - The OnlyFans profile (
/users/me) is fetched by the nightly ingest only, never by Refetch now. - Manual income is validated against the registry, so OnlyFans income can't be hand-entered and Other still needs a platform name.
Deploy
- Migrations
agency_models0030–0034run on deploy:0030creates one OnlyFans account per OnlyFans model;0031–0034move the OnlyFans fields and point the earnings rows at the account.
- The migrations are reversible. A dry run on a copy of the dev database round-tripped byte for byte.
- No env or settings changes.
Tests
- Postgres runs with
synchronous_commit=offunder pytest only. The full backend suite went from about 79 minutes to about 24.