> ## Documentation Index
> Fetch the complete documentation index at: https://www.dropfans.io/developers/llms.txt
> Use this file to discover all available pages before exploring further.

# Acting for a creator: agencies and CRMs

> An agency’s own key runs every creator and AI persona it manages, and an app owner’s key every account its app onboarded: call /v1/creators/{creatorId}/….

- Source: https://www.dropfans.io/developers/concepts/agencies
- Section: Concepts
- OpenAPI: https://www.dropfans.io/developers/openapi.json

One key can act for many accounts by naming the creator in the path, `/creators/{creatorId}/…`:

- **An agency’s own key** acts for every creator who accepted the agency and every AI persona it runs.
- **Your app owner’s own key** acts for every account your app created with [POST /accounts](https://www.dropfans.io/developers/reference/create-account.md) — as long as the account still holds the key we returned for it, bound to your app. Deleting that key (the creator can, in their dashboard) revokes your access.

Put the creator in the path: every creator endpoint (vault, drops, posts, earnings, profile, links, payout reads, …) is also served at `/api/external/v1/creators/{creatorId}/<the same path>`. Without it, the key acts for its own account, exactly as before. The agency endpoints, sign-up, webhooks and the CRM dashboard act as the agency or app itself and refuse a creator (400 `creator_scope_not_allowed`).

## 1. Get the right key

The agency signs in to the Dropfans dashboard **as itself** (not switched into one of its creators), opens [Vault → API Connect](https://www.dropfans.io/dashboard/vault?apiConnect=1) and generates a key for your app (or a Personal key for its own scripts). That is the agency’s own key. A key the agency generates while switched into a creator is that creator’s key: it stays bound to that one account.

For a CRM, use your app owner’s own key — the same one that calls [POST /accounts](https://www.dropfans.io/developers/reference/create-account.md). Keys an agency minted for its creators never act for anyone else.

## 2. Get the account ids

[GET /api/external/v1/creators](https://www.dropfans.io/developers/reference/list-creators.md) lists every account your key can act for, with its `relationship` (`managed`, `ai_persona` or `onboarded`), your `permissions` on it, `active` (whether creator-scoped calls work for it right now) and its `creatorPath`. Store the ids — they never change. New personas come from [POST /agency/personas](https://www.dropfans.io/developers/reference/create-persona.md), new creators join through [an invite](https://www.dropfans.io/developers/reference/create-agency-invite.md), new CRM accounts from [POST /accounts](https://www.dropfans.io/developers/reference/create-account.md).

## 3. Call the creator path

```bash
# Who am I acting as?
curl "https://www.dropfans.io/api/external/v1/creators/cmh4v2q8k0003xy9z7w6v5u4t/me" \
  -H "Authorization: Bearer $AGENCY_API_KEY"

# Create a drop on that persona
curl -X POST "https://www.dropfans.io/api/external/v1/creators/cmh4v2q8k0003xy9z7w6v5u4t/drops" \
  -H "Authorization: Bearer $AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Beach set","price":25,"vaultItemIds":["clxv1a2b30001item"]}'
```

The request then behaves exactly as if it was sent with that account’s own key: the drop belongs to the persona, the sale is booked on the persona, the links are the persona’s. Every response carries an `X-Dropfans-Account` header with the id of the account it acted on — assert it if you juggle many accounts. [GET /me](https://www.dropfans.io/developers/reference/get-me.md) returns `key.via`: `agency` (and the agency in `key.managedBy`) or `app`.

Send the account **id** only. Usernames are refused, because a username can change hands. Access is checked on every request — there is no session to set up or tear down — and a creator that cannot be honoured is always an error, never a silent fallback to your own account.

### The X-Dropfans-Account header (deprecated)

Sending `X-Dropfans-Account: <account id>` on the plain path does the same and keeps working. Responses to such calls carry `Deprecation: true` and a `Link: <…/v1/creators/{id}/…>; rel="successor-version"` header pointing at the path form. Sending both the path and a header that names another account is a 400 `account_mismatch`.

## Permissions

An agency needs the matching permission on the account, the same switches as in the dashboard (AI personas have all of them):

| Permission | Endpoints |
| --- | --- |
| `canManageVault` | vault: list, upload, folders, tags, video uploads |
| `canManageDrops` | drops, orders, posts |
| `canViewStats` | earnings, tips, balance, reading the subscription tier, payouts (read only) |
| `canEditProfile` | profile and timezone changes, subscription tier, Telegram notifications |
| none | GET /me, GET /timezone, GET /profile, GET /links |

Your app owner’s key has every permission except co-performers on the accounts your app onboarded. Each reference page names the permission it needs. Requesting or cancelling a payout and changing payout methods are never possible for another account: those endpoints refuse a creator (`creator_scope_not_allowed` / `account_header_not_allowed`) and keys an agency minted for a managed account (`agency_key_not_allowed`), whatever the permissions.

## Errors

| Status | `code` | When |
| --- | --- | --- |
| 400 | `account_mismatch` | The path names one creator and `X-Dropfans-Account` another. |
| 400 | `creator_scope_not_allowed` | A `/v1/creators/{creatorId}/…` call to an endpoint that acts as the key’s own account, agency or app. |
| 400 | `invalid_account_header` | The header is not an account id (e.g. a username). |
| 403 | `account_not_managed` | The key cannot act for that account: no accepted management, not an account your app onboarded (or it no longer holds your app’s key), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. |
| 403 | `permission_denied` | The agency lacks the permission named in the `permission` field on that account. |
| 400 | `account_header_not_allowed` | The header was sent to an endpoint that acts as the key’s own account, agency or app. |
| 403 | `agency_key_required` | An agency endpoint was called with a key that is not a verified agency’s own key. |

## Webhooks

An app that holds an agency’s own key also receives [webhook events](https://www.dropfans.io/developers/webhooks/overview.md) for every creator and persona that agency manages (accepted management). Those payloads carry `data.agencyId` next to `data.accountId`, so you can route them. An app is never sent the same event twice, even if it also holds that creator’s own key.

## Rate limits and money

- Rate limits stay **per key**: one key acting for ten accounts shares one budget. Read the [rate-limit headers](https://www.dropfans.io/developers/concepts/rate-limits.md) and spread polling accordingly.
- Buyers always pay on Dropfans: buy links, tip links and the subscribe sheet open the Dropfans checkout (web or Telegram Mini App), never yours. Use the links from [GET /links](https://www.dropfans.io/developers/reference/get-links.md) for each creator to get each account’s own.
- [GET /balance](https://www.dropfans.io/developers/reference/get-balance.md) can be **negative** for agency-managed accounts (internal settlements can pull a bucket below zero). Render it signed; do not clamp to zero.

Next: [Sell a drop end-to-end](https://www.dropfans.io/developers/guides/sell-a-drop.md) or [Connect a creator to your app](https://www.dropfans.io/developers/get-started/connect-a-creator.md).

---

Previous: [Money & units](https://www.dropfans.io/developers/concepts/money-and-units.md) · Next: [Sell a drop end-to-end](https://www.dropfans.io/developers/guides/sell-a-drop.md) · All pages: [llms.txt](https://www.dropfans.io/developers/llms.txt)
