> ## Documentation Index
> Fetch the complete documentation index at: https://docs.onlyfansapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Endpoint Data Sources (/introduction/essentials/endpoint-data-sources)

import {DatabaseIcon, DatabaseZapIcon, ZapIcon} from "lucide-react";

We classify every endpoint as one of three types:

<Cards className="grid grid-cols-3 gap-4 @container">
  <Card icon={<DatabaseZapIcon className="text-fd-primary" />} title="Hybrid">
    <span className="font-medium text-fd-primary">We make a live request to OnlyFans and then enriches the response</span>
    with fields from the our database (timestamps, tags, computed classifications, etc.).
  </Card>

  <Card icon={<DatabaseIcon className="text-fd-primary" />} title="Computed">
    <span className="font-medium text-fd-primary">We never call OnlyFans during the request.</span>
    The response is built entirely from data we have stored, synced, or calculated.
  </Card>

  <Card icon={<ZapIcon className="text-fd-primary" />} title="Live passthrough">
    <span className="font-medium text-fd-primary">Anything not listed as Hybrid or Computed.</span>
    The response is straight from OnlyFans, with no enrichment.
  </Card>
</Cards>

## Quick answers to common questions

* `GET /{account}/statistics/overview` → **Live passthrough.** The numbers come straight from OnlyFans.
* `GET /{account}/fans/active` → **Hybrid.** OnlyFans response plus a `lastReplyAt` timestamp on each fan, sourced from the OFAPI database.
* `GET /{account}/transactions` → **Hybrid.** OnlyFans response plus a computed `type` field (`subs`, `tips`, `post`, `chat_messages`, `stream`).

## Hybrid endpoints

These endpoints call OnlyFans live and then enrich the response with extra fields from the OFAPI database. The "Enriched with" column lists exactly what OFAPI adds on top of the OnlyFans payload.

| HTTP  | Path                                         | Enriched by OFAPI                                                                                        |
| ----- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `GET` | `/{account}/chats`                           | `lastReplyAt` per chat                                                                                   |
| `GET` | `/{account}/chats/{chat_id}/messages`        | `lastReplyAt` per participant                                                                            |
| `GET` | `/{account}/fans/all`                        | `lastReplyAt` per fan                                                                                    |
| `GET` | `/{account}/fans/active`                     | `lastReplyAt` per fan                                                                                    |
| `GET` | `/{account}/fans/expired`                    | `lastReplyAt` per fan                                                                                    |
| `GET` | `/{account}/fans/latest`                     | `lastReplyAt` per fan                                                                                    |
| `GET` | `/{account}/fans/top`                        | `lastReplyAt` per fan                                                                                    |
| `GET` | `/{account}/users/{username}`                | `lastReplyAt` (if the user is a fan)                                                                     |
| `GET` | `/{account}/transactions`                    | Computed `type` (`subs` / `tips` / `post` / `chat_messages` / `stream`), derived from the OF description |
| `GET` | `/{account}/tracking-links`                  | Tags, cached revenue & spender counts, full campaign URL prefixed with the creator's profile URL         |
| `GET` | `/{account}/trial-links`                     | Tags, cached revenue & spender counts, full campaign URL                                                 |
| `GET` | `/{account}/engagement/messages/top-message` | Engagement stats joined onto the message metadata                                                        |

## Computed endpoints

These endpoints never hit OnlyFans during the request. The response is built entirely from data OFAPI has stored, synced, or calculated.

### Smart Links (analytics + management)

| HTTP     | Path                                       | Notes                                                        |
| -------- | ------------------------------------------ | ------------------------------------------------------------ |
| `GET`    | `/smart-links`                             | List smart links                                             |
| `POST`   | `/smart-links`                             | Create a smart link                                          |
| `GET`    | `/smart-links/{smart_link_id}`             | Fetch a single smart link                                    |
| `DELETE` | `/smart-links/{smart_link_id}`             | Delete a smart link                                          |
| `GET`    | `/smart-links/{smart_link_id}/stats`       | Clicks, subs, revenue, spenders aggregated from OFAPI tables |
| `GET`    | `/smart-links/{smart_link_id}/cohort-arps` | ARPS by acquisition cohort                                   |
| `GET`    | `/smart-links/{smart_link_id}/fans`        | Attributed fans with aggregate metrics                       |
| `GET`    | `/smart-links/{smart_link_id}/spenders`    | Fans where spend `> 0`                                       |
| `GET`    | `/smart-links/{smart_link_id}/clicks`      | Raw click rows                                               |
| `GET`    | `/smart-links/{smart_link_id}/conversions` | Raw conversion rows                                          |

