Fix a fan's wrong source
Review and correct fans whose stored source came from the DM scan — assign the right one, or undo a prior override.
The Fan Source Review queue (/source-layout/fan-sources, "Needs review" /
"Assigned manually" tabs in the panel) covers one specific population: fans whose current
fan_source.kind is llm — i.e. their source came from the DM-scan, not from a click, a mapped
link, or a campaign.
Hard sources can't be touched here
A fan attributed by cid, a mapped link, or a campaign is rejected with hard_source if you
try to assign or undo through this queue. To change how a whole campaign resolves, use
Confirm the source for a scanned campaign
instead; there's no per-fan override for hard-attributed money.
Read the queue
curl "https://app.tease.link/api/admin/source-layout/fan-sources?mode=pending&limit=50" \
-H "Authorization: Bearer $TEASE_API_KEY"mode=pending (default) lists fans not yet manually resolved; mode=manual lists ones you've
already manually assigned, for undoing. Each row carries a proposal computed against your
registered sources for that fan's guessed platform:
proposal.status | Meaning |
|---|---|
unique | Exactly one registered account matches the guessed platform — the obvious pick. |
ambiguous | More than one registered account matches — you choose. |
unregistered | No registered account matches this platform at all. |
Each row also carries a state.version — an opaque tag over the fan's current source, kind,
provenance, and any prior override — required on every write as an optimistic-concurrency check.
Assign a source
curl -X POST "https://app.tease.link/api/admin/source-layout/fan-sources/assign" \
-H "Authorization: Bearer $TEASE_API_KEY" -H "Content-Type: application/json" \
-d '{"items": [{
"ref": {"page_owner_id": "owner_123", "fan_id": "fan_456"},
"source_key": "ig-main.link",
"expected_version": "a1b2c3d4e5f6a1b2c3d4"
}]}'Send expected_version from the row you just read. Each item in the response comes back with a
status:
status | Meaning |
|---|---|
assigned | Written. |
unchanged | Already exactly this source/provenance — a no-op, not an error. |
conflict | source_changed — the fan's version moved since you read it; re-fetch. |
rejected | hard_source, source_not_registered, or (for mode=pending selections) ambiguous_sources on an auto-only path. |
Undo a manual assignment
curl -X POST "https://app.tease.link/api/admin/source-layout/fan-sources/undo" \
-H "Authorization: Bearer $TEASE_API_KEY" -H "Content-Type: application/json" \
-d '{"items": [{
"ref": {"page_owner_id": "owner_123", "fan_id": "fan_456"},
"override_id": 981,
"expected_version": "9f8e7d6c5b4a3f2e1d0c"
}]}'override_id comes from the row's state.override_id. Undoing a fan whose override was already
reversed returns unchanged/already_undone rather than an error — safe to retry.
Auto-assign the unambiguous ones in bulk
For the subset of the pending queue where exactly one candidate exists, you don't have to confirm each one by hand:
curl -X POST "https://app.tease.link/api/admin/source-layout/fan-sources/backfill-unique" \
-H "Authorization: Bearer $TEASE_API_KEY" -H "Content-Type: application/json" \
-d '{"apply": false}'apply: false (the default) is a dry run — it returns the fans it would touch and their
target source without writing anything. Set apply: true to actually assign them.
Money surfaces refresh automatically
A successful assign or undo invalidates the dashboard-money, /api/admin/stats, and
source-leaderboard caches, plus the Links tab's read cache — you don't need to manually refresh
anything else in the panel after fixing a fan.
What's next
- Resolve an ambiguous LLM-guessed source — the narrower, generic-platform-only view of this same fan population.
- Confirm the source for a scanned campaign — for hard-attributed (link/campaign) fans instead.
Create a source-link rule
Author a durable rule mapping an OnlyFans link identity to a source, so future fans auto-attribute without manual confirmation.
Resolve an ambiguous LLM-guessed source
When the DM scan only recognized a platform (e.g. "instagram") and not a specific account, manually point that group of fans at the real one.