### Stored (cache) link inventory

Explicitly free — these never call OnlyFans.

| HTTP  | Path                                      | Notes                          |
| ----- | ----------------------------------------- | ------------------------------ |
| `GET` | `/{account}/stored/tracking-links`        | Cached tracking links          |
| `GET` | `/{account}/stored/trial-links`           | Cached free trial links        |
| `GET` | `/{account}/stored/shared-tracking-links` | Cached shared tracking links   |
| `GET` | `/{account}/stored/shared-trial-links`    | Cached shared free trial links |

### Webhooks

| HTTP     | Path                                                     | Notes                         |
| -------- | -------------------------------------------------------- | ----------------------------- |
| `GET`    | `/{account}/webhooks`                                    | List webhooks                 |
| `POST`   | `/{account}/webhooks`                                    | Create a webhook              |
| `GET`    | `/{account}/webhooks/{webhook_id}`                       | Fetch a single webhook        |
| `PUT`    | `/{account}/webhooks/{webhook_id}`                       | Update a webhook              |
| `DELETE` | `/{account}/webhooks/{webhook_id}`                       | Delete a webhook              |
| `GET`    | `/{account}/webhooks/events`                             | Enum of available event types |
| `GET`    | `/{account}/webhooks/{webhookEventType}/example-payload` | Static payload generator      |

### Data exports

| HTTP     | Path                                   | Notes                      |
| -------- | -------------------------------------- | -------------------------- |
| `GET`    | `/data-exports`                        | List data exports          |
| `POST`   | `/data-exports`                        | Create a data export       |
| `GET`    | `/data-exports/{data_export_id}`       | Fetch a single data export |
| `POST`   | `/data-exports/{data_export_id}/start` | Start a data export        |
| `DELETE` | `/data-exports/{data_export_id}`       | Delete a data export       |
| `POST`   | `/data-exports/{data_export_id}/retry` | Retry a data export        |

### Link tags

Tags live entirely in the OFAPI database — none of these endpoints touch OnlyFans.

| HTTP     | Path                                                              | Notes                                     |
| -------- | ----------------------------------------------------------------- | ----------------------------------------- |
| `GET`    | `/link-tags`                                                      | List every tag in your org                |
| `GET`    | `/{account}/tracking-links/{tracking_link_id}/tags`               | List tags on a tracking link              |
| `POST`   | `/{account}/tracking-links/{tracking_link_id}/tags`               | Add tags to a tracking link               |
| `DELETE` | `/{account}/tracking-links/{tracking_link_id}/tags`               | Remove tags from a tracking link          |
| `GET`    | `/{account}/trial-links/{trial_link_id}/tags`                     | List tags on a free trial link            |
| `POST`   | `/{account}/trial-links/{trial_link_id}/tags`                     | Add tags to a free trial link             |
| `DELETE` | `/{account}/trial-links/{trial_link_id}/tags`                     | Remove tags from a free trial link        |
| `GET`    | `/{account}/shared-tracking-links/{shared_tracking_link_id}/tags` | List tags on a shared tracking link       |
| `POST`   | `/{account}/shared-tracking-links/{shared_tracking_link_id}/tags` | Add tags to a shared tracking link        |
| `DELETE` | `/{account}/shared-tracking-links/{shared_tracking_link_id}/tags` | Remove tags from a shared tracking link   |
| `GET`    | `/{account}/shared-trial-links/{shared_trial_link_id}/tags`       | List tags on a shared free trial link     |
| `POST`   | `/{account}/shared-trial-links/{shared_trial_link_id}/tags`       | Add tags to a shared free trial link      |
| `DELETE` | `/{account}/shared-trial-links/{shared_trial_link_id}/tags`       | Remove tags from a shared free trial link |

### Auth & accounts

The request itself only reads or writes OFAPI rows; the actual OnlyFans login runs asynchronously in a queued job.

| HTTP     | Path                                               | Notes                             |
| -------- | -------------------------------------------------- | --------------------------------- |
| `GET`    | `/whoami`                                          | Identify the current API key      |
| `GET`    | `/accounts`                                        | List connected OF accounts        |
| `DELETE` | `/accounts/{account}`                              | Disconnect an OF account          |
| `POST`   | `/authenticate`                                    | Start an authentication attempt   |
| `GET`    | `/authenticate/{attempt_id}`                       | Poll attempt status               |
| `PUT`    | `/authenticate/{attempt_id}`                       | Submit credentials / 2FA          |
| `POST`   | `/authenticate/{attempt_id}/send-email-to-creator` | Trigger the OF email-code helper  |
| `POST`   | `/authenticate/{account_id}/reauthenticate`        | Re-auth an existing account       |
| `POST`   | `/client-sessions`                                 | Mint a short-lived client session |

### Media upload status

| HTTP  | Path                                      | Notes                            |
| ----- | ----------------------------------------- | -------------------------------- |
| `GET` | `/{account}/media/upload/{upload}/status` | Poll an in-progress media upload |

## Important clarifications

A couple of endpoints sound like they should be Hybrid or Computed, but aren't. Calling them out here to preempt confusion:

<Callout title="These sound calculated, but are Live passthrough" type="warn">
  The following endpoints return numbers and metrics, but the response is a straight passthrough of what OnlyFans returns — OFAPI does not compute or enrich them:

  * `/statistics/overview`
  * `/statistics/total-transactions`
  * `/statistics/subscriber-metrics`
  * `/me/model-start-date`
  * `/me/top-percentage`
  * `/payouts/balances`
  * `/payouts/eligibility`
  * `/payouts/list-earning-statistics`
  * `/payouts/list-payout-requests`
</Callout>

## Media URLs & file downloads

OnlyFans media files (everything served from `https://cdn*.onlyfans.com/`) get special handling. The first time we see a media file, we save our own copy of it; subsequent requests for that same file are served from our own CDN at `https://cdn.fansapi.com/` instead of contacting OnlyFans.

Two reasons this matters for you:

* **It saves credits.** Once a file is cached, fetching it again does not consume any credits — OnlyFans is never contacted.
* **It's significantly faster.** Our CDN is geographically distributed, so cached files are served from a location close to your end users instead of round-tripping through OnlyFans every time.

This affects two kinds of endpoints.

### Downloading or scraping media files

The endpoints that hand you back actual media bytes — [Download Media](/api-reference/media/download-media-from-the-only-fans-cdn) and the deprecated [Scrape Media](/api-reference/media/deprecated-scrape-media-from-the-only-fans-cdn) — first check whether we already have that file in our own CDN.

* **If we have it cached** → you get a URL on our own `cdn.fansapi.com`. Download Media returns a `302` redirect to it (most HTTP clients follow redirects automatically; `curl` needs `-L`). Scrape Media returns it as `temporary_url` in the response body. **No credits are charged in this case**, because OnlyFans is never contacted.
* **If we don't have it cached yet** → we stream the bytes from OnlyFans straight back to you as the response, and at the same time start saving our own copy. The next time anyone asks for that same file, it will be served from our CDN.

### Endpoints that return media URLs in their response

Any endpoint that returns OnlyFans CDN URLs in its response body — List Chat Messages, List Posts, List Vault Media, and so on — follows the same caching pattern, applied per-URL:

* Each `https://cdn*.onlyfans.com/*` URL in the response is checked against our CDN.
* **URLs we already have cached** are replaced with the equivalent `https://cdn.fansapi.com/*` URL before the response is returned to you.
* **URLs we don't have cached yet** are left as the original `https://cdn*.onlyfans.com/*` URL, and we start saving our own copy. Future responses that include the same URL will return the `cdn.fansapi.com` version instead.

This rewriting is applied per-URL, so a single response can contain any mix of OnlyFans CDN URLs and rewritten `cdn.fansapi.com` URLs depending on what we've already cached.

## Anything not listed here

If an endpoint isn't listed on this page, **treat it as a Live passthrough.** The response is the OnlyFans payload, unmodified by OFAPI.

{/*
  Maintainer note — to keep this page accurate, in the OFAPI app repo:

  - The Hybrid list is exactly the set of `formatWith(...)` callsites under
  `app/Http/Controllers/`. Run:
    grep -rn "formatWith" app --include="*.php"
  to find them.
  - The Computed list is API controllers (registered in `routes/api.php`) that do
  not inject `ApiOnlyFansClientForAccount`. Run:
    grep -rL "ApiOnlyFansClientForAccount" app/Http/Controllers/Api
  to find candidates.
  */}