{"openapi":"3.1.0","info":{"title":"Dropfans API","version":"1.3.0","summary":"Sell drops, manage a creator’s vault, post to the For You feed and read earnings — one dpfn_ API key per creator, or one agency key for every creator it manages.","description":"The Dropfans API lets software act on behalf of a creator: list and upload vault media,\npackage it into sellable drops, publish to the For You feed, read earnings and balance,\nand fetch canonical share links.\n\n**Auth**: every request carries `Authorization: Bearer dpfn_...`. By default a key acts for\nthe one account it belongs to. Creators mint keys in their dashboard (Vault → API Connect)\nand choose which app the key is for; to appear in that picker,\napply at https://www.dropfans.io/developers/apply.\n\n**Versioning**: the paths below are under `/api/external/v1/`. The unversioned\n`/api/external/...` paths are permanent aliases of the same endpoints.\n\n**API categories**: every operation names its category in `x-dropfans-category`. Each app\nhas a switch per category; a call to one that is off returns 403 `api_category_disabled`.\nPayouts and onboarding start off. See /developers/concepts/api-categories.\n\n**Acting for a creator**: a verified agency’s own key (for a creator or AI persona it manages)\nand an app owner’s own key (for an account its app onboarded) call any creator endpoint under\n`/api/external/v1/creators/{creatorId}/…` — the `…ForCreator` operations (ids from GET\n/api/external/v1/creators). The request then behaves exactly as if sent with that account’s own\nkey, subject to the permissions held on it; every response echoes the account acted on in `X-Dropfans-Account`.\nThe `X-Dropfans-Account` request header still works but is deprecated. The /agency/*, /accounts,\n/webhooks and /crm/* endpoints act as the agency or app itself and refuse a creator.\n\n**Rate limits**: fixed per-minute and per-day windows per tier — Personal keys\n60/min and 5,000/day, approved apps 300/min and 50,000/day,\nDropfans-operated integrations exempt. Read the live values from the response headers\n(`X-RateLimit-Tier`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`,\nplus the `-Day` variants) rather than hardcoding; a 429 carries `Retry-After` and the body\n`{\"error\":\"Rate limit exceeded\",\"code\":\"rate_limited\"}`.\n\n**Moderation parity**: everything created through the API goes through exactly the same\nmoderation as the dashboard — captions run the prohibited-word filter and media stays\nPENDING until it clears the NSFW pipeline. The API cannot bypass review.\n\nHuman docs: https://www.dropfans.io/developers · LLM edition: https://www.dropfans.io/developers/llms.txt","contact":{"email":"support@dropfans.io"},"termsOfService":"https://www.dropfans.io/developers/api-terms"},"servers":[{"url":"https://www.dropfans.io"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"account","description":"Account — Who the key belongs to, profile, timezone, subscription tier and payout balance."},{"name":"agency","description":"Agencies — Run every creator and AI persona an agency manages with one key: list them, create personas, invite creators, roster revenue."},{"name":"creators","description":"Creators you act for — The roster behind /v1/creators/{creatorId}/…: an agency’s creators and AI personas, and the accounts your app onboarded."},{"name":"vault","description":"Vault — List, upload, organise and tag the creator’s media."},{"name":"drops","description":"Drops — Create sellable drops, attach previews, check sales."},{"name":"posts","description":"Posts — Publish to the For You feed and track moderation."},{"name":"earnings","description":"Earnings — The creator’s dashboard numbers, mirrored."},{"name":"links","description":"Links — Canonical profile, tip, subscribe and buy links."},{"name":"notifications","description":"Telegram (advanced) — Where the creator’s sale notifications go. Rewrites their settings — use with care."},{"name":"crm","description":"CRM integrations — Creator sign-up from your page, your app’s webhook endpoint, and your integration dashboard’s numbers (stats, sales, connected accounts). Keys held by the app owner only."},{"name":"payouts","description":"Payouts — Payout balance and eligibility, payout history, payout methods (Paxum, the MassPay wallet), and payout requests."}],"externalDocs":{"description":"Full documentation","url":"https://www.dropfans.io/developers"},"paths":{"/api/external/v1/me":{"get":{"operationId":"getMe","tags":["account"],"summary":"Which creator this API key belongs to","description":"Returns the creator account behind the key, plus metadata about the key itself.\n\nCall it once at startup to confirm the key works and to learn the creator's `id`, `username` and `accountType` — posting to the For You feed needs CREATOR or AGENCY, and every link surface needs a `username`. The `key` block tells you which integration the key was minted for and its rate-limit tier, matching the `X-RateLimit-Tier` header.\n\nCalled for a creator (`/v1/creators/{creatorId}/me`, or the deprecated `X-Dropfans-Account`), it describes that account instead: `key.via` is `agency` (with `key.viaAgency: true` and the agency in `key.managedBy`) or `app` for an account your app onboarded — a cheap way to check you point where you think. `isAgency: true` on the agency's own key means it can use the [agency endpoints](/developers/concepts/agencies).","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The key’s creator account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"},"example":{"id":"clx2f8a1b0001qw3k","username":"valeria","name":"Valeria","image":"https://cdn.dropfans.io/valeria/profile.jpg","accountType":"CREATOR","sellerStatus":"VERIFIED_CREATOR","isAgency":false,"kycStatus":"approved","key":{"name":"KVIQA","app":{"slug":"kviqa","name":"KVIQA"},"tier":"app","managedBy":null,"viaAgency":false}}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/me\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/me`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/me\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-me","x-dropfans-category":"account","x-dropfans-agency-permission":null}},"/api/external/v1/profile":{"get":{"operationId":"getProfile","tags":["account"],"summary":"Read the creator’s public profile","description":"The creator's public profile: username, display name, bio, visibility, contact handles and images.\n\nImage URLs are signed and valid for 24 hours — fetch them when you need them, don't store them. Change any of it with [PATCH /api/external/v1/profile](/developers/reference/update-profile).","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The profile.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","username":"luna_ai","displayName":"Luna","bio":"Your favourite AI muse ✨","profileVisible":true,"location":null,"websiteUrl":null,"twitterHandle":null,"instagramHandle":"luna.ai","tiktokHandle":null,"snapchatHandle":null,"threadsHandle":null,"youtubeHandle":null,"telegramHandle":"luna_ai","whatsappNumber":null,"imessageHandle":null,"primaryContactPlatform":"telegram","avatarUrl":"https://cdn.dropfans.io/luna_ai/profile.jpg?token=…","bannerUrl":null,"avatarModerationStatus":"APPROVED","bannerModerationStatus":null}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"The account no longer exists.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Account not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/profile\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/profile`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/profile\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-profile","x-dropfans-category":"account","x-dropfans-agency-permission":null},"patch":{"operationId":"updateProfile","tags":["account"],"summary":"Update the creator’s public profile","description":"Partial update of the creator's public profile — send only the fields that change; `null` clears a field. Returns the whole profile.\n\nSame rules as the dashboard: every text field runs the prohibited-word filter, usernames must be free (the old one is kept in the account's history), and unknown fields are **refused, not ignored**. `avatarUrl` / `bannerUrl` take a public https image URL: Dropfans downloads, stores and moderates it, so a new image shows once approved (watch `avatarModerationStatus`). This changes what fans see on Dropfans — only call it when the creator asked for it.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","description":"New @handle: 3–30 of lowercase letters, digits, `_` and `-`.","example":"luna_ai","pattern":"^[a-z0-9_-]{3,30}$"},"displayName":{"type":"string","description":"Display name. Cannot be empty or null.","example":"Luna","maxLength":80},"bio":{"type":["string","null"],"description":"Profile bio.","maxLength":2000},"profileVisible":{"type":"boolean","description":"Show or hide the public profile."},"location":{"type":["string","null"],"description":"Free-text location.","maxLength":120},"websiteUrl":{"type":["string","null"],"description":"Website link.","maxLength":300},"twitterHandle":{"type":["string","null"],"description":"X / Twitter handle.","maxLength":100},"instagramHandle":{"type":["string","null"],"description":"Instagram handle.","maxLength":100},"tiktokHandle":{"type":["string","null"],"description":"TikTok handle.","maxLength":100},"snapchatHandle":{"type":["string","null"],"description":"Snapchat handle.","maxLength":100},"threadsHandle":{"type":["string","null"],"description":"Threads handle.","maxLength":100},"youtubeHandle":{"type":["string","null"],"description":"YouTube handle.","maxLength":100},"telegramHandle":{"type":["string","null"],"description":"Telegram handle.","maxLength":100},"whatsappNumber":{"type":["string","null"],"description":"WhatsApp number.","maxLength":40},"imessageHandle":{"type":["string","null"],"description":"iMessage handle.","maxLength":100},"primaryContactPlatform":{"type":["string","null"],"description":"Which contact platform the profile highlights.","maxLength":40},"avatarUrl":{"type":["string","null"],"description":"Public https URL of the new profile image (Dropfans fetches and moderates it). null removes the image.","format":"uri"},"bannerUrl":{"type":["string","null"],"description":"Public https URL of the new banner image. null removes it.","format":"uri"}}},"examples":{"bio":{"summary":"New bio and avatar","value":{"bio":"Your favourite AI muse ✨","avatarUrl":"https://cdn.example.com/luna/avatar.jpg"}}}}}},"responses":{"200":{"description":"The updated profile.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","username":"luna_ai","displayName":"Luna","bio":"Your favourite AI muse ✨","profileVisible":true,"location":null,"websiteUrl":null,"twitterHandle":null,"instagramHandle":"luna.ai","tiktokHandle":null,"snapchatHandle":null,"threadsHandle":null,"youtubeHandle":null,"telegramHandle":"luna_ai","whatsappNumber":null,"imessageHandle":null,"primaryContactPlatform":"telegram","avatarUrl":"https://cdn.dropfans.io/luna_ai/profile.jpg?token=…","bannerUrl":null,"avatarModerationStatus":"APPROVED","bannerModerationStatus":null}}}},"400":{"description":"A field that is not in the list above. Also: Wrong type, too long, an empty displayName, or an image URL that is not https. Also: A text field tripped the word filter. Also: Malformed or reserved username. Also: The image URL did not return an image. Earlier fields in the same call are already saved. Also: The body is not a JSON object. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"Unknown profile field(s): nickname","code":"unknown_field","field":"nickname"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"Profile editing is locked for this account. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Profile editing is restricted for this account.","code":"profile_locked"}}}},"409":{"description":"Another account has that username.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"Username is already taken.","code":"username_taken","field":"username"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PATCH \"https://www.dropfans.io/api/external/v1/profile\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"bio\": \"Your favourite AI muse ✨\",\n  \"avatarUrl\": \"https://cdn.example.com/luna/avatar.jpg\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/profile`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"bio\": \"Your favourite AI muse ✨\",\n    \"avatarUrl\": \"https://cdn.example.com/luna/avatar.jpg\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.patch(\n    \"https://www.dropfans.io/api/external/v1/profile\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"bio\": \"Your favourite AI muse ✨\",\n        \"avatarUrl\": \"https://cdn.example.com/luna/avatar.jpg\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-profile","x-dropfans-category":"account","x-dropfans-agency-permission":"canEditProfile"}},"/api/external/v1/timezone":{"get":{"operationId":"getTimezone","tags":["account"],"summary":"Read the creator’s timezone","description":"Returns the creator's IANA timezone, defaulting to `\"UTC\"` when they never set one.\n\nUse it as the `tz` parameter on [GET /api/external/v1/earnings](/developers/reference/get-earnings) so your day buckets line up with what the creator sees on their own dashboard.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The creator’s timezone.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Timezone"},"example":{"timezone":"Europe/Stockholm"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/timezone\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/timezone`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/timezone\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-timezone","x-dropfans-category":"account","x-dropfans-agency-permission":null},"put":{"operationId":"updateTimezone","tags":["account"],"summary":"Set the creator’s timezone","description":"Sets the creator's timezone — the same setting their dashboard uses for day bucketing.\n\nThe value must be a valid IANA name (anything in `Intl.supportedValuesOf('timeZone')`). This changes what the creator sees on their own Dropfans dashboard too, not just your API reads — only call it when the creator asked for it.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"timezone":{"type":"string","description":"IANA timezone name, e.g. \"Europe/Stockholm\". Abbreviations like \"CET\" are not accepted.","format":"iana-timezone","example":"Europe/Stockholm"}},"required":["timezone"]},"examples":{"stockholm":{"summary":"Set to Stockholm time","value":{"timezone":"Europe/Stockholm"}}}}}},"responses":{"200":{"description":"The saved timezone, echoed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Timezone"},"example":{"timezone":"Europe/Stockholm"}}}},"400":{"description":"Missing, non-string, or not a recognised IANA timezone name. Also: The request body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid timezone"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PUT \"https://www.dropfans.io/api/external/v1/timezone\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"timezone\": \"Europe/Stockholm\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/timezone`, {\n  method: 'PUT',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"timezone\": \"Europe/Stockholm\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.put(\n    \"https://www.dropfans.io/api/external/v1/timezone\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"timezone\": \"Europe/Stockholm\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-timezone","x-dropfans-category":"account","x-dropfans-agency-permission":"canEditProfile"}},"/api/external/v1/subscription":{"get":{"operationId":"getSubscription","tags":["account"],"summary":"Read the creator’s subscription tier","description":"The creator's subscription tier — price, interval, trial and whether it takes new sign-ups — plus the web link that opens the subscribe sheet. `tier` is null when the creator has no subscription set up.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The tier and subscribe link.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"},"example":{"tier":{"priceUsd":9.99,"currency":"USD","interval":"monthly","trialDays":0,"description":"All my sets, first.","pitchMessage":null,"isActive":true},"subscribeUrl":"https://www.dropfans.io/u/luna_ai?subscribe=1"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/subscription\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/subscription`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/subscription\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-subscription","x-dropfans-category":"account","x-dropfans-agency-permission":"canViewStats"},"put":{"operationId":"updateSubscription","tags":["account"],"summary":"Set the creator’s subscription tier","description":"Creates or replaces the creator's subscription tier. This is a full replace: fields you leave out go back to their defaults (`trialDays` 0, no description or pitch, active).\n\nSame rules as the dashboard: `priceUsd` is USD **dollars**, either `0` (free) or between $5 and $750. `isActive: false` pauses new sign-ups. Existing subscribers keep the price they signed up at.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"priceUsd":{"type":"number","description":"USD dollars per interval. 0 = free; otherwise $5–$750. Rounded to cents.","example":9.99,"minimum":0,"maximum":750},"interval":{"type":"string","description":"Billing interval.","enum":["monthly","weekly"],"example":"monthly"},"trialDays":{"type":"integer","description":"Free trial length in days.","default":0,"minimum":0,"maximum":30},"description":{"type":"string","description":"What subscribers get (cut at 500 characters).","maxLength":500},"pitchMessage":{"type":"string","description":"Short pitch shown in the subscribe sheet (cut at 500 characters).","maxLength":500},"isActive":{"type":"boolean","description":"false pauses new sign-ups.","default":true}},"required":["priceUsd","interval"]},"examples":{"monthly":{"summary":"$9.99 a month","value":{"priceUsd":9.99,"interval":"monthly","description":"All my sets, first."}}}}}},"responses":{"200":{"description":"The saved tier.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"tier":{"$ref":"#/components/schemas/SubscriptionTier"}},"required":["tier"]},"example":{"tier":{"priceUsd":9.99,"currency":"USD","interval":"monthly","trialDays":0,"description":"All my sets, first.","pitchMessage":null,"isActive":true}}}}},"400":{"description":"`priceUsd` missing, not a number or negative. Also: Priced above 0 but below $5. Also: Priced above $750. Also: Missing or unknown interval. Also: Bad trial length. Also: `isActive` is not a boolean. Also: The body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"priceUsd must be 0 (free) or at least 5"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PUT \"https://www.dropfans.io/api/external/v1/subscription\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"priceUsd\": 9.99,\n  \"interval\": \"monthly\",\n  \"description\": \"All my sets, first.\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/subscription`, {\n  method: 'PUT',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"priceUsd\": 9.99,\n    \"interval\": \"monthly\",\n    \"description\": \"All my sets, first.\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.put(\n    \"https://www.dropfans.io/api/external/v1/subscription\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"priceUsd\": 9.99,\n        \"interval\": \"monthly\",\n        \"description\": \"All my sets, first.\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-subscription","x-dropfans-category":"account","x-dropfans-agency-permission":"canEditProfile"}},"/api/external/v1/balance":{"get":{"operationId":"getBalance","tags":["account"],"summary":"The account’s payout balance","description":"The account's payout balance buckets in USD dollars: the creator side at the top level, plus `total` and `sides` for everything the account owns.\n\nThe top-level buckets are the creator side (own sales), unchanged since this endpoint launched. `total` is the full payable balance — the same numbers the Payouts page shows and a payout request pays out: creator side + agency side (income from managed creators and AI personas) + referral commission + partner shares. `sides` breaks `total` down.\n\n> [!WARNING] Dollars, not cents\n> This endpoint returns USD **dollars**. The earnings, check-status and payouts endpoints return **cents**. Do not mix the units. For cents, eligibility and payout status use [GET /payouts/summary](/developers/reference/get-payout-summary).\n\n> [!NOTE] Added on 2026-10-30\n> `total` and `sides` are new. The top-level fields did not change, so existing integrations keep working; read `total` for an agency, referral or partner account.\n\nBucket semantics: `pending` is revenue still inside the chargeback hold window; `available` has cleared the hold and is what a payout request pays out; `processing` is inside a payout currently being executed; `paidOut` is the lifetime total already paid. `available` can be negative (a refund of money already paid out is netted against future earnings).","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Balance buckets in USD dollars.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"},"example":{"currency":"USD","pending":120.5,"available":300.1,"processing":0,"paidOut":1755,"total":{"pending":120.5,"available":342.1,"processing":0,"paidOut":1875},"sides":{"creator":{"pending":120.5,"available":300.1,"processing":0,"paidOut":1755},"agency":{"pending":0,"available":42,"processing":0,"paidOut":120},"affiliate":{"pending":0,"available":0,"processing":0,"paidOut":0},"share":{"pending":0,"available":0,"processing":0,"paidOut":0}}}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Balance computation failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch balance"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/balance\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/balance`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/balance\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-balance","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats"}},"/api/external/v1/agency/creators":{"get":{"operationId":"listAgencyCreators","tags":["agency"],"summary":"List the creators and personas you manage","description":"Every creator and AI persona the agency manages, with the account `id` to send as `X-Dropfans-Account` and the permissions the agency holds on each.\n\nCall it with the agency's own key. Then act for any account by sending the same key plus `X-Dropfans-Account: <id>` to the regular endpoints — see [Agencies: one key for every creator](/developers/concepts/agencies). `active` tells you whether the header works for that account right now.\n\nBy default only ACCEPTED relationships come back. `?status=all` adds ended creators and retired personas, e.g. to find a persona to [reactivate](/developers/reference/reactivate-persona).","parameters":[{"name":"status","in":"query","required":false,"description":"Pass `all` to include ended and retired accounts. Omit for active (ACCEPTED) only.","schema":{"type":"string","enum":["all"]}}],"responses":{"200":{"description":"The agency and its managed accounts.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgencyCreatorList"},"example":{"agency":{"id":"cmh1agc0q0001ab7k2p9q4r8s","username":"starlight_agency","name":"Starlight Agency"},"creators":[{"id":"cmh4v2q8k0003xy9z7w6v5u4t","managedCreatorId":"cmh4v2q8k0004mc1relation","username":"luna_ai","name":"Luna","image":"https://cdn.dropfans.io/luna_ai/profile.jpg","kind":"ai_persona","status":"ACCEPTED","active":true,"kycCoveredByAgency":true,"sellerStatus":"VERIFIED_CREATOR","permissions":{"canEditProfile":true,"canManageDrops":true,"canManageVault":true,"canViewStats":true,"canManageCoPerformers":false},"profileUrl":"https://www.dropfans.io/u/luna_ai","since":"2026-10-01T09:00:00.000Z"},{"id":"cmh3k9p2a0002cd5e6f7g8h9j","managedCreatorId":"cmh3k9p2a0005mc2relation","username":"valeria","name":"Valeria","image":null,"kind":"creator","status":"ACCEPTED","active":true,"kycCoveredByAgency":false,"sellerStatus":"VERIFIED_CREATOR","permissions":{"canEditProfile":false,"canManageDrops":true,"canManageVault":true,"canViewStats":true,"canManageCoPerformers":false},"profileUrl":"https://www.dropfans.io/u/valeria","since":"2026-09-12T14:30:00.000Z"}]}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/agency/creators\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/agency/creators`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/agency/creators\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-agency-creators","x-dropfans-category":"agency"}},"/api/external/v1/agency/personas":{"post":{"operationId":"createPersona","tags":["agency"],"summary":"Create an AI persona","description":"Creates an AI persona run by the agency and returns its account `id` — use it in `X-Dropfans-Account` straight away to fill its vault, create drops and post.\n\nNeeds an agency in Agency Mode (an AI operator) whose ID check is approved. The persona is covered by the agency's ID check — it has no ID check of its own — and is marked as AI-generated on Dropfans. At most 8 personas can be active at once.\n\nBesides `username` and `displayName` you can send any [profile field](/developers/reference/update-profile) in the same call. The persona is created either way: a refused profile field comes back as `profileError` instead of failing the call.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","description":"3–30 of lowercase letters, digits, `_` and `-`. Must be free and not reserved.","example":"luna_ai","pattern":"^[a-z0-9_-]{3,30}$"},"displayName":{"type":"string","description":"Display name. Defaults to the username.","example":"Luna","maxLength":80},"bio":{"type":"string","description":"Profile bio. Every other PATCH /api/external/v1/profile field (avatarUrl, bannerUrl, social handles, profileVisible, …) is accepted here too.","maxLength":2000}},"required":["username"]},"examples":{"persona":{"summary":"A persona with a bio and avatar","value":{"username":"luna_ai","displayName":"Luna","bio":"Your favourite AI muse ✨","avatarUrl":"https://cdn.example.com/luna/avatar.jpg"}}}}}},"responses":{"201":{"description":"Created.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonaCreated"},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","managedCreatorId":"cmh4v2q8k0004mc1relation","username":"luna_ai","name":"Luna","kind":"ai_persona","profileUrl":"https://www.dropfans.io/u/luna_ai"}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Missing or malformed `username`. Also: Reserved username. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: The agency is not in Agency Mode (AI operator). Also: The agency’s ID check is not approved. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"409":{"description":"8 personas are already active. Also: Another account has that username.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"You've reached the maximum of 8 AI personas. Retire one before adding another.","code":"persona_limit"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Unexpected failure — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to create persona."}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/agency/personas\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"username\": \"luna_ai\",\n  \"displayName\": \"Luna\",\n  \"bio\": \"Your favourite AI muse ✨\",\n  \"avatarUrl\": \"https://cdn.example.com/luna/avatar.jpg\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/agency/personas`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"username\": \"luna_ai\",\n    \"displayName\": \"Luna\",\n    \"bio\": \"Your favourite AI muse ✨\",\n    \"avatarUrl\": \"https://cdn.example.com/luna/avatar.jpg\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/agency/personas\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"username\": \"luna_ai\",\n        \"displayName\": \"Luna\",\n        \"bio\": \"Your favourite AI muse ✨\",\n        \"avatarUrl\": \"https://cdn.example.com/luna/avatar.jpg\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-persona","x-dropfans-category":"agency"}},"/api/external/v1/agency/personas/{id}":{"patch":{"operationId":"renamePersona","tags":["agency"],"summary":"Rename an AI persona","description":"Changes an active persona's `username` (same rules as a creator's own username change; the old handle is kept in its history).\n\nEverything else on the persona's profile goes through [PATCH /api/external/v1/profile](/developers/reference/update-profile) with `X-Dropfans-Account`.","parameters":[{"name":"id","in":"path","required":true,"description":"The persona’s account id (`id` from GET /api/external/v1/agency/creators).","schema":{"type":"string"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","description":"The new username.","example":"luna_official","pattern":"^[a-z0-9_-]{3,30}$"}},"required":["username"]},"examples":{"rename":{"summary":"Rename","value":{"username":"luna_official"}}}}}},"responses":{"200":{"description":"The saved username.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The persona’s account id."},"username":{"type":"string","description":"The username now in effect."}},"required":["id","username"]},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","username":"luna_official"}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Missing, malformed or reserved username. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"404":{"description":"Not an active persona of this agency.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Persona not found."}}}},"409":{"description":"Another account has that username.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Username is already taken.","code":"username_taken"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PATCH \"https://www.dropfans.io/api/external/v1/agency/personas/$ACCOUNT_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"username\": \"luna_official\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const accountId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/agency/personas/${accountId}`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"username\": \"luna_official\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\naccount_id = \"…\"  # from an earlier response\n\nres = requests.patch(\n    f\"https://www.dropfans.io/api/external/v1/agency/personas/{account_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"username\": \"luna_official\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/rename-persona","x-dropfans-category":"agency"},"delete":{"operationId":"retirePersona","tags":["agency"],"summary":"Retire an AI persona","description":"Retires a persona: its profile goes offline, the relationship becomes DEPARTED and any keys the agency minted for it stop working.\n\nNothing is deleted — sales history and subscribers are kept — and it can be brought back with [reactivate](/developers/reference/reactivate-persona). Retiring frees a slot under the 8-persona cap.","parameters":[{"name":"id","in":"path","required":true,"description":"The persona’s account id (`id` from GET /api/external/v1/agency/creators).","schema":{"type":"string"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"Retired.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The persona’s account id."},"status":{"type":"string","description":"Always \"retired\".","enum":["retired"]}},"required":["id","status"]},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","status":"retired"}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"404":{"description":"No AI persona with this id under this agency.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Persona not found."}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Unexpected failure — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to retire persona."}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/agency/personas/$ACCOUNT_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const accountId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/agency/personas/${accountId}`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\naccount_id = \"…\"  # from an earlier response\n\nres = requests.delete(\n    f\"https://www.dropfans.io/api/external/v1/agency/personas/{account_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/retire-persona","x-dropfans-category":"agency"}},"/api/external/v1/agency/personas/{id}/reactivate":{"post":{"operationId":"reactivatePersona","tags":["agency"],"summary":"Reactivate a retired AI persona","description":"Brings a retired persona back online under the agency, with the same rules as the dashboard: not while another agency runs it, not over the 8-persona cap, and never for an account Dropfans suspended.\n\nFind retired personas with [GET /api/external/v1/agency/creators?status=all](/developers/reference/list-agency-creators).","parameters":[{"name":"id","in":"path","required":true,"description":"The persona’s account id (`id` from GET /api/external/v1/agency/creators).","schema":{"type":"string"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"Active again.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The persona’s account id."},"status":{"type":"string","description":"Always \"active\".","enum":["active"]}},"required":["id","status"]},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","status":"active"}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"404":{"description":"No AI persona with this id was ever run by this agency.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Persona not found."}}}},"409":{"description":"Nothing to do. Also: 8 personas are already active. Also: Another agency runs the persona now. Also: The account was deleted or banned. Also: Suspended by Dropfans, not retired by the agency.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"This persona is already active."}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Unexpected failure — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Could not reactivate the persona."}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/agency/personas/$ACCOUNT_ID/reactivate\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const accountId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/agency/personas/${accountId}/reactivate`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\naccount_id = \"…\"  # from an earlier response\n\nres = requests.post(\n    f\"https://www.dropfans.io/api/external/v1/agency/personas/{account_id}/reactivate\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/reactivate-persona","x-dropfans-category":"agency"}},"/api/external/v1/agency/invites":{"post":{"operationId":"createAgencyInvite","tags":["agency"],"summary":"Invite a creator to your agency","description":"Creates a join link that invites a real creator to be managed by the agency. The link is valid for 72 hours; with `email`, Dropfans also emails it.\n\nThe creator accepts while signed in to their own Dropfans account and agrees to the agency's permissions there — an agency can never attach a creator without their consent. Once accepted, the creator shows up in [GET /api/external/v1/agency/creators](/developers/reference/list-agency-creators).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Optional: Dropfans emails the link to this address.","format":"email","example":"valeria@example.com"},"message":{"type":"string","description":"Optional personal note shown with the invite (longer text is cut at 500 characters).","example":"Hi Valeria — excited to work with you!","maxLength":500}}},"examples":{"email":{"summary":"Email an invite","value":{"email":"valeria@example.com","message":"Hi Valeria — excited to work with you!"}}}}}},"responses":{"201":{"description":"The invite.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgencyInvite"},"example":{"inviteId":"cmh5inv0001ab7k2p9q4r8s","inviteLink":"https://www.dropfans.io/agency/join/3f9c…","expiresAt":"2026-10-29T12:00:00.000Z","emailSent":true}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Malformed `email`. Also: The body is not valid JSON. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/agency/invites\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"email\": \"valeria@example.com\",\n  \"message\": \"Hi Valeria — excited to work with you!\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/agency/invites`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"email\": \"valeria@example.com\",\n    \"message\": \"Hi Valeria — excited to work with you!\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/agency/invites\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"email\": \"valeria@example.com\",\n        \"message\": \"Hi Valeria — excited to work with you!\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-agency-invite","x-dropfans-category":"agency"},"get":{"operationId":"listAgencyInvites","tags":["agency"],"summary":"List your agency’s invites","description":"The agency’s creator invites, newest first, each with its status: `pending`, `accepted`, `expired` or `revoked`.\n\nThe join link itself is not returned again — only a hash of it is stored. Revoke a pending invite with [DELETE /agency/invites/{id}](/developers/reference/revoke-agency-invite).","parameters":[{"name":"status","in":"query","required":false,"description":"Only invites with this status.","schema":{"type":"string","enum":["pending","accepted","expired","revoked"]}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"One page of invites.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AgencyInviteRow"},"description":"The invites."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["data"]},"example":{"data":[{"id":"cmh5inv0001ab7k2p9q4r8s","status":"pending","email":"valeria@example.com","message":null,"createdAt":"2026-10-26T12:00:00.000Z","expiresAt":"2026-10-29T12:00:00.000Z","acceptedAt":null,"acceptedBy":null}],"nextCursor":null}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Bad `status` (also `invalid_limit`). Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/agency/invites\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/agency/invites`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/agency/invites\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-agency-invites","x-dropfans-category":"agency"}},"/api/external/v1/agency/invites/{id}":{"delete":{"operationId":"revokeAgencyInvite","tags":["agency"],"summary":"Revoke an invite","description":"Revokes a pending invite: its join link stops working at once. Returns the invite with `status: revoked`.\n\nAn accepted invite cannot be revoked — end the management with [DELETE /agency/creators/{id}](/developers/reference/end-management) instead.","parameters":[{"name":"id","in":"path","required":true,"description":"The invite id (`inviteId` / `id`).","schema":{"type":"string"},"example":"cmh5inv0001ab7k2p9q4r8s"}],"responses":{"200":{"description":"The revoked invite.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgencyInviteRow"}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"404":{"description":"No such invite for this agency (another agency’s invite gets the same answer).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Invite not found","code":"invite_not_found"}}}},"409":{"description":"A creator already used the link (`invite_already_revoked` when it was revoked before).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This invite was already accepted.","code":"invite_already_used"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/agency/invites/$ACCOUNT_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const accountId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/agency/invites/${accountId}`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\naccount_id = \"…\"  # from an earlier response\n\nres = requests.delete(\n    f\"https://www.dropfans.io/api/external/v1/agency/invites/{account_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/revoke-agency-invite","x-dropfans-category":"agency"}},"/api/external/v1/agency/creators/{id}":{"delete":{"operationId":"endManagement","tags":["agency"],"summary":"Stop managing a creator","description":"Ends the agency's management of a creator or persona — the same as \"Leave agreement\" in the dashboard.\n\nSplit agreements end, keys the agency minted for the account stop working, `X-Dropfans-Account` stops working for it, and an AI persona is retired. Requires `{ \"confirm\": true }` in the body so a retry loop or a stray call can never drop a creator. A real creator has to accept a new invite to come back.","parameters":[{"name":"id","in":"path","required":true,"description":"The account’s account id (`id` from GET /api/external/v1/agency/creators).","schema":{"type":"string"},"example":"cmh3k9p2a0002cd5e6f7g8h9j"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be `true`.","example":true},"reason":{"type":"string","description":"Optional reason, stored with the relationship and shown to the creator.","example":"Contract ended","maxLength":300}},"required":["confirm"]},"examples":{"end":{"summary":"End management","value":{"confirm":true,"reason":"Contract ended"}}}}}},"responses":{"200":{"description":"Ended.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The account id."},"status":{"type":"string","description":"Always \"ended\".","enum":["ended"]}},"required":["id","status"]},"example":{"id":"cmh3k9p2a0002cd5e6f7g8h9j","status":"ended"}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: `confirm` is missing or not `true`. Also: The body is not valid JSON. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"404":{"description":"No ACCEPTED relationship with this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Not managed by this agency.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/agency/creators/$ACCOUNT_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"confirm\": true,\n  \"reason\": \"Contract ended\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const accountId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/agency/creators/${accountId}`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"confirm\": true,\n    \"reason\": \"Contract ended\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\naccount_id = \"…\"  # from an earlier response\n\nres = requests.delete(\n    f\"https://www.dropfans.io/api/external/v1/agency/creators/{account_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"confirm\": True,\n        \"reason\": \"Contract ended\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/end-management","x-dropfans-category":"agency"}},"/api/external/v1/agency/stats":{"get":{"operationId":"getAgencyStats","tags":["agency"],"summary":"Revenue across your roster","description":"Revenue for the agency's own account plus every managed account it may see stats for (`canViewStats`), with a per-account breakdown — the same figures as the dashboard's \"All creators\" view.\n\nAmounts are USD **dollars** (rounded to cents), excluding refunds and chargebacks: `gross` is buyer-paid minus VAT, `net` is the sellers' earnings after the platform fee. Days are UTC; the default range is the last 30 days. For one account's day-by-day chart and transactions, call [GET /api/external/v1/earnings](/developers/reference/get-earnings) with `X-Dropfans-Account`.","parameters":[{"name":"startDate","in":"query","required":false,"description":"First UTC day (YYYY-MM-DD). Defaults to 29 days before today, so the default range is the last 30 days.","schema":{"type":"string","format":"date"},"example":"2026-10-01"},{"name":"endDate","in":"query","required":false,"description":"Last UTC day (YYYY-MM-DD), inclusive. Defaults to today.","schema":{"type":"string","format":"date"},"example":"2026-10-26"}],"responses":{"200":{"description":"Totals and per-account figures.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgencyStats"},"example":{"startDate":"2026-10-01","endDate":"2026-10-26","currency":"USD","total":{"gross":1240.5,"net":992.4,"sales":31,"tips":12,"subscriptionPayments":9},"accounts":[{"id":"cmh1agc0q0001ab7k2p9q4r8s","username":"starlight_agency","name":"Starlight Agency","kind":"agency","gross":0,"net":0,"sales":0,"tips":0,"subscriptionPayments":0},{"id":"cmh4v2q8k0003xy9z7w6v5u4t","username":"luna_ai","name":"Luna","kind":"creator","gross":820,"net":656,"sales":22,"tips":8,"subscriptionPayments":6},{"id":"cmh3k9p2a0002cd5e6f7g8h9j","username":"valeria","name":"Valeria","kind":"creator","gross":420.5,"net":336.4,"sales":9,"tips":4,"subscriptionPayments":3}]}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Malformed dates, or start after end. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/agency/stats?startDate=2026-10-01&endDate=2026-10-26\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/agency/stats?startDate=2026-10-01&endDate=2026-10-26`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/agency/stats\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"startDate\": \"2026-10-01\", \"endDate\": \"2026-10-26\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-agency-stats","x-dropfans-category":"agency"}},"/api/external/v1/agency/earnings":{"get":{"operationId":"listAgencyEarnings","tags":["agency"],"summary":"Daily earnings per creator","description":"One row per managed creator per day with revenue, across every account you may see stats for (`canViewStats`), in integer cents. Paged with a cursor.\n\nRows come ordered by `date`, then `creatorId`; days without revenue have no row. The figures match [GET /api/external/v1/earnings/summary](/developers/reference/get-earnings-summary) for that creator: refunds and chargebacks are left out, and days are whole local days in `timezone`. The agency’s own sales are not included — read those with the summary, without `X-Dropfans-Account`.\n\nKeep `startDate`, `endDate` and `timezone` the same while you follow `nextCursor`.","parameters":[{"name":"startDate","in":"query","required":false,"description":"First local day (YYYY-MM-DD). Defaults to 29 days before `endDate`. At most 366 days per window.","schema":{"type":"string","format":"date"},"example":"2026-10-01"},{"name":"endDate","in":"query","required":false,"description":"Last local day (YYYY-MM-DD), inclusive. Defaults to today in `timezone`.","schema":{"type":"string","format":"date"},"example":"2026-10-31"},{"name":"timezone","in":"query","required":false,"description":"IANA timezone for the days. `tz` is accepted too; an unknown zone is a 400.","schema":{"type":"string","default":"UTC","format":"iana-timezone"},"example":"Europe/Stockholm"},{"name":"limit","in":"query","required":false,"description":"Rows per page.","schema":{"type":"integer","default":100,"minimum":1,"maximum":500}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of rows. All money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"startDate":{"type":"string","description":"The window’s first day.","format":"date"},"endDate":{"type":"string","description":"The window’s last day (inclusive).","format":"date"},"timezone":{"type":"string","description":"The timezone used."},"currency":{"type":"string","description":"Always USD."},"data":{"type":"array","items":{"type":"object","properties":{"creatorId":{"type":"string","description":"The account id (as in GET /api/external/v1/agency/creators)."},"date":{"type":"string","description":"The local day.","format":"date"},"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Transactions that day."}},"required":["creatorId","date","grossCents","netCents","count"],"description":"One creator’s revenue on one day."},"description":"Rows, by date then creatorId."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["startDate","endDate","timezone","currency","data"]},"example":{"startDate":"2026-10-01","endDate":"2026-10-31","timezone":"Europe/Stockholm","currency":"USD","data":[{"creatorId":"cmh4v2q8k0003xy9z7w6v5u4t","date":"2026-10-01","grossCents":8200,"netCents":6560,"count":3},{"creatorId":"cmh3k9p2a0002cd5e6f7g8h9j","date":"2026-10-01","grossCents":4050,"netCents":3240,"count":2}],"nextCursor":"MjAyNi0xMC0wMXxjbWg0djJxOGswMDAzeHk5ejd3NnY1dTR0"}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Agency endpoints always act as the agency. Also: Unknown `timezone`. Also: Malformed or impossible date. Also: `startDate` is after `endDate`. Also: The window is longer than 366 days. Also: Bad `limit`. Also: The cursor was not one we returned. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Agency endpoints act as the agency itself — send them without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key is not a verified agency’s own key — a creator’s key, or a key an agency minted for one of its creators. Also: Your app has the Agency roster [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own API key.","code":"agency_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/agency/earnings?startDate=2026-10-01&endDate=2026-10-31&timezone=Europe%2FStockholm\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/agency/earnings?startDate=2026-10-01&endDate=2026-10-31&timezone=Europe%2FStockholm`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/agency/earnings\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"startDate\": \"2026-10-01\", \"endDate\": \"2026-10-31\", \"timezone\": \"Europe/Stockholm\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-agency-earnings","x-dropfans-category":"agency"}},"/api/external/v1/creators":{"get":{"operationId":"listCreators","tags":["creators"],"summary":"List the creators you can act for","description":"Every account your key can act for with /api/external/v1/creators/{creatorId}/…: the creators and AI personas your agency manages, and the accounts your app onboarded.\n\nAn agency’s own key sees its accepted creators (`managed`) and its personas (`ai_persona`). Your app owner’s own key sees the accounts your app created with [POST /accounts](/developers/reference/create-account) (`onboarded`). A key that is both sees both; an account on both lists shows once, as the agency relationship.\n\n`active: false` means a creator-scoped call would be refused right now (403 `account_not_managed`). For an `onboarded` account that happens when it is restricted, or when it no longer holds a key bound to your app — the creator revoked your access by deleting it.","parameters":[{"name":"relationship","in":"query","required":false,"description":"Only this relationship.","schema":{"type":"string","enum":["managed","ai_persona","onboarded"]}},{"name":"active","in":"query","required":false,"description":"Only accounts that are (`true`) or are not (`false`) usable right now.","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"One page, sorted by id.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RosterCreator"},"description":"The accounts."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["data"]},"example":{"data":[{"id":"cmh4v2q8k0003xy9z7w6v5u4t","username":"valeria","name":"Valeria","image":null,"relationship":"ai_persona","active":true,"permissions":{"canEditProfile":true,"canManageDrops":true,"canManageVault":true,"canViewStats":true,"canManageCoPerformers":true},"creatorPath":"/api/external/v1/creators/cmh4v2q8k0003xy9z7w6v5u4t","profileUrl":"https://www.dropfans.io/u/valeria","since":"2026-10-20T09:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"The request carried `X-Dropfans-Account`. Also: Bad `limit` (also `invalid_relationship`, `invalid_active`).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint only acts as the key’s own account — send it without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"Neither a verified agency’s own key nor the key of your app’s owner — e.g. a creator’s key, or a key an agency minted for one of its creators.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own key or your app owner's own key.","code":"roster_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/creators\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/creators`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/creators\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-creators","x-dropfans-category":"account"}},"/api/external/v1/creators/{id}":{"get":{"operationId":"getCreator","tags":["creators"],"summary":"Get one creator you can act for","description":"One account from [GET /creators](/developers/reference/list-creators): its relationship to you, your permissions on it and whether creator-scoped calls work for it right now.","parameters":[{"name":"id","in":"path","required":true,"description":"The account id.","schema":{"type":"string"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RosterCreator"},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","username":"valeria","name":"Valeria","image":null,"relationship":"ai_persona","active":true,"permissions":{"canEditProfile":true,"canManageDrops":true,"canManageVault":true,"canViewStats":true,"canManageCoPerformers":true},"creatorPath":"/api/external/v1/creators/cmh4v2q8k0003xy9z7w6v5u4t","profileUrl":"https://www.dropfans.io/u/valeria","since":"2026-10-20T09:00:00.000Z"}}}},"400":{"description":"The request carried `X-Dropfans-Account`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint only acts as the key’s own account — send it without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"Neither a verified agency’s own key nor the key of your app’s owner — e.g. a creator’s key, or a key an agency minted for one of its creators.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a verified agency's own key or your app owner's own key.","code":"roster_key_required"}}}},"404":{"description":"Not on your roster — the same answer for an id that does not exist.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Creator not found","code":"creator_not_found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/creators/$ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const id = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/creators/${id}`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nid = \"…\"  # from an earlier response\n\nres = requests.get(\n    f\"https://www.dropfans.io/api/external/v1/creators/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-creator","x-dropfans-category":"account"}},"/api/external/v1/vault":{"get":{"operationId":"listVault","tags":["vault"],"summary":"List your vault items — the source of media for posts","description":"Returns APPROVED items by default. Use an item's `id` as `vaultItemId` when creating a MEDIA post. Pass includePending=true to also see items still in moderation (their media is stripped).\n\nEvery drop and every MEDIA post is built from vault item ids, so this list is the starting point of almost every flow. Items are newest first. The response also carries all of the creator's folders — but note the folders' `itemCount` here respects the moderation filter, while [GET /api/external/v1/vault/folders](/developers/reference/list-folders) counts every non-hidden item, so the two can disagree for the same folder.","parameters":[{"name":"page","in":"query","required":false,"description":"Page number, 1-based.","schema":{"type":"integer","default":1},"example":1},{"name":"limit","in":"query","required":false,"description":"Items per page. Hard cap 50 — larger values are clamped, not rejected.","schema":{"type":"integer","default":50,"maximum":50}},{"name":"folderId","in":"query","required":false,"description":"`\"all\"` (default), `\"unfiled\"`, or a folder id from the folders list.","schema":{"type":"string"},"example":"all"},{"name":"includePending","in":"query","required":false,"description":"Pass the literal string `true` to also get PENDING and FLAGGED items (REJECTED never appears). Those items come back with `filePath: \"\"` and `downloadUrl: null` — thumbnail only — and each item gains a `moderationStatus` field.","schema":{"type":"boolean","default":false}},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Vault items, folders and pagination.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaultListResponse"},"example":{"items":[{"id":"clxv1a2b30001item","fileName":"beach-set-01.jpg","filePath":"https://cdn.dropfans.io/valeria/vault/1721990000-ab12cd.jpg","thumbnailPath":"https://cdn.dropfans.io/valeria/thumbnails/1721990000-ab12cd.jpg","fileType":"image","fileSize":482113,"durationSeconds":null,"bunnyStreamId":null,"createdAt":"2026-08-01T10:15:00.000Z","folderId":"clxf0ld3r0001abcd","contentTags":["beach","bikini"],"downloadUrl":null}],"folders":[{"id":"clxf0ld3r0001abcd","name":"Beach set","itemCount":12}],"hasMore":true,"total":128,"page":1,"limit":50}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch vault items"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/vault?page=1&folderId=all\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/vault?page=1&folderId=all`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/vault\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"page\": 1, \"folderId\": \"all\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-vault","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"},"post":{"operationId":"uploadVaultItem","tags":["vault"],"summary":"Upload an image, small video or voice message","description":"Uploads one file into the creator's vault as `multipart/form-data`.\n\nThree kinds, three shapes: **images** need two parts — a pre-compressed `displayFile` and a `thumbnailFile` (both JPEG); **audio** (voice messages) sends one `file` part (≤20MB, ≤60 min); **video** sends one `file` part — but the whole request must stay under ~4MB (a platform body cap rejects bigger requests before the app runs), so for real videos use the three-step TUS flow starting at [POST /api/external/v1/vault/video-upload](/developers/reference/start-video-upload) instead.\n\nEvery upload enters the same moderation pipeline as a dashboard upload: images are scored immediately, videos asynchronously, audio goes to human review (or auto-approves for trusted creators). The item only shows up in the default vault list once APPROVED.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"fileType":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"originalName":{"type":"string","description":"The file’s name, stored as fileName.","example":"beach-set-01.jpg"},"folderId":{"type":"string","description":"Optional folder to file the item into."},"durationSeconds":{"type":"integer","description":"Audio only — the voice message length in seconds (capped at 3600).","maximum":3600},"displayFile":{"type":"string","contentMediaType":"application/octet-stream","description":"Images only (required): the pre-compressed JPEG display copy."},"thumbnailFile":{"type":"string","contentMediaType":"application/octet-stream","description":"Images only (required): the JPEG thumbnail."},"file":{"type":"string","contentMediaType":"application/octet-stream","description":"Video/audio only (required): the media file. Audio ≤20MB; video effectively ≤~4MB here — use the TUS flow for anything bigger."}},"required":["fileType","originalName"]},"examples":{"image":{"summary":"Image upload (display + thumbnail parts)","value":{"fileType":"image","originalName":"beach-set-01.jpg","displayFile":"@photo.jpg","thumbnailFile":"@photo-thumb.jpg"}},"audio":{"summary":"Voice message","value":{"fileType":"audio","originalName":"voice-note.ogg","durationSeconds":42,"file":"@voice-note.ogg"}}}}}},"responses":{"200":{"description":"Uploaded. The item starts PENDING moderation (not included in this shape — poll the list with includePending=true, or wait for it to appear in the default list).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"item":{"$ref":"#/components/schemas/VaultItemUploaded"}},"required":["success","item"]},"example":{"success":true,"item":{"id":"clxv1a2b30001item","fileName":"beach-set-01.jpg","filePath":"https://cdn.dropfans.io/valeria/vault/1721990000-ab12cd.jpg","thumbnailPath":"https://cdn.dropfans.io/valeria/thumbnails/1721990000-ab12cd.jpg","fileType":"image","fileSize":482113,"durationSeconds":null,"bunnyStreamId":null,"createdAt":"2026-08-01T10:15:00.000Z"}}}}},"400":{"description":"Either required form field is absent. Also: `fileType` is anything other than image, video or audio. Also: Image upload without both file parts. Also: fileType=video without a `file` part. Also: fileType=audio without a `file` part. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Missing required fields: fileType and originalName"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"413":{"description":"Audio file over 20MB.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Audio too large"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Storage or moderation kickoff failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to upload file"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/vault\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -F \"fileType=image\" \\\n  -F \"originalName=beach-set-01.jpg\" \\\n  -F \"displayFile=@photo.jpg\" \\\n  -F \"thumbnailFile=@photo-thumb.jpg\""},{"lang":"JavaScript","label":"Node","source":"import { readFile } from 'node:fs/promises';\n\nconst form = new FormData();\nform.append('fileType', \"image\");\nform.append('originalName', \"beach-set-01.jpg\");\nform.append('displayFile', new Blob([await readFile('photo.jpg')]), 'photo.jpg');\nform.append('thumbnailFile', new Blob([await readFile('photo-thumb.jpg')]), 'photo-thumb.jpg');\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/vault`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n  body: form,\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/vault\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    files={\n        \"displayFile\": open(\"photo.jpg\", \"rb\"),\n        \"thumbnailFile\": open(\"photo-thumb.jpg\", \"rb\"),\n    },\n    data={\n        \"fileType\": \"image\",\n        \"originalName\": \"beach-set-01.jpg\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/upload-vault-item","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/vault/{id}":{"delete":{"operationId":"deleteVaultItem","tags":["vault"],"summary":"Delete (hide) a vault item","description":"Soft-deletes a vault item you own: nothing is removed from storage, the item is hidden and disappears from every list.\n\nIdempotent — deleting an already-hidden item is a success, so blind retries are harmless.","parameters":[{"name":"id","in":"path","required":true,"description":"The vault item id.","schema":{"type":"string"},"example":"clxv1a2b30001item"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Hidden (or already hidden).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No item with that id on this creator’s account (other creators’ ids also 404 — never 403).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Vault item not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to delete vault item"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/vault/$VAULT_ITEM_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const vaultItemId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/vault/${vaultItemId}`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nvault_item_id = \"…\"  # from an earlier response\n\nres = requests.delete(\n    f\"https://www.dropfans.io/api/external/v1/vault/{vault_item_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-vault-item","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/vault/{id}/folder":{"patch":{"operationId":"moveVaultItem","tags":["vault"],"summary":"Move a vault item to a folder","description":"Files a vault item into a folder, or unfiles it back to \"All\".\n\nOmitting `folderId` (or sending `null`, `\"\"`, an empty body — even a malformed body) unfiles the item. That leniency is deliberate: `{}` is the documented unfile signal.","parameters":[{"name":"id","in":"path","required":true,"description":"The vault item id.","schema":{"type":"string"},"example":"clxv1a2b30001item"},{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folderId":{"type":["string","null"],"description":"Destination folder id. Omit/null/\"\" to unfile.","example":"clxf0ld3r0001abcd"}}},"examples":{"move":{"summary":"Move into a folder","value":{"folderId":"clxf0ld3r0001abcd"}},"unfile":{"summary":"Move back to All","value":{}}}}}},"responses":{"200":{"description":"Moved.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"400":{"description":"`folderId` is present but not a string (e.g. a number). Also: The destination is a system folder. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"folderId must be a string"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such item on this account. Also: No such folder on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Vault item not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to move vault item"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PATCH \"https://www.dropfans.io/api/external/v1/vault/$VAULT_ITEM_ID/folder\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"folderId\": \"clxf0ld3r0001abcd\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const vaultItemId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/vault/${vaultItemId}/folder`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"folderId\": \"clxf0ld3r0001abcd\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nvault_item_id = \"…\"  # from an earlier response\n\nres = requests.patch(\n    f\"https://www.dropfans.io/api/external/v1/vault/{vault_item_id}/folder\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"folderId\": \"clxf0ld3r0001abcd\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/move-vault-item","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/vault/{id}/tags":{"patch":{"operationId":"setVaultItemTags","tags":["vault"],"summary":"Replace a vault item’s content tags","description":"Replaces (not merges) the content tags on a vault item. Send the full list every time.\n\nTags are trimmed, de-duplicated, silently truncated to 64 characters each, and capped at 50 tags — the response echoes what was actually stored, so compare it to what you sent.\n\n> [!NOTE] Field name\n> The body field is `contentTags`, not `tags`.","parameters":[{"name":"id","in":"path","required":true,"description":"The vault item id.","schema":{"type":"string"},"example":"clxv1a2b30001item"},{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentTags":{"type":"array","items":{"type":"string","description":"A tag (longer ones are cut to 64 chars).","maxLength":64},"description":"The complete new tag list (≤50 kept).","maxItems":50}},"required":["contentTags"]},"examples":{"tags":{"summary":"Set two tags","value":{"contentTags":["beach","bikini"]}}}}}},"responses":{"200":{"description":"Stored — `contentTags` echoes the normalised list.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"contentTags":{"type":"array","items":{"type":"string","description":"A stored tag."},"description":"The tags after trimming, de-duplication and capping."}},"required":["success","contentTags"]},"example":{"success":true,"contentTags":["beach","bikini"]}}}},"400":{"description":"The body is not valid JSON. Also: Missing, not an array, or contains non-strings. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such item on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Vault item not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PATCH \"https://www.dropfans.io/api/external/v1/vault/$VAULT_ITEM_ID/tags\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"contentTags\": [\n    \"beach\",\n    \"bikini\"\n  ]\n}'"},{"lang":"JavaScript","label":"Node","source":"const vaultItemId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/vault/${vaultItemId}/tags`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"contentTags\": [\n      \"beach\",\n      \"bikini\"\n    ]\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nvault_item_id = \"…\"  # from an earlier response\n\nres = requests.patch(\n    f\"https://www.dropfans.io/api/external/v1/vault/{vault_item_id}/tags\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"contentTags\": [\n            \"beach\",\n            \"bikini\",\n        ],\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/set-vault-item-tags","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/vault/folders":{"get":{"operationId":"listFolders","tags":["vault"],"summary":"List vault folders","description":"Every folder the creator has, alphabetically. **Unpaginated** — you always get the full list.\n\n`itemCount` here counts every non-hidden item regardless of moderation status, so it can be higher than the count the vault list reports for the same folder (which respects the moderation filter).","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"All folders.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"folders":{"type":"array","items":{"$ref":"#/components/schemas/Folder"},"description":"Every folder, A→Z."}},"required":["folders"]},"example":{"folders":[{"id":"clxf0ld3r0001abcd","name":"Beach set","itemCount":14}]}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch vault folders"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/vault/folders\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/vault/folders`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/vault/folders\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-folders","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"},"post":{"operationId":"createFolder","tags":["vault"],"summary":"Create a vault folder","description":"Creates a folder. Names are unique per creator (case-sensitive) and at most 50 characters.\n\nThe response is the **bare folder object** — not wrapped in `{success}` or `{folder}` like most other write endpoints.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Folder name, trimmed, 1–50 chars, unique per creator.","example":"Beach set","maxLength":50}},"required":["name"]},"examples":{"create":{"summary":"Create a folder","value":{"name":"Beach set"}}}}}},"responses":{"200":{"description":"Created — the bare folder object.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Folder"},"example":{"id":"clxf0ld3r0001abcd","name":"Beach set","itemCount":0}}}},"400":{"description":"The body is not valid JSON. Also: `name` missing or not a string. Also: `name` is whitespace only. Also: Longer than 50 characters. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"409":{"description":"Duplicate name (also returned on a create race).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"A folder with this name already exists"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to create vault folder"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/vault/folders\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"Beach set\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/vault/folders`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"name\": \"Beach set\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/vault/folders\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"name\": \"Beach set\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-folder","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/vault/folders/{folderId}":{"delete":{"operationId":"deleteFolder","tags":["vault"],"summary":"Delete a vault folder","description":"Deletes a folder you own. **Non-empty folders are allowed**: the items inside are preserved and fall back to \"All\" (unfiled) — nothing is removed from storage. System folders (compliance archives) cannot be deleted.","parameters":[{"name":"folderId","in":"path","required":true,"description":"The folder id.","schema":{"type":"string"},"example":"clxf0ld3r0001abcd"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Deleted; contained items are now unfiled.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"400":{"description":"The folder is a system folder. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"This folder is managed automatically and cannot be deleted."}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such folder on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Folder not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to delete vault folder"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/vault/folders/$FOLDER_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const folderId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/vault/folders/${folderId}`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nfolder_id = \"…\"  # from an earlier response\n\nres = requests.delete(\n    f\"https://www.dropfans.io/api/external/v1/vault/folders/{folder_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-folder","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/vault/video-upload":{"post":{"operationId":"startVideoUpload","tags":["vault"],"summary":"Start a video upload (step 1 of 3)","description":"Starts a direct-to-CDN video upload and returns presigned TUS credentials.\n\nVideos cannot ride through [POST /api/external/v1/vault](/developers/reference/upload-vault-item) — the platform rejects request bodies over ~4MB before the app even runs. Instead: **(1)** call this to create the video and get credentials, **(2)** upload the raw bytes straight to the returned `tusEndpoint` with any TUS client, sending `AuthorizationSignature`, `AuthorizationExpire`, `VideoId` and `LibraryId` as TUS headers, **(3)** call [complete](/developers/reference/complete-video-upload) with the `completionToken`. The full sequence with code is in the [upload guide](/developers/guides/upload-media).\n\nThe CDN API key itself is never exposed — only a sha256 signature valid ~6 hours. The completion token is valid 8 hours.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"originalName":{"type":"string","description":"The video file name, stored as fileName.","example":"teaser.mp4"},"fileSize":{"type":"integer","description":"Optional advisory byte count — obvious oversizes are rejected up front. The authoritative check runs at completion. Max 500MB.","example":52428800,"maximum":524288000}},"required":["originalName"]},"examples":{"start":{"summary":"Start an upload","value":{"originalName":"teaser.mp4","fileSize":52428800}}}}}},"responses":{"200":{"description":"Upload created — feed these credentials to your TUS client.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoUploadCredentials"},"example":{"videoId":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9","tusEndpoint":"https://video.bunnycdn.com/tusupload","libraryId":"572783","signature":"9b2f…64 hex…c1a0","expires":1755640800,"completionToken":"eyJ…"}}}},"400":{"description":"`originalName` absent or blank. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Missing required field: originalName"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"413":{"description":"The advisory fileSize exceeds 500MB.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Video too large. Max 500MB."}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"CDN video creation failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Could not start the video upload"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/vault/video-upload\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"originalName\": \"teaser.mp4\",\n  \"fileSize\": 52428800\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/vault/video-upload`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"originalName\": \"teaser.mp4\",\n    \"fileSize\": 52428800\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/vault/video-upload\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"originalName\": \"teaser.mp4\",\n        \"fileSize\": 52428800,\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/start-video-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/vault/video-upload/complete":{"post":{"operationId":"completeVideoUpload","tags":["vault"],"summary":"Finish a video upload (step 3 of 3)","description":"Registers a finished TUS upload as a vault item and kicks moderation.\n\n**Idempotent**: a retried completion for an already-registered video returns the existing item instead of creating a duplicate — retry freely. **409 means \"not finished yet, retry\"**: the CDN can lag a few seconds after the TUS client reports done, so on a 409 back off (2s, 5s, 10s, 30s) and call again with the same body.\n\nThe item starts `PENDING` and finalizes asynchronously (the NSFW pipeline plus transcoding). Poll [video-status](/developers/reference/video-status) with the `bunnyStreamId` to know when the video is playable, and the vault list for moderation.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"videoId":{"type":"string","description":"The `videoId` from step 1.","example":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9"},"originalName":{"type":"string","description":"Same file name you sent in step 1.","example":"teaser.mp4"},"completionToken":{"type":"string","description":"The token from step 1 (valid 8h). Proves this key started the upload."},"folderId":{"type":["string","null"],"description":"Optional folder — silently ignored if you don’t own it."}},"required":["videoId","originalName","completionToken"]},"examples":{"complete":{"summary":"Register the uploaded video","value":{"videoId":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9","originalName":"teaser.mp4","completionToken":"eyJ…"}}}}}},"responses":{"200":{"description":"Registered (or already registered — idempotent).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"item":{"$ref":"#/components/schemas/VideoVaultItem"}},"required":["success","item"]},"example":{"success":true,"item":{"id":"clxv9z8y70002item","fileName":"teaser.mp4","filePath":"https://vz-example.b-cdn.net/c2f7f9e2-…/playlist.m3u8?token=…","thumbnailPath":"https://vz-example.b-cdn.net/c2f7f9e2-…/thumbnail.jpg?token=…","fileType":"video","fileSize":52428800,"bunnyStreamId":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9","moderationStatus":"PENDING","moderationTags":[],"createdAt":"2026-08-01T10:20:00.000Z","aiEnhanced":false}}}}},"400":{"description":"Either field absent or blank. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Missing required fields: videoId and originalName"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The completionToken is wrong, for another key, or older than 8h — start over from step 1. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or expired upload token — please retry the upload"}}}},"409":{"description":"The CDN has not finished receiving the bytes — back off and retry the same call.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"The video upload has not finished — please retry."}}}},"413":{"description":"The stored byte count exceeds the cap — the upload is discarded.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Video too large. Max 500MB."}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Registration failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to register the uploaded video"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/vault/video-upload/complete\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"videoId\": \"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9\",\n  \"originalName\": \"teaser.mp4\",\n  \"completionToken\": \"eyJ…\"\n}'"},{"lang":"JavaScript","label":"Node","source":"// Step 2 happens in your client with a TUS library (npm i tus-js-client),\n// then step 3 registers the finished upload.\nimport * as tus from 'tus-js-client';\nimport { readFile } from 'node:fs/promises';\n\nconst creds = await ( // step 1\n  await fetch('https://www.dropfans.io/api/external/v1/vault/video-upload', {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({ originalName: 'teaser.mp4' }),\n  })\n).json();\n\nconst file = await readFile('teaser.mp4');\nawait new Promise((resolve, reject) => {   // step 2 — raw bytes straight to the CDN\n  new tus.Upload(file, {\n    endpoint: creds.tusEndpoint,\n    headers: {\n      AuthorizationSignature: creds.signature,\n      AuthorizationExpire: String(creds.expires),\n      VideoId: creds.videoId,\n      LibraryId: creds.libraryId,\n    },\n    metadata: { filetype: 'video/mp4', title: 'teaser.mp4' },\n    onError: reject,\n    onSuccess: resolve,\n  }).start();\n});\n\n// step 3 — 409 means \"not finished yet\": back off and retry the same call\nfor (const waitMs of [0, 2000, 5000, 10000, 30000]) {\n  if (waitMs) await new Promise((r) => setTimeout(r, waitMs));\n  const res = await fetch(\n    'https://www.dropfans.io/api/external/v1/vault/video-upload/complete',\n    {\n      method: 'POST',\n      headers: {\n        Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        videoId: creds.videoId,\n        originalName: 'teaser.mp4',\n        completionToken: creds.completionToken,\n      }),\n    },\n  );\n  if (res.status !== 409) {\n    console.log(await res.json());\n    break;\n  }\n}"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/vault/video-upload/complete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"videoId\": \"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9\",\n        \"originalName\": \"teaser.mp4\",\n        \"completionToken\": \"eyJ…\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/complete-video-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/vault/video-status":{"post":{"operationId":"videoStatus","tags":["vault"],"summary":"Check video transcoding status (batch)","description":"Transcoding status + duration for a batch of video GUIDs (`bunnyStreamId` values from your vault items).\n\nA freshly uploaded video is not forwardable or playable until `isReady` — poll this while `isProcessing`. Reasonable interval: every 15–30 seconds while you wait on a specific video.\n\n> [!WARNING] Silent truncation and omission\n> At most 50 ids are processed per call — extras are **dropped without an error**, so chunk larger lists. Ids you don't own, and ids whose lookup errored, are **omitted from the response** rather than reported: treat a missing key as \"not ready\".","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"videoIds":{"type":"array","items":{"type":"string","description":"A Bunny Stream GUID (vault item `bunnyStreamId`)."},"description":"Stream GUIDs to check (≤50 — extras silently dropped). Non-strings are filtered out; an empty array returns {\"statuses\":{}}.","maxItems":50}},"required":["videoIds"]},"examples":{"batch":{"summary":"Check two videos","value":{"videoIds":["c2f7f9e2-1111-4222-b333-4d55e6f7a8b9","0f3d9a11-2222-4333-a444-5e66f7a8b9c0"]}}}}}},"responses":{"200":{"description":"Status map keyed by the GUIDs you sent (unresolvable ids omitted).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"statuses":{"$ref":"#/components/schemas/VideoStatusMap"}},"required":["statuses"]},"example":{"statuses":{"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9":{"isReady":true,"isProcessing":false,"isFailed":false,"length":74},"0f3d9a11-2222-4333-a444-5e66f7a8b9c0":{"isReady":false,"isProcessing":true,"isFailed":false}}}}}},"400":{"description":"The body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/vault/video-status\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"videoIds\": [\n    \"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9\",\n    \"0f3d9a11-2222-4333-a444-5e66f7a8b9c0\"\n  ]\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/vault/video-status`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"videoIds\": [\n      \"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9\",\n      \"0f3d9a11-2222-4333-a444-5e66f7a8b9c0\"\n    ]\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/vault/video-status\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"videoIds\": [\n            \"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9\",\n            \"0f3d9a11-2222-4333-a444-5e66f7a8b9c0\",\n        ],\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/video-status","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/media/uploads":{"post":{"operationId":"createMediaUpload","tags":["vault"],"summary":"Start a media upload session","description":"Opens an upload session for one image, video or audio file. Video gets tus credentials for a direct upload; image and audio get 3 MB part URLs to PUT.\n\nThen call [complete](/developers/reference/complete-media-upload) and poll [the session](/developers/reference/get-media-upload) for the vault item and its moderation. The session is valid 8 hours; abandoned sessions are cleaned up daily.\n\n**Video** (up to 500 MB): upload the bytes with any tus client to `tus.endpoint`, sending `tus.headers` as headers — the same direct-to-CDN upload as [start-video-upload](/developers/reference/start-video-upload). **Image** (up to 30 MB) and **audio** (up to 20 MB): PUT each part's bytes to its `url` with your API key — parts go through us because our storage has no presigned writes. Parts can go in any order and in parallel.\n\nThe stored file has its metadata (EXIF, GPS, XMP, ID3 tags …) removed, as with every vault upload.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"filename":{"type":"string","description":"File name, stored on the vault item.","example":"beach.jpg","maxLength":255},"sizeBytes":{"type":"integer","description":"Exact file size in bytes. Image ≤ 30 MB, video ≤ 500 MB, audio ≤ 20 MB.","example":7904267},"contentType":{"type":"string","description":"MIME type; must match `kind` (image/*, video/*, audio/*).","example":"image/jpeg"},"folderId":{"type":["string","null"],"description":"Optional vault folder of this account."},"durationSeconds":{"type":"number","description":"Audio only: the voice note's length (capped at 3600s)."}},"required":["kind","filename","sizeBytes","contentType"]},"examples":{"image":{"summary":"An 8 MB photo","value":{"kind":"image","filename":"beach.jpg","sizeBytes":7904267,"contentType":"image/jpeg"}},"video":{"summary":"A video","value":{"kind":"video","filename":"teaser.mp4","sizeBytes":52428800,"contentType":"video/mp4"}}}}}},"responses":{"201":{"description":"Session opened: the session fields plus `parts` (image / audio) or `tus` (video).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Upload id."},"kind":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"status":{"type":"string","description":"`uploading` until you complete it; `processing` while a complete runs; `completed` once the vault item exists.","enum":["uploading","processing","completed","failed","expired"]},"fileName":{"type":"string","description":"The file name, stored on the vault item."},"contentType":{"type":"string","description":"The stored content type."},"sizeBytes":{"type":"integer","description":"The declared size."},"folderId":{"type":["string","null"],"description":"The vault folder the item goes in."},"partSize":{"type":["integer","null"],"description":"Image / audio: bytes per part (the last part is the remainder). Null for video."},"totalParts":{"type":["integer","null"],"description":"Image / audio: number of parts. Null for video."},"receivedParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers received so far."},"missingParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers still to upload."},"vaultItemId":{"type":["string","null"],"description":"The vault item, once completed."},"moderationStatus":{"type":["string","null"],"description":"The vault item’s moderation status, once completed.","enum":["PENDING","APPROVED","FLAGGED","REJECTED"]},"bunnyStreamId":{"type":["string","null"],"description":"Video: the Stream video id — poll [video-status](/developers/reference/video-status) with it."},"error":{"type":["object","null"],"properties":{"code":{"type":"string","description":"Machine-readable reason."},"message":{"type":["string","null"],"description":"Human-readable reason."}},"required":["code"],"description":"`{ code, message }` when the upload failed or expired."},"expiresAt":{"type":"string","description":"Upload the parts (or the tus bytes) and complete before this.","format":"date-time"},"createdAt":{"type":"string","description":"When the session was opened.","format":"date-time"},"completedAt":{"type":["string","null"],"description":"When it completed.","format":"date-time"},"parts":{"type":"array","items":{"type":"object","properties":{"partNumber":{"type":"integer","description":"1-based."},"sizeBytes":{"type":"integer","description":"Exact bytes this part must have."},"method":{"type":"string","description":"Always PUT."},"url":{"type":"string","description":"Where to PUT it (with your API key).","format":"uri"}},"required":["partNumber","sizeBytes","method","url"],"description":"One part."},"description":"Image / audio: PUT each part to its `url`."},"tus":{"type":"object","properties":{"endpoint":{"type":"string","description":"tus endpoint.","format":"uri"},"videoId":{"type":"string","description":"The Stream video id."},"libraryId":{"type":"string","description":"The Stream library id."},"signature":{"type":"string","description":"sha256 upload signature."},"expires":{"type":"integer","description":"Signature expiry (unix seconds)."},"headers":{"type":"object","description":"Send these as tus headers: AuthorizationSignature, AuthorizationExpire, VideoId, LibraryId."}},"required":["endpoint","videoId","libraryId","signature","expires","headers"],"description":"Video: tus upload credentials (the CDN API key itself is never exposed)."}},"required":["id","kind","status","fileName","contentType","sizeBytes","expiresAt","createdAt"]},"example":{"id":"mu_3f9c1a7be0d24c55a1e8b6f2","kind":"image","status":"uploading","fileName":"beach.jpg","contentType":"image/jpeg","sizeBytes":7904267,"folderId":null,"partSize":3145728,"totalParts":3,"receivedParts":[],"missingParts":[1,2,3],"vaultItemId":null,"moderationStatus":null,"bunnyStreamId":null,"error":null,"expiresAt":"2026-10-31T18:00:00.000Z","createdAt":"2026-10-31T10:00:00.000Z","completedAt":null,"parts":[{"partNumber":1,"sizeBytes":3145728,"method":"PUT","url":"https://www.dropfans.io/api/external/v1/media/uploads/mu_3f9c1a7be0d24c55a1e8b6f2/parts/1"},{"partNumber":2,"sizeBytes":3145728,"method":"PUT","url":"https://www.dropfans.io/api/external/v1/media/uploads/mu_3f9c1a7be0d24c55a1e8b6f2/parts/2"},{"partNumber":3,"sizeBytes":1612811,"method":"PUT","url":"https://www.dropfans.io/api/external/v1/media/uploads/mu_3f9c1a7be0d24c55a1e8b6f2/parts/3"}]}}}},"400":{"description":"Unknown `kind`. Also: `filename` missing or too long. Also: `sizeBytes` missing or not a positive integer. Also: `contentType` does not match `kind`. Also: Unknown folder, or another account’s. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"kind must be image, video or audio","code":"invalid_kind"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"413":{"description":"`sizeBytes` is over the limit for `kind`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"File too large. Max 30MB for image.","code":"file_too_large","maxBytes":31457280}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"The CDN did not create the video.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not start the video upload — retry later","code":"video_create_failed"}}}},"503":{"description":"Video (or, with media_uploads_unavailable, image / audio) uploads are switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Video uploads are not available right now","code":"video_uploads_unavailable"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/media/uploads\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"kind\": \"image\",\n  \"filename\": \"beach.jpg\",\n  \"sizeBytes\": 7904267,\n  \"contentType\": \"image/jpeg\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/media/uploads`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"kind\": \"image\",\n    \"filename\": \"beach.jpg\",\n    \"sizeBytes\": 7904267,\n    \"contentType\": \"image/jpeg\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/media/uploads\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"kind\": \"image\",\n        \"filename\": \"beach.jpg\",\n        \"sizeBytes\": 7904267,\n        \"contentType\": \"image/jpeg\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-media-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/media/uploads/{id}/parts/{partNumber}":{"put":{"operationId":"uploadMediaPart","tags":["vault"],"summary":"Upload one part (image / audio)","description":"Uploads one part of an image or audio session: the raw bytes as the request body (`Content-Type: application/octet-stream`).\n\nEvery part except the last is exactly `partSize` (3 MB); the last one is the remainder. Send parts in any order and in parallel. Repeating a part replaces it, so retry a failed part freely.","parameters":[{"name":"id","in":"path","required":true,"description":"The upload `id` from POST /api/external/v1/media/uploads.","schema":{"type":"string"},"example":"mu_3f9c1a7be0d24c55a1e8b6f2"},{"name":"partNumber","in":"path","required":true,"description":"1-based part number, up to `totalParts`.","schema":{"type":"integer","minimum":1},"example":1},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Part stored.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Upload id."},"partNumber":{"type":"integer","description":"The part you sent."},"sizeBytes":{"type":"integer","description":"Bytes received."},"receivedParts":{"type":"array","items":{"type":"integer","description":"Part number."},"description":"Parts received so far."},"missingParts":{"type":"array","items":{"type":"integer","description":"Part number."},"description":"Parts still missing — empty means you can complete."}},"required":["id","partNumber","sizeBytes","receivedParts","missingParts"]},"example":{"id":"mu_3f9c1a7be0d24c55a1e8b6f2","partNumber":1,"sizeBytes":3145728,"receivedParts":[1],"missingParts":[2,3]}}}},"400":{"description":"Part number out of range. Also: The part is not exactly the size it must have. Also: A video session. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Part number must be 1–3","code":"invalid_part_number"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"Unknown id, or an upload of another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Upload not found","code":"upload_not_found"}}}},"409":{"description":"The session is completed, failed or being completed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This upload is completed and takes no more parts","code":"upload_not_accepting_parts","status":"completed"}}}},"410":{"description":"Past `expiresAt`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This upload session has expired — start a new one","code":"upload_expired"}}}},"413":{"description":"The part is bigger than `partSize`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Parts are at most 3145728 bytes","code":"part_too_large","partSize":3145728}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PUT \"https://www.dropfans.io/api/external/v1/media/uploads/$VAULT_ITEM_ID/parts/$VAULT_ITEM_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const vaultItemId = '…'; // from an earlier response\nconst vaultItemId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/media/uploads/${vaultItemId}/parts/${vaultItemId}`, {\n  method: 'PUT',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nvault_item_id = \"…\"  # from an earlier response\nvault_item_id = \"…\"  # from an earlier response\n\nres = requests.put(\n    f\"https://www.dropfans.io/api/external/v1/media/uploads/{vault_item_id}/parts/{vault_item_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/upload-media-part","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/media/uploads/{id}/complete":{"post":{"operationId":"completeMediaUpload","tags":["vault"],"summary":"Complete a media upload","description":"Turns the upload into a vault item and starts moderation. Image / audio: the parts are joined and stored with their metadata removed. Video: the finished tus upload is registered.\n\n**Idempotent**: completing a completed session returns the same body, so retry freely. The item starts `PENDING`; poll [GET the session](/developers/reference/get-media-upload) for `moderationStatus`, and for a video [video-status](/developers/reference/video-status) for transcoding.\n\nFor a video, **409 `upload_not_finished` means retry**: the CDN can lag a few seconds after your tus client reports done, so back off (2s, 5s, 10s, 30s) and call again.","parameters":[{"name":"id","in":"path","required":true,"description":"The upload `id` from POST /api/external/v1/media/uploads.","schema":{"type":"string"},"example":"mu_3f9c1a7be0d24c55a1e8b6f2"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Completed (or already completed).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Upload id."},"kind":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"status":{"type":"string","description":"`uploading` until you complete it; `processing` while a complete runs; `completed` once the vault item exists.","enum":["uploading","processing","completed","failed","expired"]},"fileName":{"type":"string","description":"The file name, stored on the vault item."},"contentType":{"type":"string","description":"The stored content type."},"sizeBytes":{"type":"integer","description":"The declared size."},"folderId":{"type":["string","null"],"description":"The vault folder the item goes in."},"partSize":{"type":["integer","null"],"description":"Image / audio: bytes per part (the last part is the remainder). Null for video."},"totalParts":{"type":["integer","null"],"description":"Image / audio: number of parts. Null for video."},"receivedParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers received so far."},"missingParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers still to upload."},"vaultItemId":{"type":["string","null"],"description":"The vault item, once completed."},"moderationStatus":{"type":["string","null"],"description":"The vault item’s moderation status, once completed.","enum":["PENDING","APPROVED","FLAGGED","REJECTED"]},"bunnyStreamId":{"type":["string","null"],"description":"Video: the Stream video id — poll [video-status](/developers/reference/video-status) with it."},"error":{"type":["object","null"],"properties":{"code":{"type":"string","description":"Machine-readable reason."},"message":{"type":["string","null"],"description":"Human-readable reason."}},"required":["code"],"description":"`{ code, message }` when the upload failed or expired."},"expiresAt":{"type":"string","description":"Upload the parts (or the tus bytes) and complete before this.","format":"date-time"},"createdAt":{"type":"string","description":"When the session was opened.","format":"date-time"},"completedAt":{"type":["string","null"],"description":"When it completed.","format":"date-time"}},"required":["id","kind","status","fileName","contentType","sizeBytes","expiresAt","createdAt"]},"example":{"id":"mu_3f9c1a7be0d24c55a1e8b6f2","kind":"image","status":"completed","fileName":"beach.jpg","contentType":"image/jpeg","sizeBytes":7904267,"folderId":null,"partSize":3145728,"totalParts":3,"receivedParts":[1,2,3],"missingParts":[],"vaultItemId":"clxv9z8y70003item","moderationStatus":"PENDING","bunnyStreamId":null,"error":null,"expiresAt":"2026-10-31T18:00:00.000Z","createdAt":"2026-10-31T10:00:00.000Z","completedAt":"2026-10-31T10:00:41.000Z"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"Unknown id, or an upload of another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Upload not found","code":"upload_not_found"}}}},"409":{"description":"Image / audio: parts are missing. Upload them and complete again. Also: Video: the CDN has not received all the bytes yet — back off and retry. Also: Another complete call is running for this session. Also: The session already failed — start a new one.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Upload the missing parts first: 3","code":"missing_parts","missingParts":[3]}}}},"410":{"description":"Past `expiresAt`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This upload session has expired — start a new one","code":"upload_expired"}}}},"413":{"description":"The stored file is over the limit; the upload is discarded.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Video too large. Max 500MB.","code":"file_too_large"}}}},"415":{"description":"Image / audio: we cannot remove the file’s metadata safely (also 422 MALFORMED / UNSANITISABLE), so it is not stored.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unsupported image format. Please upload a JPEG, PNG, WebP, GIF, HEIC or AVIF.","code":"UNSUPPORTED_FORMAT"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Unexpected failure — the session goes back to `uploading`; retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not complete the upload — retry","code":"complete_failed"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/media/uploads/$VAULT_ITEM_ID/complete\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const vaultItemId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/media/uploads/${vaultItemId}/complete`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nvault_item_id = \"…\"  # from an earlier response\n\nres = requests.post(\n    f\"https://www.dropfans.io/api/external/v1/media/uploads/{vault_item_id}/complete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/complete-media-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/media/uploads/{id}":{"get":{"operationId":"getMediaUpload","tags":["vault"],"summary":"Get a media upload","description":"The session's status: which parts arrived, the vault item once completed, and its moderation status.\n\nPoll this after [complete](/developers/reference/complete-media-upload) until `moderationStatus` leaves `PENDING` — every 15–30 seconds is plenty. Sessions are kept for 30 days.","parameters":[{"name":"id","in":"path","required":true,"description":"The upload `id` from POST /api/external/v1/media/uploads.","schema":{"type":"string"},"example":"mu_3f9c1a7be0d24c55a1e8b6f2"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The session.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Upload id."},"kind":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"status":{"type":"string","description":"`uploading` until you complete it; `processing` while a complete runs; `completed` once the vault item exists.","enum":["uploading","processing","completed","failed","expired"]},"fileName":{"type":"string","description":"The file name, stored on the vault item."},"contentType":{"type":"string","description":"The stored content type."},"sizeBytes":{"type":"integer","description":"The declared size."},"folderId":{"type":["string","null"],"description":"The vault folder the item goes in."},"partSize":{"type":["integer","null"],"description":"Image / audio: bytes per part (the last part is the remainder). Null for video."},"totalParts":{"type":["integer","null"],"description":"Image / audio: number of parts. Null for video."},"receivedParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers received so far."},"missingParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers still to upload."},"vaultItemId":{"type":["string","null"],"description":"The vault item, once completed."},"moderationStatus":{"type":["string","null"],"description":"The vault item’s moderation status, once completed.","enum":["PENDING","APPROVED","FLAGGED","REJECTED"]},"bunnyStreamId":{"type":["string","null"],"description":"Video: the Stream video id — poll [video-status](/developers/reference/video-status) with it."},"error":{"type":["object","null"],"properties":{"code":{"type":"string","description":"Machine-readable reason."},"message":{"type":["string","null"],"description":"Human-readable reason."}},"required":["code"],"description":"`{ code, message }` when the upload failed or expired."},"expiresAt":{"type":"string","description":"Upload the parts (or the tus bytes) and complete before this.","format":"date-time"},"createdAt":{"type":"string","description":"When the session was opened.","format":"date-time"},"completedAt":{"type":["string","null"],"description":"When it completed.","format":"date-time"}},"required":["id","kind","status","fileName","contentType","sizeBytes","expiresAt","createdAt"]},"example":{"id":"mu_3f9c1a7be0d24c55a1e8b6f2","kind":"image","status":"completed","fileName":"beach.jpg","contentType":"image/jpeg","sizeBytes":7904267,"folderId":null,"partSize":3145728,"totalParts":3,"receivedParts":[1,2,3],"missingParts":[],"vaultItemId":"clxv9z8y70003item","moderationStatus":"PENDING","bunnyStreamId":null,"error":null,"expiresAt":"2026-10-31T18:00:00.000Z","createdAt":"2026-10-31T10:00:00.000Z","completedAt":"2026-10-31T10:00:41.000Z"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"Unknown id, or an upload of another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Upload not found","code":"upload_not_found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/media/uploads/$VAULT_ITEM_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const vaultItemId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/media/uploads/${vaultItemId}`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nvault_item_id = \"…\"  # from an earlier response\n\nres = requests.get(\n    f\"https://www.dropfans.io/api/external/v1/media/uploads/{vault_item_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-media-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault"}},"/api/external/v1/drops":{"post":{"operationId":"createDrop","tags":["drops"],"summary":"Create a sellable drop from vault items","description":"Packages up to 10 vault items into a drop and returns a checkout URL.\n\nPrice is USD **dollars**: either `0` (free) or between $5 and $750. Use APPROVED vault items — the drop inherits its moderation status from its media, so a drop built from approved items is sellable (and attachable to a post) immediately, while one containing PENDING items waits for review. Hand the buyer the returned `buyUrl`, or build a Telegram link from [GET /api/external/v1/links](/developers/reference/get-links)' `telegram.buyTemplate`.\n\n**One drop, many fans.** Don't create a copy per recipient. Create the drop once and give each fan their own link with a reference: `buyUrl?m={yourRef}` on the web, or `startapp=b_{productId}_{yourRef}` in Telegram. The reference comes back on every paid order — see [Broadcast one drop to many fans](/developers/guides/broadcast-one-drop). Different prices still need separate drops.\n\n> [!WARNING] `description` is validated but NOT stored\n> The `description` field runs through the prohibited-word filter and is then deliberately discarded — it is never shown anywhere on Dropfans. You get a 200 with no indication it was dropped. Treat it as a moderation input only.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Drop title, shown at checkout. Falsy values are stored as null.","example":"Beach set — 6 photos"},"description":{"type":"string","description":"Checked for prohibited words, then discarded — never persisted or displayed."},"price":{"type":"number","description":"USD dollars. 0 = free; otherwise $5–$750.","example":25,"minimum":0,"maximum":750},"allowDownload":{"type":"boolean","description":"Images only: when true, buyers get a Download button serving a watermarked, metadata-stripped JPEG. Videos always stream behind DRM and are never downloadable. Off unless explicitly set.","default":false},"vaultItemIds":{"type":"array","items":{"type":"string","description":"A vault item you own."},"description":"1–10 vault item ids, in display order. The first becomes the cover.","maxItems":10}},"required":["price","vaultItemIds"]},"examples":{"paidDrop":{"summary":"A $25 three-item drop","value":{"name":"Beach set — 6 photos","price":25,"vaultItemIds":["clxv1a2b30001item","clxv1a2b30002item","clxv1a2b30003item"]}}}}}},"responses":{"200":{"description":"Created. Keep the productId — sales polling, previews and post attachment all key on it.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropCreated"},"example":{"productId":"clxdr0p000001prod","buyUrl":"https://www.dropfans.io/buy/clxdr0p000001prod","mediaCount":3}}}},"400":{"description":"`price` missing, not a number, NaN or negative. Also: Priced above 0 but below $5. Also: Priced above $750. Also: The name or description tripped the word filter — a three-field envelope unique to this endpoint (posts use a two-field 422 for the same class of failure). Also: Missing or empty media list. Also: More than 10 ids. Also: One of the items was deleted (hidden). Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid price"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"An id belongs to another creator. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"You do not own all selected vault items"}}}},"404":{"description":"An id does not exist.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"One or more vault items not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to create drop"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/drops\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"Beach set — 6 photos\",\n  \"price\": 25,\n  \"vaultItemIds\": [\n    \"clxv1a2b30001item\",\n    \"clxv1a2b30002item\",\n    \"clxv1a2b30003item\"\n  ]\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/drops`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"name\": \"Beach set — 6 photos\",\n    \"price\": 25,\n    \"vaultItemIds\": [\n      \"clxv1a2b30001item\",\n      \"clxv1a2b30002item\",\n      \"clxv1a2b30003item\"\n    ]\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/drops\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"name\": \"Beach set — 6 photos\",\n        \"price\": 25,\n        \"vaultItemIds\": [\n            \"clxv1a2b30001item\",\n            \"clxv1a2b30002item\",\n            \"clxv1a2b30003item\",\n        ],\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-drop","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops"},"get":{"operationId":"listDrops","tags":["drops"],"summary":"List the creator’s drops","description":"Every drop on the account, newest first, with price, who can buy it, moderation status and checkout URL — including drops made in the dashboard.\n\nPage with `cursor`: pass the `nextCursor` of the previous page until it is null. For per-media status and sales of one drop, use [GET /api/external/v1/drops/{id}](/developers/reference/get-drop).","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size (out-of-range values are clamped).","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"A page of drops.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"drops":{"type":"array","items":{"$ref":"#/components/schemas/DropSummary"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["drops"]},"example":{"drops":[{"id":"clxdr0p000001prod","name":"Beach set — 6 photos","description":null,"price":25,"currency":"USD","accessMode":"OPEN","allowDownload":false,"status":"APPROVED","mediaCount":3,"buyUrl":"https://www.dropfans.io/buy/clxdr0p000001prod","createdAt":"2026-08-15T09:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/drops\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/drops`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/drops\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-drops","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops"}},"/api/external/v1/drops/{id}":{"get":{"operationId":"getDrop","tags":["drops"],"summary":"Read back a drop","description":"One drop you created: price, moderation status (overall and per media item), checkout URL, whether previews are attached, and a sales summary.\n\n`salesCount` counts paid orders **excluding refunds and chargebacks** — stricter than [check-status](/developers/reference/check-drop-status), which does not exclude them. Use this endpoint to verify a drop went APPROVED before attaching it to a post, and to see which media items still lack a baked preview.","parameters":[{"name":"id","in":"path","required":true,"description":"The product (drop) id from create-drop.","schema":{"type":"string"},"example":"clxdr0p000001prod"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The drop.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Drop"},"example":{"id":"clxdr0p000001prod","name":"Beach set — 6 photos","price":25,"currency":"USD","status":"APPROVED","moderationReason":null,"buyUrl":"https://www.dropfans.io/buy/clxdr0p000001prod","allowDownload":false,"mediaCount":3,"media":[{"vaultItemId":"clxv1a2b30001item","order":0,"fileType":"image","moderationStatus":"APPROVED","hasPreview":true},{"vaultItemId":"clxv1a2b30002item","order":1,"fileType":"image","moderationStatus":"APPROVED","hasPreview":true},{"vaultItemId":"clxv1a2b30003item","order":2,"fileType":"video","moderationStatus":"APPROVED","hasPreview":false}],"salesCount":2,"lastSaleAt":"2026-08-18T21:03:00.000Z","createdAt":"2026-08-15T09:00:00.000Z"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such drop on this account (another creator’s drop also 404s — never 403).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/drops/$PRODUCT_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const productId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/drops/${productId}`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nproduct_id = \"…\"  # from an earlier response\n\nres = requests.get(\n    f\"https://www.dropfans.io/api/external/v1/drops/{product_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-drop","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops"},"patch":{"operationId":"updateDrop","tags":["drops"],"summary":"Edit a drop","description":"Changes a drop's name, description, price or who can buy it — the same edit the dashboard allows. Send only what changes; `null` clears name or description.\n\nPrice is USD **dollars**: `0` (free) or between $5 and $750; a new price applies to future purchases only. Subscriber gating (`SUBS_FREE`, `SUBS_ONLY_PAID`) needs an active [subscription tier](/developers/reference/update-subscription). Name and description run the prohibited-word filter. The media of a drop cannot change — create a new drop instead.","parameters":[{"name":"id","in":"path","required":true,"description":"The product (drop) id.","schema":{"type":"string"},"example":"clxdr0p000001prod"},{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":["string","null"],"description":"Drop title, shown at checkout (cut at 200 characters).","example":"Beach set — 8 photos","maxLength":200},"description":{"type":["string","null"],"description":"Drop description (cut at 5,000 characters). Unlike create-drop, this one is stored.","maxLength":5000},"price":{"type":"number","description":"USD dollars. 0 = free; otherwise $5–$750. Rounded to cents.","example":30,"minimum":0,"maximum":750},"accessMode":{"type":"string","description":"`OPEN` = anyone can buy; `SUBS_FREE` = free for subscribers; `SUBS_ONLY_PAID` = only subscribers can buy.","enum":["OPEN","SUBS_FREE","SUBS_ONLY_PAID"]}}},"examples":{"reprice":{"summary":"Rename and reprice","value":{"name":"Beach set — 8 photos","price":30}}}}}},"responses":{"200":{"description":"The drop after the edit.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropUpdated"},"example":{"id":"clxdr0p000001prod","name":"Beach set — 8 photos","description":null,"price":30,"accessMode":"OPEN","moderationStatus":"APPROVED","currency":"USD","status":"APPROVED","buyUrl":"https://www.dropfans.io/buy/clxdr0p000001prod"}}}},"400":{"description":"`price` not a number or negative. Also: Priced above 0 but below $5. Also: Priced above $750. Also: Unknown accessMode. Also: Subscriber gating without an active tier. Also: `name` or `description` is not a string or null. Also: Name or description tripped the word filter. Also: The body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"price must be a number in USD (0 = free)"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such drop on this account (another creator’s drop also 404s).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PATCH \"https://www.dropfans.io/api/external/v1/drops/$PRODUCT_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"Beach set — 8 photos\",\n  \"price\": 30\n}'"},{"lang":"JavaScript","label":"Node","source":"const productId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/drops/${productId}`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"name\": \"Beach set — 8 photos\",\n    \"price\": 30\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nproduct_id = \"…\"  # from an earlier response\n\nres = requests.patch(\n    f\"https://www.dropfans.io/api/external/v1/drops/{product_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"name\": \"Beach set — 8 photos\",\n        \"price\": 30,\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-drop","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops"},"delete":{"operationId":"deleteDrop","tags":["drops"],"summary":"Delete a drop nobody has bought","description":"Deletes a drop that has no orders — not even an unfinished checkout. Once anyone has an order on it, buyers' access depends on it and the call returns `409 has_orders`.\n\nThe vault media stays in the vault either way.","parameters":[{"name":"id","in":"path","required":true,"description":"The product (drop) id.","schema":{"type":"string"},"example":"clxdr0p000001prod"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Deleted.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The deleted drop’s id."},"deleted":{"type":"boolean","description":"Always true."}},"required":["id","deleted"]},"example":{"id":"clxdr0p000001prod","deleted":true}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such drop on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"409":{"description":"The drop has at least one order (paid or started).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This drop has orders, so buyers keep access to it and it cannot be deleted.","code":"has_orders"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/drops/$PRODUCT_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const productId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/drops/${productId}`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nproduct_id = \"…\"  # from an earlier response\n\nres = requests.delete(\n    f\"https://www.dropfans.io/api/external/v1/drops/{product_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-drop","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops"}},"/api/external/v1/drops/{id}/previews":{"post":{"operationId":"attachDropPreviews","tags":["drops"],"summary":"Attach baked blur previews to a drop","description":"Uploads pre-blurred (\"baked\") JPEG teasers for a drop's media, so the checkout page shows the exact same blur your app showed the buyer elsewhere.\n\nThe body is `multipart/form-data` with one part per media item, named by vault item id: `previewBlob_<vaultItemId>` (the baked JPEG) and optionally `blurMeta_<vaultItemId>` (a descriptor like `\"partial\"`, `\"pixelated:59\"` or `\"full\"`). Without previews, paid media falls back to a generic gaussian blur.\n\n> [!WARNING] Best-effort — skipped items fail silently\n> Parts that are missing, not `image/jpeg`, over 8MB, or that hit a storage error are **skipped without an error**. The only signal is the `updated` count — compare it to how many parts you sent. Repeatable: re-sending overwrites the stored preview.","parameters":[{"name":"id","in":"path","required":true,"description":"The product (drop) id.","schema":{"type":"string"},"example":"clxdr0p000001prod"},{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"description":"Field names embed the vault item id — one previewBlob per media item you want a preview on.","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"previewBlob_<vaultItemId>":{"type":"string","contentMediaType":"application/octet-stream","description":"The baked JPEG teaser for that media item. Must be image/jpeg, ≤8MB."},"blurMeta_<vaultItemId>":{"type":"string","description":"Optional blur descriptor recorded alongside: \"full\", \"partial\" or \"pixelated:<intensity>\".","example":"pixelated:59"}}},"examples":{"previews":{"summary":"Baked previews for two media items","value":{"previewBlob_clxv1a2b30001item":"@preview-1.jpg","blurMeta_clxv1a2b30001item":"partial","previewBlob_clxv1a2b30002item":"@preview-2.jpg","blurMeta_clxv1a2b30002item":"pixelated:59"}}}}}},"responses":{"200":{"description":"`updated` = how many previews were actually stored. If it is lower than the number of parts you sent, the difference was silently skipped.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"updated":{"type":"integer","description":"Previews stored on this call.","example":2}},"required":["success","updated"]},"example":{"success":true,"updated":2}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The drop belongs to another creator. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"You do not own this drop"}}}},"404":{"description":"No such drop.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Unexpected failure — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to attach previews"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/drops/$PRODUCT_ID/previews\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -F \"previewBlob_clxv1a2b30001item=@preview-1.jpg;type=image/jpeg\" \\\n  -F \"blurMeta_clxv1a2b30001item=partial\" \\\n  -F \"previewBlob_clxv1a2b30002item=@preview-2.jpg;type=image/jpeg\" \\\n  -F \"blurMeta_clxv1a2b30002item=pixelated:59\""},{"lang":"JavaScript","label":"Node","source":"import { readFile } from 'node:fs/promises';\n\nconst form = new FormData();\nform.append(\n  'previewBlob_clxv1a2b30001item',\n  new Blob([await readFile('preview-1.jpg')], { type: 'image/jpeg' }),\n  'preview-1.jpg',\n);\nform.append('blurMeta_clxv1a2b30001item', 'partial');\n\nconst res = await fetch(\n  `https://www.dropfans.io/api/external/v1/drops/${productId}/previews`,\n  {\n    method: 'POST',\n    headers: { Authorization: `Bearer ${process.env.DROPFANS_API_KEY}` },\n    body: form,\n  },\n);\nconsole.log(await res.json()); // { success: true, updated: 1 }"},{"lang":"Python","source":"import os, requests\n\nres = requests.post(\n    f\"https://www.dropfans.io/api/external/v1/drops/{product_id}/previews\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    files={\n        \"previewBlob_clxv1a2b30001item\": (\"preview-1.jpg\", open(\"preview-1.jpg\", \"rb\"), \"image/jpeg\"),\n    },\n    data={\"blurMeta_clxv1a2b30001item\": \"partial\"},\n)\nprint(res.json())  # { \"success\": true, \"updated\": 1 }"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/attach-drop-previews","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops"}},"/api/external/v1/drops/check-status":{"post":{"operationId":"checkDropStatus","tags":["drops"],"summary":"Check which drops sold (batch)","description":"Sale info for a batch of product ids — the polling half of sale tracking.\n\nPoll it periodically (every few minutes is plenty) with the productIds you are tracking. Amounts are gross buyer-paid totals in **cents**. `sales` keeps its original one-entry-per-product shape; `orders` lists **every** paid order per product with its per-fan `externalRef` — use that for shared drops (or the [drop.paid webhook](/developers/webhooks/overview)).\n\n> [!WARNING] Truncation, omission, refunds\n> At most 200 ids are processed per call — extras are **dropped without an error**, so chunk larger lists. Unsold and unknown ids are **omitted** from the response (only `paid: true` entries appear). And unlike earnings, this endpoint does **NOT exclude refunded or charged-back orders** — a refunded sale still reports paid. Reconcile against [GET /api/external/v1/earnings](/developers/reference/get-earnings) for net truth.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"productIds":{"type":"array","items":{"type":"string","description":"A product id from create-drop."},"description":"Product ids to check (≤200 — extras silently dropped). Non-strings filtered out; an empty array returns {\"sales\":{}}.","maxItems":200}},"required":["productIds"]},"examples":{"batch":{"summary":"Check two drops","value":{"productIds":["clxdr0p000001prod","clxdr0p000002prod"]}}}}}},"responses":{"200":{"description":"Sales map — only sold products appear. Multiple paid orders on one product report the most recent.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"sales":{"$ref":"#/components/schemas/SalesMap"},"orders":{"$ref":"#/components/schemas/OrdersByProduct"}},"required":["sales","orders"]},"example":{"sales":{"clxdr0p000001prod":{"paid":true,"saleAmountCents":2500,"buyerEmail":"buyer@example.com"}},"orders":{"clxdr0p000001prod":[{"orderId":"clxor0001order","productId":"clxdr0p000001prod","accountId":"clx2f8a1b0001qw3k","externalRef":"tg_48213377","amountCents":2500,"currency":"USD","paidAt":"2026-10-17T16:20:00.000Z","paidWith":"card","status":"paid","buyer":{"id":"clxbu0001buyer","email":"buyer@example.com","telegramUserId":"48213377","telegramUsername":"fan_one"}}]}}}}},"400":{"description":"The body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to check drop status"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/drops/check-status\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"productIds\": [\n    \"clxdr0p000001prod\",\n    \"clxdr0p000002prod\"\n  ]\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/drops/check-status`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"productIds\": [\n      \"clxdr0p000001prod\",\n      \"clxdr0p000002prod\"\n    ]\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/drops/check-status\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"productIds\": [\n            \"clxdr0p000001prod\",\n            \"clxdr0p000002prod\",\n        ],\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/check-drop-status","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops"}},"/api/external/v1/orders":{"get":{"operationId":"listOrders","tags":["drops"],"summary":"List paid orders (per-fan references)","description":"Paid drop orders of the key's account, newest first — the polling twin of the [drop.paid webhook](/developers/webhooks/overview).\n\nFilter by `externalRef` to answer \"did this fan pay?\" on a shared drop, or by `productId` / `since` to sweep. Refunded and charged-back orders stay in the list with their `status` — act on `status: \"paid\"` only.","parameters":[{"name":"productId","in":"query","required":false,"description":"Only orders for this drop.","schema":{"type":"string"},"example":"clxdr0p000001prod"},{"name":"externalRef","in":"query","required":false,"description":"Only orders bought through links carrying this reference.","schema":{"type":"string","maxLength":32,"pattern":"^[A-Za-z0-9_-]{1,32}$"},"example":"tg_48213377"},{"name":"since","in":"query","required":false,"description":"Only orders paid at or after this time.","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"A page of orders.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/Order"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["orders"]},"example":{"orders":[{"orderId":"clxor0001order","productId":"clxdr0p000001prod","accountId":"clx2f8a1b0001qw3k","externalRef":"tg_48213377","amountCents":2750,"currency":"USD","paidAt":"2026-10-17T16:20:00.000Z","paidWith":"card","status":"paid","buyer":{"id":"clxbu0001buyer","email":"buyer@example.com","telegramUserId":"48213377","telegramUsername":"fan_one"}}],"nextCursor":null}}}},"400":{"description":"Malformed reference. Also: Unparseable `since`. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"externalRef must be 1–32 of A-Z a-z 0-9 _ -"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/orders?productId=clxdr0p000001prod&externalRef=tg_48213377\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/orders?productId=clxdr0p000001prod&externalRef=tg_48213377`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/orders\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"productId\": \"clxdr0p000001prod\", \"externalRef\": \"tg_48213377\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-orders","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops"}},"/api/external/v1/posts":{"post":{"operationId":"createPost","tags":["posts"],"summary":"Publish a post to the For You feed","description":"Rate limit: 5 posts per creator per rolling 24 hours. Bursts are fine — only the daily volume is capped. Exceeding it returns 429 with a Retry-After header.\n\nThree shapes:\n  • TEXT   — caption only.\n  • MEDIA  — a gallery of 1-10 images from your vault, each free or paid.\n  • DROP   — attach an existing approved drop by productId.\n\nFor MEDIA, list your vault first (GET /api/external/v1/vault) and use the id\nof an item whose moderationStatus is APPROVED to publish without waiting.\n\nEverything posted here goes through exactly the same moderation as a post written in the web composer: captions run the prohibited-word filter, and media posts stay PENDING until every image clears the NSFW pipeline. You cannot use this API to bypass review.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"caption":{"type":"string","description":"Post text. Required for kind=TEXT. Silently truncated to 2000 characters.","example":"im 5 min away, wyd?","maxLength":2000},"kind":{"type":"string","description":"Post shape. DROP is not a request value — send productId instead.","enum":["TEXT","MEDIA","SUBSCRIPTION","COMMUNITY"],"default":"TEXT"},"productId":{"type":"string","description":"Attach an existing approved drop. Forces kind=DROP. Must belong to you."},"media":{"type":"array","items":{"type":"object","properties":{"vaultItemId":{"type":"string","description":"A vault item you own (GET /api/external/v1/vault)."},"isPaid":{"type":"boolean","description":"Paid items are shown blurred and mint a PPV unlock. Note: posting via API bakes no custom blur preview — paid items fall back to a gaussian blur.","default":false},"price":{"type":"number","description":"USD. Required when isPaid is true. Minimum $5.","minimum":5},"order":{"type":"integer","description":"Display order. Defaults to array index."}},"required":["vaultItemId"],"description":"One gallery entry."},"description":"Required when kind=MEDIA.","maxItems":10},"scheduledAt":{"type":"string","description":"ISO-8601. At least 1 minute ahead, at most 30 days. Omit to publish now.","format":"date-time"}}},"examples":{"text":{"summary":"Text post","value":{"caption":"im 5 min away, wyd?"}},"mediaFree":{"summary":"Free image from the vault","value":{"kind":"MEDIA","caption":"rate my fit 1-10","media":[{"vaultItemId":"clxv1a2b30001item","isPaid":false,"order":0}]}},"mediaPaid":{"summary":"Free teaser + paid unlock, scheduled","value":{"kind":"MEDIA","caption":"can i show you??","scheduledAt":"2026-08-26T19:00:00Z","media":[{"vaultItemId":"clxv1a2b30001item","isPaid":false,"order":0},{"vaultItemId":"clxv1a2b30002item","isPaid":true,"price":10,"order":1}]}}}}}},"responses":{"201":{"description":"Post created. Check `status`: APPROVED means it is already live, PENDING means it is still in review and will go live by itself once it clears.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The new post id — poll GET /api/external/v1/posts/{id} with it.","example":"clxp0st000001feed"},"status":{"type":"string","description":"PENDING is normal, not an error: media posts wait on the NSFW pipeline and a flagged caption waits on a human.","enum":["PENDING","APPROVED"]},"pending":{"type":"boolean","description":"Convenience mirror of status === \"PENDING\"."},"scheduledAt":{"type":["string","null"],"description":"Echoed schedule time, or null for immediate posts.","format":"date-time"},"url":{"type":["string","null"],"description":"The creator’s profile URL (where the post appears once live). Null when the creator has no username yet.","format":"uri"}},"required":["id","status","pending"]},"example":{"id":"clxp0st000001feed","status":"PENDING","pending":true,"scheduledAt":null,"url":"https://www.dropfans.io/u/valeria"}}}},"400":{"description":"The body is not valid JSON. Also: kind=MEDIA without media. Also: More than 10 media entries. Also: A media entry lacks vaultItemId (index varies). Also: isPaid without a valid price (index varies). Also: scheduledAt is not a parseable date. Also: scheduledAt is in the past or under a minute ahead. Also: scheduledAt beyond 30 days. Also: kind=TEXT with an empty caption. Also: productId points at a drop still in moderation — check GET /api/external/v1/drops/{id}. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key belongs to a CONSUMER account. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the For You posts [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Only creators can post"}}}},"404":{"description":"productId does not exist on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"422":{"description":"Caption tripped the prohibited-word filter — rewrite it and retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithMatchedWord"},"example":{"error":"Your post contains a word that isn’t allowed.","matchedWord":"…"}}}},"429":{"description":"Daily posting cap (5 per rolling 24h) reached. Retry-After header = seconds to wait. This is separate from the API rate limit (whose body carries code:\"rate_limited\").","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"You’ve reached the posting limit (5 per day). Try again in …"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/posts\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"caption\": \"im 5 min away, wyd?\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/posts`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"caption\": \"im 5 min away, wyd?\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/posts\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"caption\": \"im 5 min away, wyd?\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-post","x-dropfans-category":"posts","x-dropfans-agency-permission":"canManageDrops"},"get":{"operationId":"listPosts","tags":["posts"],"summary":"List your posts and their moderation status","description":"Your posts, newest first, plus the current posting limits — read `limits` from the response rather than hardcoding numbers.\n\nThe `status` filter takes one moderation state; unrecognised values are silently ignored (you get the unfiltered list, not an error).","parameters":[{"name":"page","in":"query","required":false,"description":"Page number, 1-based.","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","required":false,"description":"Posts per page (default 20, cap 50 — larger values clamped).","schema":{"type":"integer","default":20,"maximum":50}},{"name":"status","in":"query","required":false,"description":"Filter by moderation state (case-insensitive). Unrecognised values are ignored.","schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]}},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Your posts, newest first, plus the current limits.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostListResponse"},"example":{"posts":[{"id":"clxp0st000001feed","kind":"MEDIA","caption":"rate my fit 1-10","status":"APPROVED","live":true,"scheduledAt":null,"publishedAt":"2026-08-18T19:00:00.000Z","createdAt":"2026-08-18T18:59:40.000Z","productId":null,"likes":14,"comments":3,"media":[{"id":"clxpm3d1a0001post","vaultItemId":"clxv1a2b30001item","isPaid":false,"order":0,"type":"image"}]}],"pagination":{"page":1,"limit":20,"total":63,"hasMore":true},"limits":{"postsPerDay":5,"maxCaptionChars":2000,"maxMediaPerPost":10,"maxScheduleDays":30,"minPaidPrice":5}}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the For You posts [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/posts\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/posts`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/posts\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-posts","x-dropfans-category":"posts","x-dropfans-agency-permission":"canManageDrops"}},"/api/external/v1/posts/{id}":{"get":{"operationId":"getPost","tags":["posts"],"summary":"Check one post’s moderation status","description":"One post, as a **bare object** (not wrapped). The polling endpoint after a PENDING create: check `status` and `live`.\n\nA sensible poll cadence is every 30–60 seconds while PENDING; media moderation usually resolves within minutes.","parameters":[{"name":"id","in":"path","required":true,"description":"The post id.","schema":{"type":"string"},"example":"clxp0st000001feed"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The post.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"},"example":{"id":"clxp0st000001feed","kind":"MEDIA","caption":"rate my fit 1-10","status":"APPROVED","live":true,"scheduledAt":null,"publishedAt":"2026-08-18T19:00:00.000Z","createdAt":"2026-08-18T18:59:40.000Z","productId":null,"likes":14,"comments":3,"media":[{"id":"clxpm3d1a0001post","vaultItemId":"clxv1a2b30001item","isPaid":false,"order":0,"type":"image"}]}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the For You posts [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such post on your account. Deliberately 404 (not 403) for another creator’s post — ids cannot be probed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/posts/$POST_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const postId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/posts/${postId}`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\npost_id = \"…\"  # from an earlier response\n\nres = requests.get(\n    f\"https://www.dropfans.io/api/external/v1/posts/{post_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-post","x-dropfans-category":"posts","x-dropfans-agency-permission":"canManageDrops"},"delete":{"operationId":"deletePost","tags":["posts"],"summary":"Delete a post (or cancel a scheduled one)","description":"Hard-deletes one of your posts. Deleting a scheduled post before it goes live cancels it.\n\nReturns `{\"ok\":true}` — note this family uses `ok` where the vault endpoints use `success`.","parameters":[{"name":"id","in":"path","required":true,"description":"The post id.","schema":{"type":"string"},"example":"clxp0st000001feed"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Deleted.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"},"example":{"ok":true}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the For You posts [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such post on your account (another creator’s post also 404s).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/posts/$POST_ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const postId = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/posts/${postId}`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\npost_id = \"…\"  # from an earlier response\n\nres = requests.delete(\n    f\"https://www.dropfans.io/api/external/v1/posts/{post_id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-post","x-dropfans-category":"posts","x-dropfans-agency-permission":"canManageDrops"}},"/api/external/v1/earnings":{"get":{"operationId":"getEarnings","tags":["earnings"],"summary":"Earnings stats, chart and recent transactions","description":"The same revenue the creator sees on their own dashboard: drop sales + tips + subscription payments, refunds and chargebacks excluded, bucketed by day in the caller's timezone.\n\nEverything here is in **cents** (the balance endpoint is dollars). `stats.totalEarningsCents` is NET (after the platform fee); `grossEarningsCents` and the chart series are seller GROSS (buyer-paid minus tax, before the fee) so per-day merges against your own gross ledgers compare like for like. Pass `tz` = the creator's timezone (read it from [GET /api/external/v1/timezone](/developers/reference/get-timezone)) or your day buckets won't match their dashboard.\n\n> [!NOTE] transactions is a fixed cap, not a page\n> `transactions` is always the newest 50 across all three sources. For the complete, paginated ledger with net / fee / VAT per transaction, use [GET /api/external/v1/earnings/transactions](/developers/reference/list-earnings-transactions).","parameters":[{"name":"startDate","in":"query","required":true,"description":"Window start, YYYY-MM-DD, interpreted in `tz`.","schema":{"type":"string","format":"date"},"example":"2026-08-01"},{"name":"endDate","in":"query","required":true,"description":"Window end (inclusive), YYYY-MM-DD, interpreted in `tz`.","schema":{"type":"string","format":"date"},"example":"2026-08-19"},{"name":"tz","in":"query","required":false,"description":"IANA timezone for day bucketing. **Invalid values silently fall back to UTC** — no error.","schema":{"type":"string","default":"UTC","format":"iana-timezone"},"example":"Europe/Stockholm"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Stats, chart and the newest transactions. All money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarningsResponse"},"example":{"stats":{"totalEarningsCents":182050,"grossEarningsCents":214180,"previousPeriodEarningsCents":141200,"previousPeriodGrossEarningsCents":166100,"transactionCount":41,"avgTransactionCents":4440,"uniqueCustomers":28,"typeTotals":{"drop":{"grossCents":150000,"netCents":127500,"count":30},"tip":{"grossCents":44180,"netCents":37550,"count":8},"subscription":{"grossCents":20000,"netCents":17000,"count":3}}},"chart":{"labels":["Aug 18","Aug 19"],"values":[12500,9800],"dates":["2026-08-18","2026-08-19"],"groupBy":"day","typedValues":{"drop":[10000,7500],"tip":[2500,2300],"subscription":[0,0]}},"transactions":[{"id":"clx0rd3r000001sale","productId":"clxdr0p000001prod","productName":"Beach set — 6 photos","amountCents":2000,"grossAmountCents":2500,"buyerEmail":"buyer@example.com","buyerName":null,"paidAt":"2026-08-18T21:03:00.000Z","type":"drop"}]}}}},"400":{"description":"Either date param is missing. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"startDate and endDate query params are required (YYYY-MM-DD)"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch earnings"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/earnings?startDate=2026-08-01&endDate=2026-08-19&tz=Europe%2FStockholm\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/earnings?startDate=2026-08-01&endDate=2026-08-19&tz=Europe%2FStockholm`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/earnings\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"startDate\": \"2026-08-01\", \"endDate\": \"2026-08-19\", \"tz\": \"Europe/Stockholm\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-earnings","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats"}},"/api/external/v1/earnings/summary":{"get":{"operationId":"getEarningsSummary","tags":["earnings"],"summary":"Earnings summary: totals, sources and a day / week series","description":"Totals for all time, this month and your window, a breakdown by source (drop, tip, subscription) and a zero-filled day or week series, in integer cents.\n\nThe same revenue as [GET /api/external/v1/earnings](/developers/reference/get-earnings): refunds and chargebacks are left out, so for the same window and timezone `totals.period` equals its `stats.totalEarningsCents` (net) and `stats.grossEarningsCents` (gross). Each transaction is rounded to cents once, so the `series` always adds up to `totals.period`.\n\nDays are whole local days in `timezone` (DST-aware: a switch day is 23 or 25 hours long). Weeks start on Monday; the first and last week are clipped to your window, and `startsAt` is when each bucket starts inside it.","parameters":[{"name":"startDate","in":"query","required":false,"description":"First local day (YYYY-MM-DD). Defaults to 29 days before `endDate`. At most 366 days per window.","schema":{"type":"string","format":"date"},"example":"2026-10-01"},{"name":"endDate","in":"query","required":false,"description":"Last local day (YYYY-MM-DD), inclusive. Defaults to today in `timezone`.","schema":{"type":"string","format":"date"},"example":"2026-10-31"},{"name":"granularity","in":"query","required":false,"description":"Series bucket: a local day, or a Monday-start week.","schema":{"type":"string","enum":["day","week"],"default":"day"}},{"name":"timezone","in":"query","required":false,"description":"IANA timezone for the days, weeks and \"this month\". `tz` is accepted too. Unlike GET /earnings, an unknown zone is a 400, not UTC.","schema":{"type":"string","default":"UTC","format":"iana-timezone"},"example":"Europe/Stockholm"},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"Totals, breakdown and series. All money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"startDate":{"type":"string","description":"The window’s first day.","format":"date"},"endDate":{"type":"string","description":"The window’s last day (inclusive).","format":"date"},"timezone":{"type":"string","description":"The timezone used."},"granularity":{"type":"string","description":"The series bucket.","enum":["day","week"]},"currency":{"type":"string","description":"Always USD."},"totals":{"type":"object","properties":{"allTime":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Since the account’s first sale."},"thisMonth":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"The current calendar month in `timezone`."},"period":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Your window — equals the sum of `series`."}},"required":["allTime","thisMonth","period"],"description":"`allTime`, `thisMonth` (the current month in `timezone`, up to today) and `period` (your window), each `{ grossCents, netCents, count }`."},"breakdownBySource":{"type":"object","properties":{"drop":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Drop sales."},"tip":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Tips."},"subscription":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Subscription payments (first charges and renewals)."}},"required":["drop","tip","subscription"],"description":"`drop`, `tip` and `subscription` for your window, each `{ grossCents, netCents, count }`."},"series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"The local day, or the Monday the week starts on (can be before `startDate`).","format":"date"},"startsAt":{"type":"string","description":"When the bucket starts, clipped to the window.","format":"date-time"},"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Transactions in the bucket."}},"required":["date","startsAt","grossCents","netCents","count"],"description":"A bucket."},"description":"One point per day or week of the window, oldest first, zero-filled."}},"required":["startDate","endDate","timezone","granularity","currency","totals","breakdownBySource","series"]},"example":{"startDate":"2026-10-26","endDate":"2026-10-27","timezone":"Europe/Stockholm","granularity":"day","currency":"USD","totals":{"allTime":{"grossCents":2480000,"netCents":1984000,"count":912},"thisMonth":{"grossCents":214180,"netCents":182050,"count":41},"period":{"grossCents":22300,"netCents":18950,"count":7}},"breakdownBySource":{"drop":{"grossCents":15000,"netCents":12750,"count":4},"tip":{"grossCents":5300,"netCents":4500,"count":2},"subscription":{"grossCents":2000,"netCents":1700,"count":1}},"series":[{"date":"2026-10-26","startsAt":"2026-10-25T23:00:00.000Z","grossCents":12500,"netCents":10620,"count":4},{"date":"2026-10-27","startsAt":"2026-10-26T23:00:00.000Z","grossCents":9800,"netCents":8330,"count":3}]}}}},"400":{"description":"Unknown `timezone`. Also: Malformed or impossible date (e.g. 2026-02-31). Also: `startDate` is after `endDate`. Also: The window is longer than 366 days. Also: Any other `granularity`. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"timezone must be an IANA timezone name, e.g. Europe/Stockholm","code":"invalid_timezone"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch the earnings summary"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/earnings/summary?startDate=2026-10-01&endDate=2026-10-31&timezone=Europe%2FStockholm\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/earnings/summary?startDate=2026-10-01&endDate=2026-10-31&timezone=Europe%2FStockholm`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/earnings/summary\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"startDate\": \"2026-10-01\", \"endDate\": \"2026-10-31\", \"timezone\": \"Europe/Stockholm\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-earnings-summary","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats"}},"/api/external/v1/earnings/transactions":{"get":{"operationId":"listEarningsTransactions","tags":["earnings"],"summary":"Full transaction ledger (paginated, net per transaction)","description":"Every drop sale, tip and subscription payment of the key's account, newest first, with net, gross, platform fee and VAT per transaction. No cap — follow `nextCursor` until it is null.\n\nSame sources and filters as [GET /api/external/v1/earnings](/developers/reference/get-earnings): refunds and chargebacks are left out, so the `netAmountCents` of a window's pages add up to its `stats.totalEarningsCents` (pass the same window as `since` / `until` instants). Pass `includeReversed=true` to also get refunded and charged-back transactions, with their `status`.\n\nKeep `since`, `until`, `type` and `includeReversed` the same while you follow a cursor.","parameters":[{"name":"since","in":"query","required":false,"description":"Only transactions paid at or after this time.","schema":{"type":"string","format":"date-time"},"example":"2026-10-01T00:00:00Z"},{"name":"until","in":"query","required":false,"description":"Only transactions paid at or before this time.","schema":{"type":"string","format":"date-time"},"example":"2026-10-31T23:59:59.999Z"},{"name":"type","in":"query","required":false,"description":"Comma-separated subset of drop,tip,subscription. Default: all three.","schema":{"type":"string"},"example":"drop,tip"},{"name":"includeReversed","in":"query","required":false,"description":"Also return refunded and charged-back transactions.","schema":{"type":"boolean","default":false}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":100,"minimum":1,"maximum":200}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"A page of transactions. All money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"transactions":{"type":"array","items":{"$ref":"#/components/schemas/LedgerTransaction"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["transactions"]},"example":{"transactions":[{"id":"clx0rd3r000001sale","type":"drop","productId":"clxdr0p000001prod","productName":"Beach set — 6 photos","externalRef":"tg_48213377","amountCents":2000,"netAmountCents":2000,"grossAmountCents":2500,"platformFeeCents":500,"taxCents":250,"totalChargedCents":2750,"currency":"USD","buyerEmail":"buyer@example.com","buyerName":null,"paidAt":"2026-10-18T21:03:00.000Z","status":"paid"}],"nextCursor":"MjAyNi0xMC0xOFQyMTowMzowMC4wMDBafGNseDByZDNyMDAwMDAxc2FsZQ"}}}},"400":{"description":"Unparseable `since` (or `until`). Also: Unknown type. Also: The cursor was not one we returned. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"since must be an ISO date"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/earnings/transactions?since=2026-10-01T00%3A00%3A00Z&until=2026-10-31T23%3A59%3A59.999Z&type=drop%2Ctip\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/earnings/transactions?since=2026-10-01T00%3A00%3A00Z&until=2026-10-31T23%3A59%3A59.999Z&type=drop%2Ctip`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/earnings/transactions\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"since\": \"2026-10-01T00:00:00Z\", \"until\": \"2026-10-31T23:59:59.999Z\", \"type\": \"drop,tip\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-earnings-transactions","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats"}},"/api/external/v1/tips":{"get":{"operationId":"listTips","tags":["earnings"],"summary":"List paid tips (per-fan references)","description":"Paid tips of the key's account, newest first — the polling twin of the [tip.paid webhook](/developers/webhooks/overview).\n\nFilter by `externalRef` to answer \"did this fan tip?\" for a tip link you sent, or by `since` to sweep. Each tip carries the fan's `message`. Refunded and charged-back tips stay in the list with their `status` — act on `status: \"paid\"` only.","parameters":[{"name":"externalRef","in":"query","required":false,"description":"Only tips made through links carrying this reference.","schema":{"type":"string","maxLength":32,"pattern":"^[A-Za-z0-9_-]{1,32}$"},"example":"fan-48213377"},{"name":"since","in":"query","required":false,"description":"Only tips paid at or after this time.","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"A page of tips.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"tips":{"type":"array","items":{"$ref":"#/components/schemas/Tip"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["tips"]},"example":{"tips":[{"tipId":"clxtp0001tip","accountId":"clx2f8a1b0001qw3k","externalRef":"fan-48213377","amountCents":1100,"currency":"USD","message":"For the new set 💕","paidAt":"2026-10-23T16:20:00.000Z","paidWith":"card","status":"paid","tipper":{"id":"clxbu0001buyer","email":"fan@example.com","telegramUserId":"48213377","telegramUsername":"fan_one"}}],"nextCursor":null}}}},"400":{"description":"Malformed reference. Also: Unparseable `since`. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"externalRef must be 1–32 of A-Z a-z 0-9 _ -"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/tips?externalRef=fan-48213377\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/tips?externalRef=fan-48213377`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/tips\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"externalRef\": \"fan-48213377\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-tips","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats"}},"/api/external/v1/links":{"get":{"operationId":"getLinks","tags":["links"],"summary":"The creator’s profile, tip and subscribe links","description":"The creator's shareable links in one call. Never build Dropfans URLs by hand.\n\n**Link ids (`links`).** Every link is just `https://www.dropfans.io/buy/{id}` on the web and `https://t.me/<bot>/app?startapp={id}` in Telegram. There are no parameters on the link. What it opens, the account and your app are stored with the id. `links.profile`, `links.tip` (the fan picks the amount) and `links.subscribe` (opens the subscribe sheet) are created on the first call and returned unchanged after that. For a drop, a fixed tip amount or a per-fan reference, create a link with [POST /api/external/v1/links](/developers/reference/create-link).\n\n**Commission.** With a key that belongs to an app, a drop bought, a tip sent or a subscription started through your app's links earns your app owner commission **for life**, including every renewal of that subscription, at your app's commission rate. Every call also makes your app the account's connected CRM.\n\n**Templates (`web`, `telegram`), deprecated.** These are unchanged and keep working. Fields ending in `Template` have placeholders to fill in: `{usd}` (whole dollars, web tip), `{cents}` (Telegram tip), `{productId}` and `{externalRef}`. A sale through a template link keeps its `externalRef`. One with an `externalRef` counts for a CRM only if it is the only app that has ever generated links for the account, its own key works the account (directly or through its agency), and the account has no personal key. Use link ids for anything new. The `telegram` block is null when the shared Dropfans bot is not configured, and so is each link's `telegram` URL. Web tip prefill: `?tip=<usd>` between $5 and $750; other amounts open the sheet unfilled.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The creator’s links.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Links"},"example":{"username":"valeria","links":{"profile":{"id":"k3x9m2qa7d","type":"profile","url":"https://www.dropfans.io/buy/k3x9m2qa7d","telegram":"https://t.me/DropfansBot/app?startapp=k3x9m2qa7d","productId":null,"amountUsd":null,"externalRef":null,"createdAt":"2026-10-29T12:00:00.000Z"},"tip":{"id":"p0w8n4rt2c","type":"tip","url":"https://www.dropfans.io/buy/p0w8n4rt2c","telegram":"https://t.me/DropfansBot/app?startapp=p0w8n4rt2c","productId":null,"amountUsd":null,"externalRef":null,"createdAt":"2026-10-29T12:00:00.000Z"},"subscribe":{"id":"h5j1v9xs3e","type":"subscribe","url":"https://www.dropfans.io/buy/h5j1v9xs3e","telegram":"https://t.me/DropfansBot/app?startapp=h5j1v9xs3e","productId":null,"amountUsd":null,"externalRef":null,"createdAt":"2026-10-29T12:00:00.000Z"}},"web":{"profile":"https://www.dropfans.io/u/valeria","tip":"https://www.dropfans.io/u/valeria?tip=1","tipTemplate":"https://www.dropfans.io/u/valeria?tip={usd}","tipWithRefTemplate":"https://www.dropfans.io/u/valeria?tip={usd}&m={externalRef}","subscribe":"https://www.dropfans.io/u/valeria?subscribe=1","buyTemplate":"https://www.dropfans.io/buy/{productId}","buyWithRefTemplate":"https://www.dropfans.io/buy/{productId}?m={externalRef}"},"telegram":{"bot":"DropfansBot","profile":"https://t.me/DropfansBot/app?startapp=p_valeria","tip":"https://t.me/DropfansBot/app?startapp=t_valeria","tipTemplate":"https://t.me/DropfansBot/app?startapp=pt_{cents}_valeria","tipWithRefTemplate":"https://t.me/DropfansBot/app?startapp=tm_{cents}_{externalRef}_valeria","subscribe":"https://t.me/DropfansBot/app?startapp=s_valeria","buyTemplate":"https://t.me/DropfansBot/app?startapp=b_{productId}","buyWithRefTemplate":"https://t.me/DropfansBot/app?startapp=b_{productId}_{externalRef}"}}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: Your app has the Links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"409":{"description":"The creator has no username yet. Have the creator pick a handle in their Dropfans settings, then retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Set a username first","code":"username_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/links\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/links`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/links\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-links","x-dropfans-category":"links","x-dropfans-agency-permission":null},"post":{"operationId":"createLink","tags":["links"],"summary":"Create a link for a drop, a tip, a subscription or the profile","description":"Creates one link id. The link is `https://www.dropfans.io/buy/{id}` (web) and `https://t.me/<bot>/app?startapp={id}` (Telegram), with no parameters. The drop, the tip amount and your `externalRef` are stored with the id.\n\n- `buy`: a drop (`productId` from create-drop) opens its checkout. A subscriber-only drop opens the subscribe sheet instead.\n- `tip`: opens the tip sheet, prefilled with `amountUsd` when you set one ($5–$750), or the fan picks.\n- `subscribe`: opens the subscribe sheet. `profile` opens the profile.\n\n`externalRef` (1–32 of `A-Z a-z 0-9 _ -`) comes back on the sale: the `drop.paid` / `tip.paid` webhooks and GET /orders and /tips, together with the link's `linkId`. One link per fan per drop is the usual pattern.\n\nThe same request always returns the same link, so it's safe to call again. With a key that belongs to an app, sales through the link earn your app owner commission for life, and the call makes your app the account's connected CRM.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"What the link opens.","enum":["buy","tip","subscribe","profile"]},"productId":{"type":"string","description":"The drop, for `buy` (required there, refused otherwise). Must belong to the account."},"amountUsd":{"type":"number","description":"Fixed tip amount for `tip` ($5–$750). Omit to let the fan pick."},"externalRef":{"type":"string","description":"Your per-fan reference, returned on the sale.","maxLength":32,"pattern":"^[A-Za-z0-9_-]{1,32}$"}},"required":["type"]},"examples":{"buy":{"summary":"One drop, one fan","value":{"type":"buy","productId":"cmv5tmpcm0015h4oucxkgc4ma","externalRef":"tg_48213377"}},"tip":{"summary":"A $20 tip link","value":{"type":"tip","amountUsd":20,"externalRef":"tg_48213377"}}}}}},"responses":{"200":{"description":"The link (new, or the existing one for this exact request).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"},"example":{"id":"q7m2c8zk4w","type":"buy","url":"https://www.dropfans.io/buy/q7m2c8zk4w","telegram":"https://t.me/DropfansBot/app?startapp=q7m2c8zk4w","productId":"cmv5tmpcm0015h4oucxkgc4ma","amountUsd":null,"externalRef":"tg_48213377","createdAt":"2026-10-29T12:00:00.000Z"}}}},"400":{"description":"Unknown `type`. Also `invalid_external_ref`, `invalid_amount` (out of range, or not a tip) and `invalid_product` (productId on a non-buy link). Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"type must be one of profile, tip, subscribe, buy","code":"invalid_type"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: Your app has the Links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"`productId` is missing, unknown or another account’s.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Drop not found","code":"product_not_found"}}}},"409":{"description":"The creator has no username yet.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Set a username first","code":"username_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/links\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"type\": \"buy\",\n  \"productId\": \"cmv5tmpcm0015h4oucxkgc4ma\",\n  \"externalRef\": \"tg_48213377\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/links`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"type\": \"buy\",\n    \"productId\": \"cmv5tmpcm0015h4oucxkgc4ma\",\n    \"externalRef\": \"tg_48213377\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/links\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"type\": \"buy\",\n        \"productId\": \"cmv5tmpcm0015h4oucxkgc4ma\",\n        \"externalRef\": \"tg_48213377\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-link","x-dropfans-category":"links","x-dropfans-agency-permission":null}},"/api/external/v1/notifications":{"get":{"operationId":"getNotifications","tags":["notifications"],"summary":"Read the Telegram notification status","description":"Where the creator's sale notifications currently go: their saved handle, whether a personal chat is connected, and whether a group/channel is connected.\n\nRead-only and safe. Use it before any write in this group so you never clobber an existing setup.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The current connection state.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationsStatus"},"example":{"telegramHandle":"valeria_tg","personalConnected":true,"groupConnected":false,"groupChatId":null,"groupName":null}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account. Also: Your app has the Telegram notifications [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"The key’s account no longer exists.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"User not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/notifications\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/notifications`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/notifications\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-notifications","x-dropfans-category":"notifications","x-dropfans-agency-permission":"canEditProfile"},"put":{"operationId":"updateNotifications","tags":["notifications"],"summary":"Update Telegram notification settings","description":"An action-dispatch endpoint — the `action` field picks one of three operations:\n\n- `save-handle` — store the creator's Telegram @handle (`telegramHandle`, leading @ stripped).\n- `disconnect` — clear the personal chat, the group, or both (`type`: \"personal\" | \"group\" | \"all\").\n- `add-group` — register a group/channel by chat id (`groupChatId`, e.g. \"-100…\"). The bot must already be a member: the id is verified against Telegram before saving, and private-chat ids are rejected.\n\n> [!WARNING] This rewrites the creator's live notification settings\n> The same fields power the creator's own Dropfans → Telegram sale notifications. Changing them here changes where the creator's notifications go — including notifications your app has nothing to do with. Only call this when the creator explicitly asked for it.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","description":"Which operation to perform.","enum":["save-handle","disconnect","add-group"]},"telegramHandle":{"type":"string","description":"save-handle only: the @handle (leading @ is stripped).","example":"valeria_tg"},"type":{"type":"string","description":"disconnect only: what to clear.","enum":["personal","group","all"]},"groupChatId":{"type":"string","description":"add-group only: the Telegram chat id of a group/channel the bot is in.","example":"-1001234567890"}},"required":["action"]},"examples":{"saveHandle":{"summary":"Save the creator’s handle","value":{"action":"save-handle","telegramHandle":"valeria_tg"}},"addGroup":{"summary":"Register a notification group","value":{"action":"add-group","groupChatId":"-1001234567890"}},"disconnect":{"summary":"Disconnect everything","value":{"action":"disconnect","type":"all"}}}}}},"responses":{"200":{"description":"Action applied. save-handle echoes `telegramHandle`; add-group echoes `groupName`; disconnect returns `{success:true}` alone.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"telegramHandle":{"type":"string","description":"save-handle only: the stored handle (without @)."},"groupName":{"type":"string","description":"add-group only: the group’s title as Telegram reports it."}},"required":["success"]},"example":{"success":true,"groupName":"Valeria sales"}}}},"400":{"description":"The body is not valid JSON. Also: save-handle without a handle. Also: save-handle with an empty handle after stripping @. Also: disconnect with a bad type. Also: add-group without a chat id. Also: Telegram does not know the chat, or the bot is not a member. Also: add-group with a personal chat id. Also: `action` is none of the three. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account. Also: Your app has the Telegram notifications [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PUT \"https://www.dropfans.io/api/external/v1/notifications\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"action\": \"save-handle\",\n  \"telegramHandle\": \"valeria_tg\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/notifications`, {\n  method: 'PUT',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"action\": \"save-handle\",\n    \"telegramHandle\": \"valeria_tg\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.put(\n    \"https://www.dropfans.io/api/external/v1/notifications\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"action\": \"save-handle\",\n        \"telegramHandle\": \"valeria_tg\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-notifications","x-dropfans-category":"notifications","x-dropfans-agency-permission":"canEditProfile"}},"/api/external/v1/register-telegram-chat":{"post":{"operationId":"registerTelegramChat","tags":["notifications"],"summary":"Register the creator’s personal notification chat","description":"Stores a Telegram chat id as the creator's **personal** notification target — the DM their sale notifications go to.\n\nUnlike add-group, the id is **not verified against Telegram** — a wrong id silently breaks the creator's notifications until corrected. Prefer letting the creator connect through the Dropfans dashboard; use this only when your app already knows the correct chat id (e.g. the creator is talking to your bot).\n\n> [!WARNING] This rewrites the creator's live notification settings\n> The same fields power the creator's own Dropfans → Telegram sale notifications. Changing them here changes where the creator's notifications go — including notifications your app has nothing to do with. Only call this when the creator explicitly asked for it.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"telegramChatId":{"type":"string","description":"The Telegram chat id of the creator’s DM with the notification bot. Stored as-is, unverified.","example":"123456789"}},"required":["telegramChatId"]},"examples":{"register":{"summary":"Register a personal chat","value":{"telegramChatId":"123456789"}}}}}},"responses":{"200":{"description":"Stored.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"400":{"description":"The body is not valid JSON. Also: Missing or non-string chat id. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account. Also: Your app has the Telegram notifications [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/register-telegram-chat\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"telegramChatId\": \"123456789\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/register-telegram-chat`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"telegramChatId\": \"123456789\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/register-telegram-chat\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"telegramChatId\": \"123456789\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/register-telegram-chat","x-dropfans-category":"notifications","x-dropfans-agency-permission":"canEditProfile"}},"/api/external/v1/accounts":{"post":{"operationId":"createAccount","tags":["crm"],"summary":"Create a creator account (sign-up from your page)","description":"Creates a creator (or agency) account from your own sign-up page and returns the ID-check link to redirect the creator to.\n\nThe account is created with everything our own onboarding sets — handle, display name, bio, residency, avatar, banner and subscription price — and starts as `pending_kyc`. Send the creator to `kycUrl` (a full-page redirect or a new tab, never an iframe). When they finish, they come back to your `kycReturnUrl` with `?kyc=approved|declined|in_review`. That parameter is only a hint for your UI: the decision arrives as the [account.kyc_updated webhook](/developers/webhooks/overview), and selling is unlocked only once the account is `active`.\n\nThe response also holds an `apiKey` for the new account, bound to your app. Use it straight away to upload media and create drops for the creator. Store it like a password; it is shown once. Your app owner’s own key can also act for the account under [/api/external/v1/creators/{accountId}/…](/developers/concepts/agencies) for as long as the account keeps that key.\n\n**Commission.** Sales made through the links you get from GET /api/external/v1/links for the account (a drop bought, a tip, a subscription and all its renewals) earn your app owner a commission for life — 5% unless agreed otherwise, paid out of our platform fee, never taken from the creator.\n\n**Terms.** Show the creator our Terms of Service, Privacy Policy and 2257 statement and record their acceptance. Send `legalAccepted: true` with the IP address and user agent of **the creator’s browser** at the moment they accepted (not your server’s). We generate the signed acceptance record from them.\n\n> [!NOTE] Owner-held key + the Onboarding category\n> Call this with a key your app owner holds: their own, or one their agency minted for its personas or managed creators. Creator sign-up is the Onboarding [API category](/developers/concepts/api-categories), off for new apps; ask us to switch it on (403 `api_category_disabled` until then).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"The creator’s email. It becomes their sign-in. 409 if it is already registered.","format":"email","example":"valeria@example.com"},"password":{"type":"string","description":"Optional. Leave it out and we email the creator a link to set one (valid 7 days). Either way they get a welcome email.","minLength":8,"maxLength":200},"username":{"type":"string","description":"Public @handle (letters, digits, underscores). 409 when taken.","example":"valeria"},"displayName":{"type":"string","description":"Display name on the profile.","example":"Valeria","maxLength":50},"bio":{"type":"string","description":"Profile bio.","maxLength":500},"location":{"type":"string","description":"Optional profile location line.","maxLength":100},"accountType":{"type":"string","description":"`agency` is for AI-creator operators that run several personas.","enum":["creator","agency"],"default":"creator"},"residencyCountry":{"type":"string","description":"Country of residence, ISO 3166-1 alpha-2. Used for payouts and tax.","example":"SE","pattern":"^[A-Z]{2}$"},"avatarUrl":{"type":"string","description":"https URL of the profile picture (JPEG, PNG or WebP, ≤4 MB). Fetched once, stripped of metadata and moderated like a normal upload. A bad image never fails the sign-up; check `images.avatar`.","format":"uri"},"bannerUrl":{"type":"string","description":"https URL of the profile banner. Same rules as avatarUrl.","format":"uri"},"subscription":{"type":"object","properties":{"priceUsd":{"type":"number","description":"Price in USD dollars, $5–$750.","example":9.99,"minimum":5,"maximum":750},"interval":{"type":"string","description":"Billing period.","enum":["monthly","weekly"],"default":"monthly"},"trialDays":{"type":"integer","description":"Free trial length.","default":0,"minimum":0,"maximum":30}},"required":["priceUsd"],"description":"Optional subscription offer for the profile."},"legalAccepted":{"type":"boolean","description":"Must be `true`: the creator accepted the Terms of Service, Privacy Policy and 2257 statement on your page."},"acceptedFromIp":{"type":"string","description":"The creator’s browser IP at acceptance.","example":"203.0.113.7"},"acceptedUserAgent":{"type":"string","description":"The creator’s browser user agent at acceptance.","maxLength":500},"kycReturnUrl":{"type":"string","description":"https URL the creator returns to after the ID check. We append `?kyc=<status>`.","format":"uri","example":"https://crm.example.com/onboarding/done"}},"required":["email","username","residencyCountry","legalAccepted","acceptedFromIp","acceptedUserAgent"]},"examples":{"creator":{"summary":"A creator with profile and subscription","value":{"email":"valeria@example.com","username":"valeria","displayName":"Valeria","bio":"New sets every Friday.","residencyCountry":"SE","avatarUrl":"https://cdn.example.com/valeria/avatar.jpg","bannerUrl":"https://cdn.example.com/valeria/banner.jpg","subscription":{"priceUsd":9.99,"interval":"monthly","trialDays":0},"legalAccepted":true,"acceptedFromIp":"203.0.113.7","acceptedUserAgent":"Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) …","kycReturnUrl":"https://crm.example.com/onboarding/done"}}}}}},"responses":{"201":{"description":"Created. Redirect the creator to `kycUrl`; keep `accountId` and `apiKey`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","description":"The new account’s id.","example":"clxac0001acct"},"username":{"type":"string","description":"Public @handle (without @).","example":"valeria"},"displayName":{"type":["string","null"],"description":"Display name.","example":"Valeria"},"email":{"type":["string","null"],"description":"Sign-in email.","format":"email"},"accountType":{"type":"string","description":"What the account was created as.","enum":["creator","agency"]},"status":{"type":"string","description":"`pending_kyc` until the ID check is approved, then `active` (can sell and get paid).","enum":["pending_kyc","active"]},"sellerStatus":{"type":"string","description":"Internal seller state, for support (PENDING_KYC, KYC_IN_REVIEW, KYC_REJECTED, VERIFIED_CREATOR, VERIFIED_AGENCY)."},"kycStatus":{"type":"string","description":"ID-check state. `session_created` = link opened, not finished; `processing` = approved, compliance documents still being generated.","enum":["not_started","session_created","in_review","processing","approved","rejected"]},"profileUrl":{"type":"string","description":"Public profile URL.","format":"uri"},"createdAt":{"type":"string","description":"When the account was created.","format":"date-time"},"apiKey":{"type":"string","description":"A key for the new account, bound to your app. Shown once."},"kycUrl":{"type":["string","null"],"description":"The ID-check link. Null if it could not be opened right now; then call create-kyc-session.","format":"uri"},"kycExpiresAt":{"type":["string","null"],"description":"The link is reused until then; ask for a new one after.","format":"date-time"},"referralCredited":{"type":"boolean","description":"True when the account was attributed to your app owner. Commission does not depend on it: it is paid on sales through your app’s links."},"images":{"type":"object","properties":{"avatar":{"type":["string","null"],"description":"Avatar result.","enum":["saved","failed"]},"banner":{"type":["string","null"],"description":"Banner result.","enum":["saved","failed"]}},"description":"What happened to avatarUrl / bannerUrl: \"saved\", \"failed\" or null (not sent)."}},"required":["accountId","username","accountType","status","sellerStatus","kycStatus","profileUrl","createdAt","apiKey","referralCredited","images"]},"example":{"accountId":"clxac0001acct","username":"valeria","displayName":"Valeria","email":"valeria@example.com","accountType":"creator","status":"pending_kyc","sellerStatus":"PENDING_KYC","kycStatus":"session_created","profileUrl":"https://www.dropfans.io/u/valeria","createdAt":"2026-10-17T16:00:00.000Z","apiKey":"dpfn_3f9c…","kycUrl":"https://verify.didit.me/session/…","kycExpiresAt":"2026-10-18T16:00:00.000Z","referralCredited":true,"images":{"avatar":"saved","banner":"saved"}}}}},"400":{"description":"A field failed validation. `field` names it. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"residencyCountry must be an ISO 3166-1 alpha-2 code (e.g. \"SE\").","code":"invalid_input","field":"residencyCountry"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the Creator onboarding [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"409":{"description":"The email is registered. Also: The handle is taken.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"There is already a DropFans account with this email. Sign in instead.","code":"email_taken"}}}},"429":{"description":"Too many sign-ups from your app this hour. `Retry-After` says when to retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"At most 20 sign-ups per hour.","code":"rate_limited"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/accounts\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"email\": \"valeria@example.com\",\n  \"username\": \"valeria\",\n  \"displayName\": \"Valeria\",\n  \"bio\": \"New sets every Friday.\",\n  \"residencyCountry\": \"SE\",\n  \"avatarUrl\": \"https://cdn.example.com/valeria/avatar.jpg\",\n  \"bannerUrl\": \"https://cdn.example.com/valeria/banner.jpg\",\n  \"subscription\": {\n    \"priceUsd\": 9.99,\n    \"interval\": \"monthly\",\n    \"trialDays\": 0\n  },\n  \"legalAccepted\": true,\n  \"acceptedFromIp\": \"203.0.113.7\",\n  \"acceptedUserAgent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) …\",\n  \"kycReturnUrl\": \"https://crm.example.com/onboarding/done\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/accounts`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"email\": \"valeria@example.com\",\n    \"username\": \"valeria\",\n    \"displayName\": \"Valeria\",\n    \"bio\": \"New sets every Friday.\",\n    \"residencyCountry\": \"SE\",\n    \"avatarUrl\": \"https://cdn.example.com/valeria/avatar.jpg\",\n    \"bannerUrl\": \"https://cdn.example.com/valeria/banner.jpg\",\n    \"subscription\": {\n      \"priceUsd\": 9.99,\n      \"interval\": \"monthly\",\n      \"trialDays\": 0\n    },\n    \"legalAccepted\": true,\n    \"acceptedFromIp\": \"203.0.113.7\",\n    \"acceptedUserAgent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) …\",\n    \"kycReturnUrl\": \"https://crm.example.com/onboarding/done\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/accounts\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"email\": \"valeria@example.com\",\n        \"username\": \"valeria\",\n        \"displayName\": \"Valeria\",\n        \"bio\": \"New sets every Friday.\",\n        \"residencyCountry\": \"SE\",\n        \"avatarUrl\": \"https://cdn.example.com/valeria/avatar.jpg\",\n        \"bannerUrl\": \"https://cdn.example.com/valeria/banner.jpg\",\n        \"subscription\": {\n            \"priceUsd\": 9.99,\n            \"interval\": \"monthly\",\n            \"trialDays\": 0,\n        },\n        \"legalAccepted\": True,\n        \"acceptedFromIp\": \"203.0.113.7\",\n        \"acceptedUserAgent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) …\",\n        \"kycReturnUrl\": \"https://crm.example.com/onboarding/done\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-account","x-dropfans-category":"onboarding"},"get":{"operationId":"listAccounts","tags":["crm"],"summary":"List accounts you created","description":"Accounts your app created through create-account, newest first, with their current status.","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of accounts.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"accounts":{"type":"array","items":{"$ref":"#/components/schemas/CrmAccount"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Null on the last page."}},"required":["accounts"]},"example":{"accounts":[{"accountId":"clxac0001acct","username":"valeria","displayName":"Valeria","email":"valeria@example.com","accountType":"creator","status":"pending_kyc","sellerStatus":"PENDING_KYC","kycStatus":"session_created","profileUrl":"https://www.dropfans.io/u/valeria","createdAt":"2026-10-17T16:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint acts as the key’s own account or app — call it without /creators/{creatorId}.","code":"creator_scope_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the Creator onboarding [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/accounts\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/accounts`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/accounts\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-accounts","x-dropfans-category":"onboarding"}},"/api/external/v1/accounts/{id}":{"get":{"operationId":"getAccount","tags":["crm"],"summary":"Get an account you created","description":"Status of one account your app created — `pending_kyc` until the ID check is approved, then `active`.","parameters":[{"name":"id","in":"path","required":true,"description":"The accountId from create-account.","schema":{"type":"string"},"example":"clxac0001acct"}],"responses":{"200":{"description":"The account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmAccount"},"example":{"accountId":"clxac0001acct","username":"valeria","displayName":"Valeria","email":"valeria@example.com","accountType":"creator","status":"pending_kyc","sellerStatus":"PENDING_KYC","kycStatus":"session_created","profileUrl":"https://www.dropfans.io/u/valeria","createdAt":"2026-10-17T16:00:00.000Z"}}}},"400":{"description":"Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint acts as the key’s own account or app — call it without /creators/{creatorId}.","code":"creator_scope_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the Creator onboarding [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"404":{"description":"No such account, or another app created it.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Account not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/accounts/$ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const id = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/accounts/${id}`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nid = \"…\"  # from an earlier response\n\nres = requests.get(\n    f\"https://www.dropfans.io/api/external/v1/accounts/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-account","x-dropfans-category":"onboarding"}},"/api/external/v1/accounts/{id}/kyc-session":{"post":{"operationId":"createKycSession","tags":["crm"],"summary":"Get a fresh ID-check link","description":"The ID-check link for an account you created — when the first one expired, the creator closed it, or the check was declined and they may try again.\n\nA link younger than 24 hours is reused unless you pass a new `kycReturnUrl`.","parameters":[{"name":"id","in":"path","required":true,"description":"The accountId.","schema":{"type":"string"},"example":"clxac0001acct"}],"requestBody":{"required":true,"description":"Optional.","content":{"application/json":{"schema":{"type":"object","properties":{"kycReturnUrl":{"type":"string","description":"https URL to return to; we append `?kyc=<status>`.","format":"uri"},"acceptedFromIp":{"type":"string","description":"The creator’s browser IP, when you have it."},"acceptedUserAgent":{"type":"string","description":"The creator’s browser user agent."}}},"examples":{"retry":{"summary":"New link with a return URL","value":{"kycReturnUrl":"https://crm.example.com/onboarding/done"}}}}}},"responses":{"200":{"description":"The link.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"kycUrl":{"type":"string","description":"Redirect the creator here.","format":"uri"},"kycExpiresAt":{"type":"string","description":"Reused until then.","format":"date-time"},"reused":{"type":"boolean","description":"True when an open session was returned."}},"required":["kycUrl","kycExpiresAt","reused"]},"example":{"kycUrl":"https://verify.didit.me/session/…","kycExpiresAt":"2026-10-18T16:00:00.000Z","reused":false}}}},"400":{"description":"Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint acts as the key’s own account or app — call it without /creators/{creatorId}.","code":"creator_scope_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the Creator onboarding [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"404":{"description":"No such account, or another app created it.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Account not found"}}}},"409":{"description":"Approved (or being finalised) — nothing to do.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"The ID check is already done.","code":"already_verified"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"The verification provider is down.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"The ID check is unavailable right now. Try again later.","code":"kyc_unavailable"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/accounts/$ID/kyc-session\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"kycReturnUrl\": \"https://crm.example.com/onboarding/done\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const id = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/accounts/${id}/kyc-session`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"kycReturnUrl\": \"https://crm.example.com/onboarding/done\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nid = \"…\"  # from an earlier response\n\nres = requests.post(\n    f\"https://www.dropfans.io/api/external/v1/accounts/{id}/kyc-session\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"kycReturnUrl\": \"https://crm.example.com/onboarding/done\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-kyc-session","x-dropfans-category":"onboarding"}},"/api/external/v1/webhooks":{"get":{"operationId":"getWebhook","tags":["crm"],"summary":"Get your webhook endpoint","description":"Your app’s webhook endpoint, its events and the last 20 deliveries (with status codes and errors) — the first place to look when an event seems missing.","responses":{"200":{"description":"The configuration.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConfig"},"example":{"url":"https://crm.example.com/hooks/dropfans","events":["drop.paid","drop.refunded","account.kyc_updated"],"hasSecret":true,"availableEvents":["drop.paid","drop.refunded","tip.paid","tip.refunded","subscription.paid","subscription.canceled","subscription.ended","account.kyc_updated","payout.requested","payout.processing","payout.paid","payout.failed"],"recentDeliveries":[{"id":"evt_2b7c…","event":"drop.paid","status":"DELIVERED","attempts":1,"lastStatusCode":200,"lastError":null,"createdAt":"2026-10-17T16:20:01.000Z","deliveredAt":"2026-10-17T16:20:01.000Z","nextAttemptAt":null}]}}}},"400":{"description":"Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint acts as the key’s own account or app — call it without /creators/{creatorId}.","code":"creator_scope_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the App webhooks [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/webhooks\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/webhooks`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/webhooks\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-webhook","x-dropfans-category":"webhooks"},"put":{"operationId":"setWebhook","tags":["crm"],"summary":"Set your webhook endpoint","description":"Sets the https endpoint that receives your app’s events. The first call also creates the signing secret and returns it **once** as `secret`. Store it; later calls don’t return it (use rotate-webhook-secret).\n\nLeave `events` out to get every event, including ones added later.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Public https URL (no IPs, no localhost, no credentials).","format":"uri","example":"https://crm.example.com/hooks/dropfans"},"events":{"type":"array","items":{"type":"string","description":"Event type.","enum":["drop.paid","drop.refunded","tip.paid","tip.refunded","subscription.paid","subscription.canceled","subscription.ended","account.kyc_updated","payout.requested","payout.processing","payout.paid","payout.failed"]},"description":"Subset of events to receive. Omit for all."}},"required":["url"]},"examples":{"all":{"summary":"All events","value":{"url":"https://crm.example.com/hooks/dropfans"}}}}}},"responses":{"200":{"description":"Saved.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"The saved endpoint.","format":"uri"},"events":{"type":"array","items":{"type":"string","description":"Event type."},"description":"Events delivered."},"secret":{"type":"string","description":"Signing secret (`whsec_…`) — only on the first save."}},"required":["url","events"]},"example":{"url":"https://crm.example.com/hooks/dropfans","events":["drop.paid","drop.refunded","account.kyc_updated"],"secret":"whsec_8d1e…"}}}},"400":{"description":"Not a public https URL, or unknown events. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"url must use https"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the App webhooks [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PUT \"https://www.dropfans.io/api/external/v1/webhooks\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"url\": \"https://crm.example.com/hooks/dropfans\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/webhooks`, {\n  method: 'PUT',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"url\": \"https://crm.example.com/hooks/dropfans\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.put(\n    \"https://www.dropfans.io/api/external/v1/webhooks\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"url\": \"https://crm.example.com/hooks/dropfans\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/set-webhook","x-dropfans-category":"webhooks"},"delete":{"operationId":"deleteWebhook","tags":["crm"],"summary":"Remove your webhook endpoint","description":"Stops deliveries. Events still waiting for a retry are dropped. Poll [GET /api/external/v1/orders](/developers/reference/list-orders) meanwhile.","responses":{"200":{"description":"Removed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","description":"Always true."}},"required":["deleted"]},"example":{"deleted":true}}}},"400":{"description":"Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint acts as the key’s own account or app — call it without /creators/{creatorId}.","code":"creator_scope_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the App webhooks [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/webhooks\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/webhooks`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.delete(\n    \"https://www.dropfans.io/api/external/v1/webhooks\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-webhook","x-dropfans-category":"webhooks"}},"/api/external/v1/webhooks/rotate-secret":{"post":{"operationId":"rotateWebhookSecret","tags":["crm"],"summary":"Rotate the webhook signing secret","description":"Issues a new signing secret and returns it once. Every delivery from now on, including retries, is signed with it. Accept both secrets for a few minutes while you deploy.","responses":{"200":{"description":"The new secret.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"secret":{"type":"string","description":"The new `whsec_…` secret."}},"required":["secret"]},"example":{"secret":"whsec_51aa…"}}}},"400":{"description":"Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint acts as the key’s own account or app — call it without /creators/{creatorId}.","code":"creator_scope_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the App webhooks [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/webhooks/rotate-secret\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/webhooks/rotate-secret`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/webhooks/rotate-secret\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/rotate-webhook-secret","x-dropfans-category":"webhooks"}},"/api/external/v1/webhooks/test":{"post":{"operationId":"testWebhook","tags":["crm"],"summary":"Send a test event","description":"Sends a signed `ping` event to your endpoint and reports what it answered — use it to check your signature verification.","responses":{"200":{"description":"The outcome.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Event id."},"delivered":{"type":"boolean","description":"True when your endpoint answered 2xx."},"statusCode":{"type":["integer","null"],"description":"Your endpoint’s status code."},"error":{"type":["string","null"],"description":"Why it failed."}},"required":["id","delivered"]},"example":{"id":"evt_9f01…","delivered":true,"statusCode":200,"error":null}}}},"400":{"description":"Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint acts as the key’s own account or app — call it without /creators/{creatorId}.","code":"creator_scope_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the App webhooks [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"409":{"description":"No endpoint configured.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Set a webhook URL first (PUT /api/external/webhooks)."}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/webhooks/test\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/webhooks/test`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/webhooks/test\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/test-webhook","x-dropfans-category":"webhooks"}},"/api/external/v1/payouts/summary":{"get":{"operationId":"getPayoutSummary","tags":["payouts"],"summary":"Payout balance, eligibility and status","description":"Everything a \"Pay out\" button needs in one call: balances, the minimum, the payout method and whether a payout request would be accepted right now.\n\nIt returns the balance per bucket and per side, the minimum, the default payout method (masked), the open request, whether a payout is being sent, the upcoming releases, and whether a payout request would be accepted right now.\n\nAll money is integer **cents**. The balance is everything the account owns — its creator side (own sales), agency side (income from managed creators and AI personas), referral commission and partner shares — the same totals as the creator's Payouts page.\n\n`ineligibleReasons` lists **every** gate that fails, in the order [POST /payouts/requests](/developers/reference/create-payout-request) checks them, with the same codes it answers with: `kyc_required`, `payouts_disabled`, `consumer_account`, `no_method`, `masspay_not_activated`, `below_minimum`, `request_open`, `in_flight`.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The summary. Money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayoutSummary"},"example":{"accountId":"clx2f8a1b0001qw3k","currency":"USD","pendingCents":12050,"availableCents":34210,"processingCents":0,"paidOutCents":187500,"sides":{"creator":{"pendingCents":12050,"availableCents":34210,"processingCents":0,"paidOutCents":175500},"agency":{"pendingCents":0,"availableCents":0,"processingCents":0,"paidOutCents":12000},"affiliate":{"pendingCents":0,"availableCents":0,"processingCents":0,"paidOutCents":0},"share":{"pendingCents":0,"availableCents":0,"processingCents":0,"paidOutCents":0}},"requestableCents":34210,"minimumPayoutCents":2000,"payoutsEnabled":true,"kycVerified":true,"defaultMethod":{"id":"clxpm0001method","type":"MASSPAY","isDefault":true,"nickname":null,"label":"Payout wallet · SWE","holderType":"INDIVIDUAL","createdAt":"2026-09-02T10:00:00.000Z","paxum":null,"masspay":{"country":"SWE","currency":null,"payerName":null,"activated":true},"bank":null},"openRequest":null,"inFlight":false,"upcoming":[{"availableOn":"2026-11-04","amountCents":4500}],"eligible":true,"ineligibleReasons":[]}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/payouts/summary\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/summary`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/payouts/summary\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-payout-summary","x-dropfans-category":"payouts","x-dropfans-agency-permission":"canViewStats"}},"/api/external/v1/payouts":{"get":{"operationId":"listPayouts","tags":["payouts"],"summary":"Payout history (paginated)","description":"The account's payout history, newest first — the same rows as the creator's Payouts page, in integer cents.\n\nIt lists payouts sent by Dropfans (`kind: \"payout\"`), payouts recorded by an admin (`\"manual\"`) and payout requests not fulfilled yet (`\"request\"`). Once a request is paid it is replaced by the payout that fulfilled it (`requestId` links them). Money in integer **cents**.\n\nLike the dashboard, payout attempts that never moved money (`failed` / `cancelled`) are left out unless you ask for them with `status`, and a wallet load that was sent back is hidden together with its negative twin unless `includeReversed=true` (the pair nets to zero).\n\nKeep the filters the same while you follow `nextCursor`.","parameters":[{"name":"since","in":"query","required":false,"description":"Only rows created (requests: made) at or after this time.","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"name":"until","in":"query","required":false,"description":"Only rows created at or before this time.","schema":{"type":"string","format":"date-time"}},{"name":"status","in":"query","required":false,"description":"Comma-separated subset of requested, approved, pending, processing, paid, failed, cancelled, rejected. Default: everything except failed / cancelled payout attempts.","schema":{"type":"string"},"example":"paid"},{"name":"kind","in":"query","required":false,"description":"Comma-separated subset of payout, manual, request. Default: all three.","schema":{"type":"string"}},{"name":"includeReversed","in":"query","required":false,"description":"Also return reversed wallet loads and their negative reversal rows.","schema":{"type":"boolean","default":false}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"A page of rows. Money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"payouts":{"type":"array","items":{"$ref":"#/components/schemas/Payout"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["payouts"]},"example":{"payouts":[{"id":"clxpr0001request","kind":"request","status":"requested","amountCents":34210,"currency":"USD","side":"creator","sides":{"creatorCents":34210,"agencyCents":0,"affiliateCents":0,"shareCents":0},"method":{"type":"MASSPAY","label":"Payout wallet · SWE"},"note":"October","failureMessage":null,"invoiceNumber":null,"requestId":null,"payoutId":null,"createdAt":"2026-10-30T09:12:00.000Z","initiatedAt":null,"paidAt":null,"failedAt":null,"reversedAt":null,"reversalOfId":null},{"id":"clxpo0001payout","kind":"payout","status":"paid","amountCents":52000,"currency":"USD","side":"combined","sides":{"creatorCents":40000,"agencyCents":12000,"affiliateCents":0,"shareCents":0},"method":{"type":"PAXUM_P2P","label":"Paxum · j***@example.com"},"note":null,"failureMessage":null,"invoiceNumber":1042,"requestId":"clxpr0000request","payoutId":null,"createdAt":"2026-10-15T08:00:00.000Z","initiatedAt":"2026-10-15T08:00:05.000Z","paidAt":"2026-10-15T08:03:41.000Z","failedAt":null,"reversedAt":null,"reversalOfId":null}],"nextCursor":null}}}},"400":{"description":"Unparseable `since` (`invalid_until` for `until`). Also: Unknown status (`invalid_kind` for an unknown kind). Also: `limit` out of range. Also: The cursor was not one we returned. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"since must be an ISO date","code":"invalid_since"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/payouts?since=2026-01-01T00%3A00%3A00Z&status=paid\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/payouts?since=2026-01-01T00%3A00%3A00Z&status=paid`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/payouts\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"since\": \"2026-01-01T00:00:00Z\", \"status\": \"paid\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-payouts","x-dropfans-category":"payouts","x-dropfans-agency-permission":"canViewStats"}},"/api/external/v1/payouts/{id}":{"get":{"operationId":"getPayout","tags":["payouts"],"summary":"One payout or payout request","description":"One row of the history by id — a payout, a manual payout or a payout request — in any status, including failed attempts, fulfilled requests and reversal rows.\n\nThe same shape as the [payout.* webhooks](/developers/webhooks/overview) (which add `accountId`).","parameters":[{"name":"id","in":"path","required":true,"description":"Row id from the list, a webhook or POST /payouts/requests.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The row. Money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payout"},"example":{"id":"clxpo0001payout","kind":"payout","status":"paid","amountCents":52000,"currency":"USD","side":"combined","sides":{"creatorCents":40000,"agencyCents":12000,"affiliateCents":0,"shareCents":0},"method":{"type":"PAXUM_P2P","label":"Paxum · j***@example.com"},"note":null,"failureMessage":null,"invoiceNumber":1042,"requestId":"clxpr0000request","payoutId":null,"createdAt":"2026-10-15T08:00:00.000Z","initiatedAt":"2026-10-15T08:00:05.000Z","paidAt":"2026-10-15T08:03:41.000Z","failedAt":null,"reversedAt":null,"reversalOfId":null}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"Unknown id, or it belongs to another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Payout not found","code":"not_found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/payouts/$ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const id = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/${id}`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nid = \"…\"  # from an earlier response\n\nres = requests.get(\n    f\"https://www.dropfans.io/api/external/v1/payouts/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-payout","x-dropfans-category":"payouts","x-dropfans-agency-permission":"canViewStats"}},"/api/external/v1/payouts/methods":{"get":{"operationId":"listPayoutMethods","tags":["payouts"],"summary":"Payout methods (masked)","description":"The account's payout methods, default first, with every destination masked.\n\nAdd a Paxum method with [POST /payouts/methods](/developers/reference/create-payout-method), the MassPay wallet with [POST /payouts/masspay/profile](/developers/reference/setup-masspay-wallet); the creator can also manage them in the dashboard.\n\nNothing that moves money is returned: the Paxum e-mail is masked (`j***@example.com`), a bank account shows its last 4 characters only, and MassPay tokens are never included.","parameters":[{"$ref":"#/components/parameters/XDropfansAccount"}],"responses":{"200":{"description":"The methods.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"methods":{"type":"array","items":{"$ref":"#/components/schemas/PayoutMethodSummary"},"description":"Default first, then newest first."}},"required":["methods"]},"example":{"methods":[{"id":"clxpm0001method","type":"PAXUM_P2P","isDefault":true,"nickname":null,"label":"Paxum · j***@example.com","holderType":"INDIVIDUAL","createdAt":"2026-09-02T10:00:00.000Z","paxum":{"email":"j***@example.com","lookupStatus":"active","verificationStatus":"COMPLETED"},"masspay":null,"bank":null}]}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/payouts/methods\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/methods`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/payouts/methods\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-payout-methods","x-dropfans-category":"payouts","x-dropfans-agency-permission":"canViewStats"},"post":{"operationId":"createPayoutMethod","tags":["payouts"],"summary":"Add a Paxum payout method","description":"Add a Paxum account as a payout method — what \"Add Paxum\" does in the dashboard, with a stricter e-mail check.\n\nThe e-mail is looked up at Paxum and must be an **active** Paxum account: unknown or inactive accounts are refused with 422 `paxum_account_not_active` (the dashboard shows that on the card; an integration has nobody to show it to). If Paxum cannot be reached the answer is 502 `paxum_unavailable` — retry.\n\n**Safe to retry, no `Idempotency-Key` needed:** adding an e-mail the account already has (case-insensitive) returns that existing method with 200 and `Idempotent-Replayed: true` instead of a duplicate; `nickname` / `isDefault` are then not applied (use PATCH).\n\n`isDefault: true` makes it the method payouts go to. A MassPay wallet is set up with [POST /payouts/masspay/profile](/developers/reference/setup-masspay-wallet) instead.\n\nThe key's own account only (`X-Dropfans-Account` and agency-minted keys are refused) and only after the ID check (403 `kyc_required`).\n\n> [!NOTE] Needs the Payouts category and an app key\n> Payouts are an [API category](/developers/concepts/api-categories) that is off for every app until we switch it on — ask support. Personal keys can read payouts but get 403 `app_key_required` here.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"The method type. Only `PAXUM_P2P` is created here.","enum":["PAXUM_P2P"]},"paxumEmail":{"type":"string","description":"The e-mail of the creator’s Paxum account. Never returned unmasked.","format":"email","example":"jane@example.com","maxLength":254},"nickname":{"type":["string","null"],"description":"The creator’s own label, shown instead of the masked e-mail.","maxLength":100},"isDefault":{"type":"boolean","description":"Make it the default payout method.","default":false}},"required":["type","paxumEmail"]},"examples":{"paxum":{"summary":"Paxum as the default method","value":{"type":"PAXUM_P2P","paxumEmail":"jane@example.com","nickname":"Main Paxum","isDefault":true}}}}}},"responses":{"201":{"description":"The method was added (200 with `Idempotent-Replayed: true` when the account already had this e-mail).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"},"Idempotent-Replayed":{"description":"`true` when the method already existed (status 200).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"$ref":"#/components/schemas/PayoutMethodSummary"}},"required":["method"]},"example":{"method":{"id":"clxpm0002method","type":"PAXUM_P2P","isDefault":true,"nickname":"Main Paxum","label":"Main Paxum","holderType":"INDIVIDUAL","createdAt":"2026-10-30T10:00:00.000Z","paxum":{"email":"j***@example.com","lookupStatus":"active","verificationStatus":null},"masspay":null,"bank":null}}}}},"400":{"description":"`paxumEmail` missing or not an e-mail. Also: `type` missing or another type (MASSPAY: use POST /payouts/masspay/profile). Also: A field that is not in the table (`invalid_nickname` / `invalid_is_default` for a wrong type or length). Also: The body is not valid JSON (`invalid_body` when it is not an object). Also: `X-Dropfans-Account` names another account. An agency can never change where a creator it manages is paid. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"paxumEmail is not a valid email","code":"invalid_paxum_email"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The account has not passed the ID check. Also: The key was minted by an agency for an account it manages. Also: A personal key (not bound to an app). Personal keys may read payouts, but not change them. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Verify your identity (KYC) before setting up payouts.","code":"kyc_required"}}}},"409":{"description":"Another payout operation holds the account’s payout lock. Retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Another payout operation is running for this account. Try again in a moment.","code":"payout_busy"}}}},"422":{"description":"The e-mail is not an active Paxum account (`lookupStatus`: `not_found` or `inactive`).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"No Paxum account uses this e-mail. Check it, or create the Paxum account first.","code":"paxum_account_not_active","lookupStatus":"not_found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"The Paxum lookup failed. Retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not reach Paxum to check the e-mail. Try again in a moment.","code":"paxum_unavailable"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/payouts/methods\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"type\": \"PAXUM_P2P\",\n  \"paxumEmail\": \"jane@example.com\",\n  \"nickname\": \"Main Paxum\",\n  \"isDefault\": true\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/methods`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"type\": \"PAXUM_P2P\",\n    \"paxumEmail\": \"jane@example.com\",\n    \"nickname\": \"Main Paxum\",\n    \"isDefault\": true\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/payouts/methods\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"type\": \"PAXUM_P2P\",\n        \"paxumEmail\": \"jane@example.com\",\n        \"nickname\": \"Main Paxum\",\n        \"isDefault\": True,\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-payout-method","x-dropfans-category":"payouts"}},"/api/external/v1/payouts/methods/{id}":{"patch":{"operationId":"updatePayoutMethod","tags":["payouts"],"summary":"Change a payout method","description":"Rename a payout method, make it the default (or stop using it as the default), or point a Paxum method at another Paxum e-mail.\n\nSend only what changes. Any other field is refused with 400 `unknown_field`. A new `paxumEmail` is looked up again like on create (422 `paxum_account_not_active` unless active) and clears the method's earlier Paxum identity check, which was for the old account. `isDefault: true` moves the default here; `isDefault: false` leaves the account without a default method.\n\nThe key's own account only, after the ID check.\n\n> [!NOTE] Needs the Payouts category and an app key\n> Payouts are an [API category](/developers/concepts/api-categories) that is off for every app until we switch it on — ask support. Personal keys can read payouts but get 403 `app_key_required` here.","parameters":[{"name":"id","in":"path","required":true,"description":"The method id (from GET /payouts/methods).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nickname":{"type":["string","null"],"description":"New label; null or \"\" clears it.","maxLength":100},"isDefault":{"type":"boolean","description":"true: make it the default. false: no longer the default."},"paxumEmail":{"type":"string","description":"`PAXUM_P2P` only: the new Paxum e-mail.","format":"email"}}},"examples":{"makeDefault":{"summary":"Make it the default","value":{"isDefault":true}}}}}},"responses":{"200":{"description":"The updated method.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"$ref":"#/components/schemas/PayoutMethodSummary"}},"required":["method"]},"example":{"method":{"id":"clxpm0002method","type":"PAXUM_P2P","isDefault":true,"nickname":"Main Paxum","label":"Main Paxum","holderType":"INDIVIDUAL","createdAt":"2026-10-30T10:00:00.000Z","paxum":{"email":"j***@example.com","lookupStatus":"active","verificationStatus":null},"masspay":null,"bank":null}}}}},"400":{"description":"A field that cannot be changed (`invalid_nickname`, `invalid_is_default`, `invalid_paxum_email` for bad values). Also: `paxumEmail` on a MassPay wallet. Also: The body is not valid JSON (`invalid_body` when it is not an object). Also: `X-Dropfans-Account` names another account. An agency can never change where a creator it manages is paid. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unknown field: bankIban. Allowed: nickname, isDefault, paxumEmail.","code":"unknown_field"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The account has not passed the ID check. Also: The key was minted by an agency for an account it manages. Also: A personal key (not bound to an app). Personal keys may read payouts, but not change them. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Verify your identity (KYC) before setting up payouts.","code":"kyc_required"}}}},"404":{"description":"Unknown id, or it belongs to another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Not found","code":"not_found"}}}},"422":{"description":"The new e-mail is not an active Paxum account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This Paxum account is not active. Activate it at Paxum first.","code":"paxum_account_not_active","lookupStatus":"inactive"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"The Paxum lookup failed. Retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not reach Paxum to check the e-mail. Try again in a moment.","code":"paxum_unavailable"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X PATCH \"https://www.dropfans.io/api/external/v1/payouts/methods/$ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"isDefault\": true\n}'"},{"lang":"JavaScript","label":"Node","source":"const id = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/methods/${id}`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"isDefault\": true\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nid = \"…\"  # from an earlier response\n\nres = requests.patch(\n    f\"https://www.dropfans.io/api/external/v1/payouts/methods/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"isDefault\": True,\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-payout-method","x-dropfans-category":"payouts"},"delete":{"operationId":"deletePayoutMethod","tags":["payouts"],"summary":"Remove a payout method","description":"Remove a payout method — refused with 409 `method_in_use` while a payout to it is still pending or processing.\n\nPayouts already made keep their own masked copy of the destination, so the history is unaffected. Removing the MassPay wallet does not close the payee at MassPay: setting the wallet up again re-attaches it. The key's own account only, after the ID check.\n\n> [!NOTE] Needs the Payouts category and an app key\n> Payouts are an [API category](/developers/concepts/api-categories) that is off for every app until we switch it on — ask support. Personal keys can read payouts but get 403 `app_key_required` here.","parameters":[{"name":"id","in":"path","required":true,"description":"The method id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Removed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The removed method."},"deleted":{"type":"boolean","description":"Always true."}},"required":["id","deleted"]},"example":{"id":"clxpm0002method","deleted":true}}}},"400":{"description":"`X-Dropfans-Account` names another account. An agency can never change where a creator it manages is paid. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint only acts as the key’s own account — send it without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The account has not passed the ID check. Also: The key was minted by an agency for an account it manages. Also: A personal key (not bound to an app). Personal keys may read payouts, but not change them. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Verify your identity (KYC) before setting up payouts.","code":"kyc_required"}}}},"404":{"description":"Unknown id, or it belongs to another account (also on a repeated delete).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Not found","code":"not_found"}}}},"409":{"description":"A payout to this method is pending or processing.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Cannot delete: this method is attached to active payouts. Wait for them to settle.","code":"method_in_use"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X DELETE \"https://www.dropfans.io/api/external/v1/payouts/methods/$ID\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const id = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/methods/${id}`, {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nid = \"…\"  # from an earlier response\n\nres = requests.delete(\n    f\"https://www.dropfans.io/api/external/v1/payouts/methods/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-payout-method","x-dropfans-category":"payouts"}},"/api/external/v1/payouts/masspay/profile":{"get":{"operationId":"getMasspayProfile","tags":["payouts"],"summary":"MassPay payout profile","description":"The MassPay payout profile behind the payout wallet, read live from MassPay, with the required fields it still lacks in `missingFields`.\n\nBefore the payee exists (`provisioned: false`) the profile is a prefill from the account (name, e-mail, country) for your form. A payee created automatically at the ID check often has no address yet: `missingFields` then lists what [POST /payouts/masspay/profile](/developers/reference/setup-masspay-wallet) has to send. Personal data — the key's own account only.\n\n> [!NOTE] Needs the Payouts category and an app key\n> Payouts are an [API category](/developers/concepts/api-categories) that is off for every app until we switch it on — ask support. Personal keys can read payouts but get 403 `app_key_required` here.","responses":{"200":{"description":"The profile.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"provisioned":{"type":"boolean","description":"True once the payee exists at MassPay."},"status":{"type":["string","null"],"description":"MassPay’s status for the payee (e.g. ACTIVE). Null before it exists."},"missingFields":{"type":"array","items":{"type":"string","description":"A profile field name.","enum":["businessName","firstName","middleName","lastName","email","mobileNumber","language","dateOfBirth","country","address1","address2","city","stateProvince","postalCode"]},"description":"Required fields blank at MassPay. Empty when complete (and before the payee exists)."},"profile":{"$ref":"#/components/schemas/MasspayProfile"}},"required":["provisioned","missingFields","profile"]},"example":{"provisioned":true,"status":"ACTIVE","missingFields":["address1","city","stateProvince","postalCode"],"profile":{"accountType":"INDIVIDUAL","businessName":"","firstName":"Jane","middleName":"","lastName":"Doe","email":"jane@example.com","mobileNumber":"46701234567","language":"en","dateOfBirth":"1994-05-17","country":"SWE","address1":"","address2":"","city":"","stateProvince":"","postalCode":""}}}}},"400":{"description":"`X-Dropfans-Account` names another account. An agency can never change where a creator it manages is paid. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint only acts as the key’s own account — send it without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key was minted by an agency for an account it manages. Also: A personal key (not bound to an app). Personal keys may read payouts, but not change them. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Payout methods need the account’s own key — a key an agency minted for a managed account cannot read or change where payouts go.","code":"agency_key_not_allowed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"MassPay did not answer. Retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not read your MassPay profile. Try again in a moment.","code":"masspay_unavailable"}}}},"503":{"description":"MassPay payouts are switched off on this environment.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"MassPay is not available right now.","code":"not_configured"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/payouts/masspay/profile\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/masspay/profile`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/payouts/masspay/profile\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-masspay-profile","x-dropfans-category":"payouts"},"post":{"operationId":"setupMasspayWallet","tags":["payouts"],"summary":"Set up the MassPay wallet","description":"Set up the account's MassPay payout wallet from the same profile the dashboard's setup form collects, and make it the default payout method.\n\n**Required:** `firstName`, `lastName`, `email`, `country`, `address1`, `city`, `stateProvince`, `postalCode`, plus `businessName` when `accountType` is `BUSINESS`. **Optional:** `middleName`, `mobileNumber`, `language`, `dateOfBirth`, `address2`. Enter everything as on the payee's government-issued ID. Every field is checked before anything is sent to MassPay; a refused profile answers 400 `invalid_profile` naming the first bad `field`, with all of them in `errors`.\n\n- **No payee yet** → the payee is created at MassPay with the full profile (201).\n- **Payee exists but lacks required details** (see `missingFields` on [GET /payouts/masspay/profile](/developers/reference/get-masspay-profile)) → the fields you send fill them in. `country`, `email` and `businessName` stay as MassPay has them; send at least the missing fields.\n- **Payee complete** → the body is not needed; the wallet is (re)attached.\n\n**Activation:** before the first payout to the wallet, the payee must open `activationUrl` once in a browser (a MassPay requirement). The link expires — get a fresh one from [GET /payouts/masspay/activation](/developers/reference/get-masspay-activation) when you send the payee there. Payout requests to a wallet that is not activated are refused (`masspay_not_activated`).\n\nSafe to retry: there is one MassPay payee and one wallet per account. The key's own account only, after the ID check.\n\n> [!NOTE] Needs the Payouts category and an app key\n> Payouts are an [API category](/developers/concepts/api-categories) that is off for every app until we switch it on — ask support. Personal keys can read payouts but get 403 `app_key_required` here.","requestBody":{"required":true,"description":"The payout profile. Optional when the payee already exists and is complete.","content":{"application/json":{"schema":{"type":"object","properties":{"accountType":{"type":"string","description":"Who the payee is. `BUSINESS` makes `businessName` required; the person fields are then the authorized representative’s.","enum":["INDIVIDUAL","BUSINESS"],"default":"INDIVIDUAL"},"businessName":{"type":"string","description":"**Required when `accountType` is BUSINESS.** The company’s registered legal name. Its presence is what makes the payee a business account at MassPay; the person fields are then the authorized representative’s. Cannot be changed once set.","example":"Jane Doe Media AB","maxLength":150},"firstName":{"type":"string","description":"As on the government-issued ID.","example":"Jane","maxLength":100},"middleName":{"type":"string","description":"Optional. As on the ID.","maxLength":100},"lastName":{"type":"string","description":"As on the ID.","example":"Doe","maxLength":100},"email":{"type":"string","description":"Must not be used by another MassPay account.","format":"email","example":"jane@example.com","maxLength":254},"mobileNumber":{"type":"string","description":"Optional. With country code; 7–15 digits once spaces and symbols are removed.","example":"+46 70 123 45 67","maxLength":32},"language":{"type":"string","description":"Optional. ISO 639-1 code for MassPay’s e-mails and portal (default \"en\").","example":"en","maxLength":2},"dateOfBirth":{"type":"string","description":"Optional. YYYY-MM-DD, a real date; the payee must be at least 18.","format":"date","example":"1994-05-17","maxLength":10},"country":{"type":"string","description":"ISO 3166-1 alpha-3 country of residence.","example":"SWE","maxLength":3},"address1":{"type":"string","description":"Street address.","example":"Storgatan 1","maxLength":150},"address2":{"type":"string","description":"Optional. Apartment, suite, c/o.","maxLength":150},"city":{"type":"string","description":"City.","example":"Stockholm","maxLength":100},"stateProvince":{"type":"string","description":"State, province, county or region.","example":"Stockholm County","maxLength":100},"postalCode":{"type":"string","description":"Postal / ZIP code.","example":"111 22","maxLength":20}},"required":["firstName","lastName","email","country","address1","city","stateProvince","postalCode"]},"examples":{"individual":{"summary":"An individual","value":{"accountType":"INDIVIDUAL","firstName":"Jane","lastName":"Doe","email":"jane@example.com","country":"SWE","address1":"Storgatan 1","city":"Stockholm","stateProvince":"Stockholm County","postalCode":"111 22","dateOfBirth":"1994-05-17","language":"sv"}},"complete":{"summary":"Completing an existing payee","value":{"address1":"Storgatan 1","city":"Stockholm","stateProvince":"Stockholm County","postalCode":"111 22"}}}}}},"responses":{"201":{"description":"The wallet was attached (201 when the wallet method was created, 200 when an existing one was re-attached).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"$ref":"#/components/schemas/PayoutMethodSummary"},"activationUrl":{"type":["string","null"],"description":"Where the payee activates the wallet (once, in a browser). Null when already activated. Expires.","format":"uri"},"created":{"type":"boolean","description":"True when the MassPay payee was created by this call."},"completed":{"type":"boolean","description":"True when missing profile fields were filled in at MassPay by this call."}},"required":["method","created","completed"]},"example":{"method":{"id":"clxpm0001method","type":"MASSPAY","isDefault":true,"nickname":null,"label":"Payout wallet · SWE","holderType":"INDIVIDUAL","createdAt":"2026-10-30T10:00:00.000Z","paxum":null,"masspay":{"country":"SWE","currency":null,"payerName":null,"activated":false},"bank":null},"activationUrl":"https://payee.masspay.io/activate/…","created":true,"completed":false}}}},"400":{"description":"A field is missing or invalid. Codes in `errors`: required, too_long, invalid_type, invalid_account_type, invalid_email, invalid_country, invalid_date_of_birth, under_18, invalid_mobile_number, invalid_language. Also: The body is not valid JSON (`invalid_body` when it is not an object). Also: `X-Dropfans-Account` names another account. An agency can never change where a creator it manages is paid. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"City is required.","code":"invalid_profile","field":"city","errors":[{"field":"city","code":"required","message":"City is required."}]}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The account has not passed the ID check. Also: The key was minted by an agency for an account it manages. Also: A personal key (not bound to an app). Personal keys may read payouts, but not change them. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Verify your identity (KYC) before setting up payouts.","code":"kyc_required"}}}},"409":{"description":"An existing payee has no usable country. Contact support.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not determine your payout country. Contact support.","code":"no_country"}}}},"422":{"description":"MassPay refused the profile (`masspay_rejected` with MassPay’s reason for other refusals).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This email is already used by another MassPay account. Enter a different email.","code":"masspay_email_in_use"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"MassPay did not answer. Retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not read your MassPay profile. Try again in a moment.","code":"masspay_unavailable"}}}},"503":{"description":"MassPay payouts are switched off on this environment.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"MassPay is not available right now.","code":"not_configured"}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/payouts/masspay/profile\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"accountType\": \"INDIVIDUAL\",\n  \"firstName\": \"Jane\",\n  \"lastName\": \"Doe\",\n  \"email\": \"jane@example.com\",\n  \"country\": \"SWE\",\n  \"address1\": \"Storgatan 1\",\n  \"city\": \"Stockholm\",\n  \"stateProvince\": \"Stockholm County\",\n  \"postalCode\": \"111 22\",\n  \"dateOfBirth\": \"1994-05-17\",\n  \"language\": \"sv\"\n}'"},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/masspay/profile`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    \"accountType\": \"INDIVIDUAL\",\n    \"firstName\": \"Jane\",\n    \"lastName\": \"Doe\",\n    \"email\": \"jane@example.com\",\n    \"country\": \"SWE\",\n    \"address1\": \"Storgatan 1\",\n    \"city\": \"Stockholm\",\n    \"stateProvince\": \"Stockholm County\",\n    \"postalCode\": \"111 22\",\n    \"dateOfBirth\": \"1994-05-17\",\n    \"language\": \"sv\"\n  }),\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/payouts/masspay/profile\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    json={\n        \"accountType\": \"INDIVIDUAL\",\n        \"firstName\": \"Jane\",\n        \"lastName\": \"Doe\",\n        \"email\": \"jane@example.com\",\n        \"country\": \"SWE\",\n        \"address1\": \"Storgatan 1\",\n        \"city\": \"Stockholm\",\n        \"stateProvince\": \"Stockholm County\",\n        \"postalCode\": \"111 22\",\n        \"dateOfBirth\": \"1994-05-17\",\n        \"language\": \"sv\",\n    },\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/setup-masspay-wallet","x-dropfans-category":"payouts"}},"/api/external/v1/payouts/masspay/activation":{"get":{"operationId":"getMasspayActivation","tags":["payouts"],"summary":"MassPay wallet activation","description":"Whether the payee has activated the MassPay wallet and, if not, a fresh `activationUrl` to send them to.\n\nThe payee opens it once in a browser; MassPay refuses payouts to the wallet until then. The link expires, so fetch it right before you show it, and never store it. Once activated, `activated` stays true. The link signs the payee in: the key's own account only.\n\n> [!NOTE] Needs the Payouts category and an app key\n> Payouts are an [API category](/developers/concepts/api-categories) that is off for every app until we switch it on — ask support. Personal keys can read payouts but get 403 `app_key_required` here.","responses":{"200":{"description":"The activation state.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"provisioned":{"type":"boolean","description":"True when the account has a MassPay payee."},"activated":{"type":"boolean","description":"True once the payee finished activation."},"activationUrl":{"type":["string","null"],"description":"The activation link while not activated; null otherwise.","format":"uri"}},"required":["provisioned","activated"]},"example":{"provisioned":true,"activated":false,"activationUrl":"https://payee.masspay.io/activate/…"}}}},"400":{"description":"`X-Dropfans-Account` names another account. An agency can never change where a creator it manages is paid. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint only acts as the key’s own account — send it without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key was minted by an agency for an account it manages. Also: A personal key (not bound to an app). Personal keys may read payouts, but not change them. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Payout methods need the account’s own key — a key an agency minted for a managed account cannot read or change where payouts go.","code":"agency_key_not_allowed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"MassPay did not answer (503 when unreachable). Retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"MassPay request failed","code":"masspay_unavailable","provisioned":true,"activated":false,"activationUrl":null}}}}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/payouts/masspay/activation\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/masspay/activation`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/payouts/masspay/activation\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-masspay-activation","x-dropfans-category":"payouts"}},"/api/external/v1/payouts/requests":{"post":{"operationId":"createPayoutRequest","tags":["payouts"],"summary":"Request a payout","description":"Request a payout of the account's **full** available balance — exactly what \"Pay out funds\" does in the dashboard.\n\nOne request is created per side (creator, agency, affiliate, share) that has money and no open request; each is reviewed and paid on its own. There is no amount: partial payouts are not possible.\n\n**`Idempotency-Key` header required** (1–255 printable characters, e.g. a UUID per payout you intend). Sending the same key with the same body again returns the original requests (201, with `Idempotent-Replayed: true`) instead of a second payout; the same key with a different body is refused with 409 `idempotency_conflict`. Keys are scoped to the account **and your app** (or, for a personal key, that key), so another app can never replay or block yours. A second call with the same key while the first is still running gets 409 `payout_busy`; retry it and it replays the first one's answer. Retry network errors with the same key.\n\nChecked in this order, each with its own `code`: ID check (`kyc_required`) → payouts enabled (`payouts_disabled`) → not a buyer account (`consumer_account`) → a default payout method (`no_method`) → the payout wallet activated if the method is a MassPay wallet (`masspay_not_activated`) → the minimum (`below_minimum`) → no open request (`request_open`) → no payout being sent (`in_flight`). [GET /payouts/summary](/developers/reference/get-payout-summary) reports the same gates up front.\n\nThe key's own account only: `X-Dropfans-Account` is refused, and so is a key an agency minted for an account it manages (403 `agency_key_not_allowed`) — an agency can never request a payout for a creator it manages.\n\n> [!NOTE] Needs the Payouts category and an app key\n> Payouts are an [API category](/developers/concepts/api-categories) that is off for every app until we switch it on — ask support. Personal keys can read payouts but get 403 `app_key_required` here.","requestBody":{"required":true,"description":"Optional — an empty body is fine.","content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":["string","null"],"description":"A note for the Dropfans team, shown with the request.","maxLength":500}}},"examples":{"withNote":{"summary":"With a note","value":{"note":"October"}}}}}},"responses":{"201":{"description":"The requests created (or, on a replay, the original ones).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"},"Idempotent-Replayed":{"description":"`true` when this answers a repeated Idempotency-Key.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayoutRequest"},"example":{"requests":[{"id":"clxpr0001request","kind":"request","status":"requested","amountCents":34210,"currency":"USD","side":"creator","sides":{"creatorCents":34210,"agencyCents":0,"affiliateCents":0,"shareCents":0},"method":{"type":"MASSPAY","label":"Payout wallet · SWE"},"note":"October","failureMessage":null,"invoiceNumber":null,"requestId":null,"payoutId":null,"createdAt":"2026-10-30T09:12:00.000Z","initiatedAt":null,"paidAt":null,"failedAt":null,"reversedAt":null,"reversalOfId":null}]}}}},"400":{"description":"No `Idempotency-Key` header (`invalid_idempotency_key` when it is malformed). Also: `note` is not a string or too long. Also: The body is not valid JSON. Also: No default payout method. Also: The default method is a MassPay wallet the payee has not activated yet. Also: The available balance is below the account’s minimum (or not positive). Also: `X-Dropfans-Account` names another account. An agency can never request or cancel a payout for a creator it manages. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Send an Idempotency-Key header (a unique value per payout request, e.g. a UUID).","code":"idempotency_key_required"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The account has not passed the ID check. Also: Dropfans has paused payouts for the account. Also: A buyer account. Also: The key was minted by an agency for an account it manages. Also: A personal key (not bound to an app). Personal keys may read payouts, but not change them. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Verify your identity (KYC) before requesting a payout.","code":"kyc_required"}}}},"409":{"description":"Every side with money already has an open request. Also: A payout is pending or processing. Also: Another payout operation holds the account’s payout lock (e.g. a concurrent request). Retry with the same key. Also: The key was used before with another body.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"You already have a payout request awaiting review.","code":"request_open"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/payouts/requests\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"note\":\"October\"}'"},{"lang":"JavaScript","label":"Node","source":"import { randomUUID } from 'node:crypto';\n\n// Keep the key with your record of this payout and reuse it on retries.\nconst idempotencyKey = randomUUID();\nconst res = await fetch('https://www.dropfans.io/api/external/v1/payouts/requests', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n    'Idempotency-Key': idempotencyKey,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ note: 'October' }),\n});\nconst data = await res.json();\nif (!res.ok) throw new Error(`${res.status} ${data.code}: ${data.error}`);\nconsole.log(data.requests);"},{"lang":"Python","source":"import os, uuid, requests\n\n# Keep the key with your record of this payout and reuse it on retries.\nidempotency_key = str(uuid.uuid4())\nres = requests.post(\n    \"https://www.dropfans.io/api/external/v1/payouts/requests\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\",\n        \"Idempotency-Key\": idempotency_key,\n    },\n    json={\"note\": \"October\"},\n)\nres.raise_for_status()\nprint(res.json()[\"requests\"])"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-payout-request","x-dropfans-category":"payouts"}},"/api/external/v1/payouts/requests/{id}/cancel":{"post":{"operationId":"cancelPayoutRequest","tags":["payouts"],"summary":"Cancel a payout request","description":"Cancel one of the account's payout requests while it is still `requested`.\n\nIts side can be requested again straight away. Once a request is `approved` or `processing` (Paxum requests are `processing` from the moment they are made — the mass-payout file may already be paid) it is on its way and can no longer be cancelled; nor once it is paid, rejected or cancelled. The answer is then 409 `request_not_cancellable` — so repeating a cancel is harmless.\n\nThe key's own account only (`X-Dropfans-Account` and agency-minted keys are refused).\n\n> [!NOTE] Needs the Payouts category and an app key\n> Payouts are an [API category](/developers/concepts/api-categories) that is off for every app until we switch it on — ask support. Personal keys can read payouts but get 403 `app_key_required` here.","parameters":[{"name":"id","in":"path","required":true,"description":"The request id (`kind: \"request\"`).","schema":{"type":"string"}}],"responses":{"200":{"description":"The cancelled request.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payout"},"example":{"id":"clxpr0001request","kind":"request","status":"cancelled","amountCents":34210,"currency":"USD","side":"creator","sides":{"creatorCents":34210,"agencyCents":0,"affiliateCents":0,"shareCents":0},"method":{"type":"MASSPAY","label":"Payout wallet · SWE"},"note":"October","failureMessage":null,"invoiceNumber":null,"requestId":null,"payoutId":null,"createdAt":"2026-10-30T09:12:00.000Z","initiatedAt":null,"paidAt":null,"failedAt":null,"reversedAt":null,"reversalOfId":null}}}},"400":{"description":"`X-Dropfans-Account` names another account. An agency can never request or cancel a payout for a creator it manages. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint only acts as the key’s own account — send it without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key was minted by an agency for an account it manages. Also: A personal key (not bound to an app). Personal keys may read payouts, but not change them. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Payout requests need the account’s own key — a key an agency minted for a managed account cannot request or cancel payouts.","code":"agency_key_not_allowed"}}}},"404":{"description":"Unknown id, or it belongs to another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Not found","code":"not_found"}}}},"409":{"description":"Approved or processing (on its way), or already paid, rejected or cancelled.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This request is already being paid out and can no longer be cancelled.","code":"request_not_cancellable"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl -X POST \"https://www.dropfans.io/api/external/v1/payouts/requests/$ID/cancel\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const id = '…'; // from an earlier response\n\nconst res = await fetch(`https://www.dropfans.io/api/external/v1/payouts/requests/${id}/cancel`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nid = \"…\"  # from an earlier response\n\nres = requests.post(\n    f\"https://www.dropfans.io/api/external/v1/payouts/requests/{id}/cancel\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/cancel-payout-request","x-dropfans-category":"payouts"}},"/api/external/v1/crm/app":{"get":{"operationId":"getCrmApp","tags":["crm"],"summary":"Get your app","description":"Your app as we know it: name, logo, status, commission terms and which API categories are switched on. Always the app the key is bound to.","responses":{"200":{"description":"Your app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmApp"},"example":{"id":"clxap0001app","name":"Acme CRM","logoUrl":"https://cdn.example.com/acme/logo.png","status":"approved","commission":{"rate":0.05,"types":["drop","tip","subscription"]},"apiCategories":[{"id":"account","label":"Account","enabled":true,"locked":true},{"id":"payouts","label":"Payouts","enabled":false,"locked":false}]}}}},"400":{"description":"`X-Dropfans-Account` was sent. These endpoints always answer for the key’s app. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint only acts as the key’s own account — send it without X-Dropfans-Account.","code":"account_header_not_allowed"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the CRM dashboard [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/crm/app\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/crm/app`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/crm/app\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-crm-app","x-dropfans-category":"crm"}},"/api/external/v1/crm/stats":{"get":{"operationId":"getCrmStats","tags":["crm"],"summary":"Dashboard stats","description":"Your integration dashboard’s Dashboard tab as data: revenue, booked commission, sales and new accounts, as totals plus zero-filled hour, day, week or month buckets.\n\nIt returns revenue through your app’s links, the commission booked for your app owner, sales and newly connected accounts. The numbers are the dashboard’s own: same sales, same day boundaries (Europe/Stockholm unless you pass `tz`), same automatic bucket size. Amounts are integer **US cents, excluding tax, before our platform fee**; refunded and charged-back sales are left out. `earningsCents` is the commission **booked** on those sales — it is paid out with your app owner’s earnings, so booked is not the same as already paid.","parameters":[{"name":"startDate","in":"query","required":true,"description":"First day, YYYY-MM-DD (inclusive, in `tz`).","schema":{"type":"string","format":"date"},"example":"2026-10-01"},{"name":"endDate","in":"query","required":true,"description":"Last day, YYYY-MM-DD (inclusive, in `tz`). At most 366 days after startDate.","schema":{"type":"string","format":"date"},"example":"2026-10-30"},{"name":"tz","in":"query","required":false,"description":"IANA time zone the calendar days (and buckets) are cut in. Defaults to Europe/Stockholm, like your dashboard.","schema":{"type":"string","default":"Europe/Stockholm","format":"iana-timezone"},"example":"America/New_York"},{"name":"granularity","in":"query","required":false,"description":"Bucket size. Leave it out for the dashboard’s automatic pick (hour for one day, day up to 30 days, week up to 90, month beyond). `hour` is allowed for up to 3 days.","schema":{"type":"string","enum":["hour","day","week","month"]}}],"responses":{"200":{"description":"Totals and the bucket series.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmStats"},"example":{"startDate":"2026-10-27","endDate":"2026-10-29","tz":"Europe/Stockholm","granularity":"day","currency":"USD","totals":{"revenueCents":6000,"earningsCents":300,"transactions":4,"newConnectedAccounts":1,"connectedAccountsNow":18},"series":[{"bucket":"2026-10-27","start":"2026-10-26T23:00:00.000Z","revenueCents":0,"earningsCents":0,"transactions":0,"newConnectedAccounts":0},{"bucket":"2026-10-28","start":"2026-10-27T23:00:00.000Z","revenueCents":4500,"earningsCents":225,"transactions":3,"newConnectedAccounts":1},{"bucket":"2026-10-29","start":"2026-10-28T23:00:00.000Z","revenueCents":1500,"earningsCents":75,"transactions":1,"newConnectedAccounts":0}]}}}},"400":{"description":"`startDate` / `endDate` missing (stats) or not a YYYY-MM-DD day. Also: `endDate` is before `startDate`. Also: More than 366 days. Also: Unknown `tz`. Also: `granularity=hour` over more than 3 days, or an unknown granularity. Also: `X-Dropfans-Account` was sent. These endpoints always answer for the key’s app. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"startDate must be a real calendar day, YYYY-MM-DD.","code":"invalid_input","field":"startDate"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the CRM dashboard [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/crm/stats?startDate=2026-10-01&endDate=2026-10-30&tz=America%2FNew_York\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/crm/stats?startDate=2026-10-01&endDate=2026-10-30&tz=America%2FNew_York`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/crm/stats\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"startDate\": \"2026-10-01\", \"endDate\": \"2026-10-30\", \"tz\": \"America/New_York\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-crm-stats","x-dropfans-category":"crm"}},"/api/external/v1/crm/transactions":{"get":{"operationId":"listCrmTransactions","tags":["crm"],"summary":"List sales through your app","description":"Your integration dashboard’s Transactions tab: every sale through your app’s links across all your accounts, newest first, with the commission booked on each.\n\nDrop sales, tips and subscription payments are all included. Refunded and charged-back sales are included by default with their `status` (like the dashboard); pass `includeReversed=false` to leave them out. Window by exact instants (`since` / `until`) or by calendar days (`startDate` / `endDate` in `tz`), not both. Page with `cursor`.","parameters":[{"name":"since","in":"query","required":false,"description":"Only sales paid at or after this instant (ISO 8601).","schema":{"type":"string","format":"date-time"}},{"name":"until","in":"query","required":false,"description":"Only sales paid at or before this instant (ISO 8601).","schema":{"type":"string","format":"date-time"}},{"name":"startDate","in":"query","required":false,"description":"Instead of since/until: first day, YYYY-MM-DD, in `tz`. Needs endDate.","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","required":false,"description":"Last day, YYYY-MM-DD, in `tz` (at most 366 days).","schema":{"type":"string","format":"date"}},{"name":"tz","in":"query","required":false,"description":"IANA time zone the calendar days (and buckets) are cut in. Defaults to Europe/Stockholm, like your dashboard.","schema":{"type":"string","default":"Europe/Stockholm","format":"iana-timezone"},"example":"America/New_York"},{"name":"type","in":"query","required":false,"description":"Comma-separated subset of `drop,tip,subscription`. Default: all.","schema":{"type":"string"},"example":"drop,tip"},{"name":"includeReversed","in":"query","required":false,"description":"`false` leaves refunded and charged-back sales out.","schema":{"type":"boolean","default":true}},{"name":"limit","in":"query","required":false,"description":"Page size (clamped to the range).","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page, unchanged. Keep the other parameters the same.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of sales.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"currency":{"type":"string","description":"Currency of every *Cents field.","enum":["USD"]},"transactions":{"type":"array","items":{"$ref":"#/components/schemas/CrmTransaction"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["currency","transactions"]},"example":{"currency":"USD","transactions":[{"id":"clxor0001ord","type":"drop","paidAt":"2026-10-29T18:42:11.000Z","transactionId":"cb_8812734","linkId":"k3v9x2m1qa","amountCents":1500,"crmEarnedCents":75,"status":"paid","creator":{"id":"clxac0001acct","username":"valeria","name":"Valeria"}}],"nextCursor":"MjAyNi0xMC0yOVQxODo0MjoxMS4wMDBafGNseG9yMDAwMW9yZA"}}}},"400":{"description":"Both windows were sent. Also: Unparseable `since` / `until`, or `until` before `since`. Also: `startDate` / `endDate` missing (stats) or not a YYYY-MM-DD day. Also: `endDate` is before `startDate`. Also: More than 366 days. Also: Unknown `tz`. Also: Unknown `type`. Also: Anything else. Also: Malformed `cursor`. Also: `X-Dropfans-Account` was sent. These endpoints always answer for the key’s app. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"Use since/until or startDate/endDate, not both.","code":"invalid_input","field":"since"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the CRM dashboard [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/crm/transactions?tz=America%2FNew_York&type=drop%2Ctip\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/crm/transactions?tz=America%2FNew_York&type=drop%2Ctip`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/crm/transactions\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n    params={\"tz\": \"America/New_York\", \"type\": \"drop,tip\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-crm-transactions","x-dropfans-category":"crm"}},"/api/external/v1/crm/accounts":{"get":{"operationId":"listCrmAccounts","tags":["crm"],"summary":"List your connected accounts","description":"Your integration dashboard’s Accounts tab: every account your app has generated links for, with its all-time sales through your links and the commission booked on them.\n\nAccounts that sold through your links without you generating them are listed too.\n\nAn account is `connected` while your app is the one that generated its links most recently. When another CRM generated them after you, `movedAway.at` says when; which CRM is never disclosed. Agencies are the sum of their `children` (their creators and their own sales as a creator); pass `flat=true` to get only those rows, each with `agencyId`, so that a column sums without double counting.\n\nAmounts are integer US cents, excluding tax, before our platform fee; refunded and charged-back sales are left out.","parameters":[{"name":"flat","in":"query","required":false,"description":"`true`: no nesting — plain accounts plus every agency’s rows, each with `agencyId`; agency sum rows left out.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Every account, connected first, then by sales through your links.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"currency":{"type":"string","description":"Currency of every *Cents field.","enum":["USD"]},"accounts":{"type":"array","items":{"$ref":"#/components/schemas/CrmConnectedAccount"},"description":"Connected first, then by viaLinksCents."},"totals":{"$ref":"#/components/schemas/CrmAccountsTotals"}},"required":["currency","accounts","totals"]},"example":{"currency":"USD","accounts":[{"id":"clxac0001acct","username":"valeria","name":"Valeria","kind":"account","connected":true,"connectedAt":"2026-10-17T16:05:00.000Z","movedAway":null,"links":4,"allTimeGrossCents":250000,"viaLinksCents":64000,"crmEarnedCents":3200},{"id":"clxac0002acct","username":"nora","name":"Nora","kind":"account","connected":false,"connectedAt":"2026-09-02T10:00:00.000Z","movedAway":{"at":"2026-10-20T08:30:00.000Z"},"links":2,"allTimeGrossCents":90000,"viaLinksCents":12000,"crmEarnedCents":600}],"totals":{"links":6,"allTimeGrossCents":340000,"viaLinksCents":76000,"crmEarnedCents":3800}}}}},"400":{"description":"Anything else. Also: `X-Dropfans-Account` was sent. These endpoints always answer for the key’s app. Also: Called under /api/external/v1/creators/{creatorId}/ — this endpoint always acts as the key’s own account, agency or app.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"flat must be true or false.","code":"invalid_input","field":"flat"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"A Personal key was used. Also: The key was minted by a creator for themselves. App-level calls need a key held by your app owner: their own, or one their agency minted for its personas or managed creators. Also: Your app has the CRM dashboard [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-codeSamples":[{"lang":"cURL","label":"curl","source":"curl \"https://www.dropfans.io/api/external/v1/crm/accounts\" \\\n  -H \"Authorization: Bearer $DROPFANS_API_KEY\""},{"lang":"JavaScript","label":"Node","source":"const res = await fetch(`https://www.dropfans.io/api/external/v1/crm/accounts`, {\n  headers: {\n    Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,\n  },\n});\nconsole.log(await res.json());"},{"lang":"Python","source":"import os\nimport requests\n\nres = requests.get(\n    \"https://www.dropfans.io/api/external/v1/crm/accounts\",\n    headers={\"Authorization\": f\"Bearer {os.environ['DROPFANS_API_KEY']}\"},\n)\nprint(res.json())"}],"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-crm-accounts","x-dropfans-category":"crm"}},"/api/external/v1/creators/{creatorId}/me":{"get":{"operationId":"getMeForCreator","tags":["account"],"summary":"Which creator this API key belongs to (for a creator)","description":"Same as `getMe` (GET /api/external/v1/me), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key).","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The key’s creator account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"},"example":{"id":"clx2f8a1b0001qw3k","username":"valeria","name":"Valeria","image":"https://cdn.dropfans.io/valeria/profile.jpg","accountType":"CREATOR","sellerStatus":"VERIFIED_CREATOR","isAgency":false,"kycStatus":"approved","key":{"name":"KVIQA","app":{"slug":"kviqa","name":"KVIQA"},"tier":"app","managedBy":null,"viaAgency":false}}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-me","x-dropfans-category":"account","x-dropfans-agency-permission":null,"x-dropfans-mirror-of":"getMe"}},"/api/external/v1/creators/{creatorId}/profile":{"get":{"operationId":"getProfileForCreator","tags":["account"],"summary":"Read the creator’s public profile (for a creator)","description":"Same as `getProfile` (GET /api/external/v1/profile), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key).","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The profile.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","username":"luna_ai","displayName":"Luna","bio":"Your favourite AI muse ✨","profileVisible":true,"location":null,"websiteUrl":null,"twitterHandle":null,"instagramHandle":"luna.ai","tiktokHandle":null,"snapchatHandle":null,"threadsHandle":null,"youtubeHandle":null,"telegramHandle":"luna_ai","whatsappNumber":null,"imessageHandle":null,"primaryContactPlatform":"telegram","avatarUrl":"https://cdn.dropfans.io/luna_ai/profile.jpg?token=…","bannerUrl":null,"avatarModerationStatus":"APPROVED","bannerModerationStatus":null}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"The account no longer exists.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Account not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-profile","x-dropfans-category":"account","x-dropfans-agency-permission":null,"x-dropfans-mirror-of":"getProfile"},"patch":{"operationId":"updateProfileForCreator","tags":["account"],"summary":"Update the creator’s public profile (for a creator)","description":"Same as `updateProfile` (PATCH /api/external/v1/profile), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canEditProfile`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","description":"New @handle: 3–30 of lowercase letters, digits, `_` and `-`.","example":"luna_ai","pattern":"^[a-z0-9_-]{3,30}$"},"displayName":{"type":"string","description":"Display name. Cannot be empty or null.","example":"Luna","maxLength":80},"bio":{"type":["string","null"],"description":"Profile bio.","maxLength":2000},"profileVisible":{"type":"boolean","description":"Show or hide the public profile."},"location":{"type":["string","null"],"description":"Free-text location.","maxLength":120},"websiteUrl":{"type":["string","null"],"description":"Website link.","maxLength":300},"twitterHandle":{"type":["string","null"],"description":"X / Twitter handle.","maxLength":100},"instagramHandle":{"type":["string","null"],"description":"Instagram handle.","maxLength":100},"tiktokHandle":{"type":["string","null"],"description":"TikTok handle.","maxLength":100},"snapchatHandle":{"type":["string","null"],"description":"Snapchat handle.","maxLength":100},"threadsHandle":{"type":["string","null"],"description":"Threads handle.","maxLength":100},"youtubeHandle":{"type":["string","null"],"description":"YouTube handle.","maxLength":100},"telegramHandle":{"type":["string","null"],"description":"Telegram handle.","maxLength":100},"whatsappNumber":{"type":["string","null"],"description":"WhatsApp number.","maxLength":40},"imessageHandle":{"type":["string","null"],"description":"iMessage handle.","maxLength":100},"primaryContactPlatform":{"type":["string","null"],"description":"Which contact platform the profile highlights.","maxLength":40},"avatarUrl":{"type":["string","null"],"description":"Public https URL of the new profile image (Dropfans fetches and moderates it). null removes the image.","format":"uri"},"bannerUrl":{"type":["string","null"],"description":"Public https URL of the new banner image. null removes it.","format":"uri"}}},"examples":{"bio":{"summary":"New bio and avatar","value":{"bio":"Your favourite AI muse ✨","avatarUrl":"https://cdn.example.com/luna/avatar.jpg"}}}}}},"responses":{"200":{"description":"The updated profile.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"},"example":{"id":"cmh4v2q8k0003xy9z7w6v5u4t","username":"luna_ai","displayName":"Luna","bio":"Your favourite AI muse ✨","profileVisible":true,"location":null,"websiteUrl":null,"twitterHandle":null,"instagramHandle":"luna.ai","tiktokHandle":null,"snapchatHandle":null,"threadsHandle":null,"youtubeHandle":null,"telegramHandle":"luna_ai","whatsappNumber":null,"imessageHandle":null,"primaryContactPlatform":"telegram","avatarUrl":"https://cdn.dropfans.io/luna_ai/profile.jpg?token=…","bannerUrl":null,"avatarModerationStatus":"APPROVED","bannerModerationStatus":null}}}},"400":{"description":"A field that is not in the list above. Also: Wrong type, too long, an empty displayName, or an image URL that is not https. Also: A text field tripped the word filter. Also: Malformed or reserved username. Also: The image URL did not return an image. Earlier fields in the same call are already saved. Also: The body is not a JSON object. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"Unknown profile field(s): nickname","code":"unknown_field","field":"nickname"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"Profile editing is locked for this account. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Profile editing is restricted for this account.","code":"profile_locked"}}}},"409":{"description":"Another account has that username.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithField"},"example":{"error":"Username is already taken.","code":"username_taken","field":"username"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-profile","x-dropfans-category":"account","x-dropfans-agency-permission":"canEditProfile","x-dropfans-mirror-of":"updateProfile"}},"/api/external/v1/creators/{creatorId}/timezone":{"get":{"operationId":"getTimezoneForCreator","tags":["account"],"summary":"Read the creator’s timezone (for a creator)","description":"Same as `getTimezone` (GET /api/external/v1/timezone), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key).","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The creator’s timezone.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Timezone"},"example":{"timezone":"Europe/Stockholm"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-timezone","x-dropfans-category":"account","x-dropfans-agency-permission":null,"x-dropfans-mirror-of":"getTimezone"},"put":{"operationId":"updateTimezoneForCreator","tags":["account"],"summary":"Set the creator’s timezone (for a creator)","description":"Same as `updateTimezone` (PUT /api/external/v1/timezone), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canEditProfile`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"timezone":{"type":"string","description":"IANA timezone name, e.g. \"Europe/Stockholm\". Abbreviations like \"CET\" are not accepted.","format":"iana-timezone","example":"Europe/Stockholm"}},"required":["timezone"]},"examples":{"stockholm":{"summary":"Set to Stockholm time","value":{"timezone":"Europe/Stockholm"}}}}}},"responses":{"200":{"description":"The saved timezone, echoed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Timezone"},"example":{"timezone":"Europe/Stockholm"}}}},"400":{"description":"Missing, non-string, or not a recognised IANA timezone name. Also: The request body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid timezone"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-timezone","x-dropfans-category":"account","x-dropfans-agency-permission":"canEditProfile","x-dropfans-mirror-of":"updateTimezone"}},"/api/external/v1/creators/{creatorId}/subscription":{"get":{"operationId":"getSubscriptionForCreator","tags":["account"],"summary":"Read the creator’s subscription tier (for a creator)","description":"Same as `getSubscription` (GET /api/external/v1/subscription), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The tier and subscribe link.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"},"example":{"tier":{"priceUsd":9.99,"currency":"USD","interval":"monthly","trialDays":0,"description":"All my sets, first.","pitchMessage":null,"isActive":true},"subscribeUrl":"https://www.dropfans.io/u/luna_ai?subscribe=1"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-subscription","x-dropfans-category":"account","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"getSubscription"},"put":{"operationId":"updateSubscriptionForCreator","tags":["account"],"summary":"Set the creator’s subscription tier (for a creator)","description":"Same as `updateSubscription` (PUT /api/external/v1/subscription), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canEditProfile`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"priceUsd":{"type":"number","description":"USD dollars per interval. 0 = free; otherwise $5–$750. Rounded to cents.","example":9.99,"minimum":0,"maximum":750},"interval":{"type":"string","description":"Billing interval.","enum":["monthly","weekly"],"example":"monthly"},"trialDays":{"type":"integer","description":"Free trial length in days.","default":0,"minimum":0,"maximum":30},"description":{"type":"string","description":"What subscribers get (cut at 500 characters).","maxLength":500},"pitchMessage":{"type":"string","description":"Short pitch shown in the subscribe sheet (cut at 500 characters).","maxLength":500},"isActive":{"type":"boolean","description":"false pauses new sign-ups.","default":true}},"required":["priceUsd","interval"]},"examples":{"monthly":{"summary":"$9.99 a month","value":{"priceUsd":9.99,"interval":"monthly","description":"All my sets, first."}}}}}},"responses":{"200":{"description":"The saved tier.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"tier":{"$ref":"#/components/schemas/SubscriptionTier"}},"required":["tier"]},"example":{"tier":{"priceUsd":9.99,"currency":"USD","interval":"monthly","trialDays":0,"description":"All my sets, first.","pitchMessage":null,"isActive":true}}}}},"400":{"description":"`priceUsd` missing, not a number or negative. Also: Priced above 0 but below $5. Also: Priced above $750. Also: Missing or unknown interval. Also: Bad trial length. Also: `isActive` is not a boolean. Also: The body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"priceUsd must be 0 (free) or at least 5"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-subscription","x-dropfans-category":"account","x-dropfans-agency-permission":"canEditProfile","x-dropfans-mirror-of":"updateSubscription"}},"/api/external/v1/creators/{creatorId}/balance":{"get":{"operationId":"getBalanceForCreator","tags":["account"],"summary":"The account’s payout balance (for a creator)","description":"Same as `getBalance` (GET /api/external/v1/balance), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"Balance buckets in USD dollars.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"},"example":{"currency":"USD","pending":120.5,"available":300.1,"processing":0,"paidOut":1755,"total":{"pending":120.5,"available":342.1,"processing":0,"paidOut":1875},"sides":{"creator":{"pending":120.5,"available":300.1,"processing":0,"paidOut":1755},"agency":{"pending":0,"available":42,"processing":0,"paidOut":120},"affiliate":{"pending":0,"available":0,"processing":0,"paidOut":0},"share":{"pending":0,"available":0,"processing":0,"paidOut":0}}}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Balance computation failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch balance"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-balance","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"getBalance"}},"/api/external/v1/creators/{creatorId}/vault":{"get":{"operationId":"listVaultForCreator","tags":["vault"],"summary":"List your vault items — the source of media for posts (for a creator)","description":"Same as `listVault` (GET /api/external/v1/vault), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"page","in":"query","required":false,"description":"Page number, 1-based.","schema":{"type":"integer","default":1},"example":1},{"name":"limit","in":"query","required":false,"description":"Items per page. Hard cap 50 — larger values are clamped, not rejected.","schema":{"type":"integer","default":50,"maximum":50}},{"name":"folderId","in":"query","required":false,"description":"`\"all\"` (default), `\"unfiled\"`, or a folder id from the folders list.","schema":{"type":"string"},"example":"all"},{"name":"includePending","in":"query","required":false,"description":"Pass the literal string `true` to also get PENDING and FLAGGED items (REJECTED never appears). Those items come back with `filePath: \"\"` and `downloadUrl: null` — thumbnail only — and each item gains a `moderationStatus` field.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Vault items, folders and pagination.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaultListResponse"},"example":{"items":[{"id":"clxv1a2b30001item","fileName":"beach-set-01.jpg","filePath":"https://cdn.dropfans.io/valeria/vault/1721990000-ab12cd.jpg","thumbnailPath":"https://cdn.dropfans.io/valeria/thumbnails/1721990000-ab12cd.jpg","fileType":"image","fileSize":482113,"durationSeconds":null,"bunnyStreamId":null,"createdAt":"2026-08-01T10:15:00.000Z","folderId":"clxf0ld3r0001abcd","contentTags":["beach","bikini"],"downloadUrl":null}],"folders":[{"id":"clxf0ld3r0001abcd","name":"Beach set","itemCount":12}],"hasMore":true,"total":128,"page":1,"limit":50}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch vault items"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-vault","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"listVault"},"post":{"operationId":"uploadVaultItemForCreator","tags":["vault"],"summary":"Upload an image, small video or voice message (for a creator)","description":"Same as `uploadVaultItem` (POST /api/external/v1/vault), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"fileType":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"originalName":{"type":"string","description":"The file’s name, stored as fileName.","example":"beach-set-01.jpg"},"folderId":{"type":"string","description":"Optional folder to file the item into."},"durationSeconds":{"type":"integer","description":"Audio only — the voice message length in seconds (capped at 3600).","maximum":3600},"displayFile":{"type":"string","contentMediaType":"application/octet-stream","description":"Images only (required): the pre-compressed JPEG display copy."},"thumbnailFile":{"type":"string","contentMediaType":"application/octet-stream","description":"Images only (required): the JPEG thumbnail."},"file":{"type":"string","contentMediaType":"application/octet-stream","description":"Video/audio only (required): the media file. Audio ≤20MB; video effectively ≤~4MB here — use the TUS flow for anything bigger."}},"required":["fileType","originalName"]},"examples":{"image":{"summary":"Image upload (display + thumbnail parts)","value":{"fileType":"image","originalName":"beach-set-01.jpg","displayFile":"@photo.jpg","thumbnailFile":"@photo-thumb.jpg"}},"audio":{"summary":"Voice message","value":{"fileType":"audio","originalName":"voice-note.ogg","durationSeconds":42,"file":"@voice-note.ogg"}}}}}},"responses":{"200":{"description":"Uploaded. The item starts PENDING moderation (not included in this shape — poll the list with includePending=true, or wait for it to appear in the default list).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"item":{"$ref":"#/components/schemas/VaultItemUploaded"}},"required":["success","item"]},"example":{"success":true,"item":{"id":"clxv1a2b30001item","fileName":"beach-set-01.jpg","filePath":"https://cdn.dropfans.io/valeria/vault/1721990000-ab12cd.jpg","thumbnailPath":"https://cdn.dropfans.io/valeria/thumbnails/1721990000-ab12cd.jpg","fileType":"image","fileSize":482113,"durationSeconds":null,"bunnyStreamId":null,"createdAt":"2026-08-01T10:15:00.000Z"}}}}},"400":{"description":"Either required form field is absent. Also: `fileType` is anything other than image, video or audio. Also: Image upload without both file parts. Also: fileType=video without a `file` part. Also: fileType=audio without a `file` part. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Missing required fields: fileType and originalName"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"413":{"description":"Audio file over 20MB.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Audio too large"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Storage or moderation kickoff failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to upload file"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/upload-vault-item","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"uploadVaultItem"}},"/api/external/v1/creators/{creatorId}/vault/{id}":{"delete":{"operationId":"deleteVaultItemForCreator","tags":["vault"],"summary":"Delete (hide) a vault item (for a creator)","description":"Same as `deleteVaultItem` (DELETE /api/external/v1/vault/{id}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The vault item id.","schema":{"type":"string"},"example":"clxv1a2b30001item"}],"responses":{"200":{"description":"Hidden (or already hidden).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No item with that id on this creator’s account (other creators’ ids also 404 — never 403).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Vault item not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to delete vault item"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-vault-item","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"deleteVaultItem"}},"/api/external/v1/creators/{creatorId}/vault/{id}/folder":{"patch":{"operationId":"moveVaultItemForCreator","tags":["vault"],"summary":"Move a vault item to a folder (for a creator)","description":"Same as `moveVaultItem` (PATCH /api/external/v1/vault/{id}/folder), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The vault item id.","schema":{"type":"string"},"example":"clxv1a2b30001item"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folderId":{"type":["string","null"],"description":"Destination folder id. Omit/null/\"\" to unfile.","example":"clxf0ld3r0001abcd"}}},"examples":{"move":{"summary":"Move into a folder","value":{"folderId":"clxf0ld3r0001abcd"}},"unfile":{"summary":"Move back to All","value":{}}}}}},"responses":{"200":{"description":"Moved.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"400":{"description":"`folderId` is present but not a string (e.g. a number). Also: The destination is a system folder. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"folderId must be a string"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such item on this account. Also: No such folder on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Vault item not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to move vault item"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/move-vault-item","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"moveVaultItem"}},"/api/external/v1/creators/{creatorId}/vault/{id}/tags":{"patch":{"operationId":"setVaultItemTagsForCreator","tags":["vault"],"summary":"Replace a vault item’s content tags (for a creator)","description":"Same as `setVaultItemTags` (PATCH /api/external/v1/vault/{id}/tags), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The vault item id.","schema":{"type":"string"},"example":"clxv1a2b30001item"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentTags":{"type":"array","items":{"type":"string","description":"A tag (longer ones are cut to 64 chars).","maxLength":64},"description":"The complete new tag list (≤50 kept).","maxItems":50}},"required":["contentTags"]},"examples":{"tags":{"summary":"Set two tags","value":{"contentTags":["beach","bikini"]}}}}}},"responses":{"200":{"description":"Stored — `contentTags` echoes the normalised list.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"contentTags":{"type":"array","items":{"type":"string","description":"A stored tag."},"description":"The tags after trimming, de-duplication and capping."}},"required":["success","contentTags"]},"example":{"success":true,"contentTags":["beach","bikini"]}}}},"400":{"description":"The body is not valid JSON. Also: Missing, not an array, or contains non-strings. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such item on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Vault item not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/set-vault-item-tags","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"setVaultItemTags"}},"/api/external/v1/creators/{creatorId}/vault/folders":{"get":{"operationId":"listFoldersForCreator","tags":["vault"],"summary":"List vault folders (for a creator)","description":"Same as `listFolders` (GET /api/external/v1/vault/folders), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"All folders.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"folders":{"type":"array","items":{"$ref":"#/components/schemas/Folder"},"description":"Every folder, A→Z."}},"required":["folders"]},"example":{"folders":[{"id":"clxf0ld3r0001abcd","name":"Beach set","itemCount":14}]}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch vault folders"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-folders","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"listFolders"},"post":{"operationId":"createFolderForCreator","tags":["vault"],"summary":"Create a vault folder (for a creator)","description":"Same as `createFolder` (POST /api/external/v1/vault/folders), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Folder name, trimmed, 1–50 chars, unique per creator.","example":"Beach set","maxLength":50}},"required":["name"]},"examples":{"create":{"summary":"Create a folder","value":{"name":"Beach set"}}}}}},"responses":{"200":{"description":"Created — the bare folder object.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Folder"},"example":{"id":"clxf0ld3r0001abcd","name":"Beach set","itemCount":0}}}},"400":{"description":"The body is not valid JSON. Also: `name` missing or not a string. Also: `name` is whitespace only. Also: Longer than 50 characters. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"409":{"description":"Duplicate name (also returned on a create race).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"A folder with this name already exists"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to create vault folder"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-folder","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"createFolder"}},"/api/external/v1/creators/{creatorId}/vault/folders/{folderId}":{"delete":{"operationId":"deleteFolderForCreator","tags":["vault"],"summary":"Delete a vault folder (for a creator)","description":"Same as `deleteFolder` (DELETE /api/external/v1/vault/folders/{folderId}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"folderId","in":"path","required":true,"description":"The folder id.","schema":{"type":"string"},"example":"clxf0ld3r0001abcd"}],"responses":{"200":{"description":"Deleted; contained items are now unfiled.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"400":{"description":"The folder is a system folder. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"This folder is managed automatically and cannot be deleted."}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such folder on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Folder not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to delete vault folder"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-folder","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"deleteFolder"}},"/api/external/v1/creators/{creatorId}/vault/video-upload":{"post":{"operationId":"startVideoUploadForCreator","tags":["vault"],"summary":"Start a video upload (step 1 of 3) (for a creator)","description":"Same as `startVideoUpload` (POST /api/external/v1/vault/video-upload), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"originalName":{"type":"string","description":"The video file name, stored as fileName.","example":"teaser.mp4"},"fileSize":{"type":"integer","description":"Optional advisory byte count — obvious oversizes are rejected up front. The authoritative check runs at completion. Max 500MB.","example":52428800,"maximum":524288000}},"required":["originalName"]},"examples":{"start":{"summary":"Start an upload","value":{"originalName":"teaser.mp4","fileSize":52428800}}}}}},"responses":{"200":{"description":"Upload created — feed these credentials to your TUS client.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoUploadCredentials"},"example":{"videoId":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9","tusEndpoint":"https://video.bunnycdn.com/tusupload","libraryId":"572783","signature":"9b2f…64 hex…c1a0","expires":1755640800,"completionToken":"eyJ…"}}}},"400":{"description":"`originalName` absent or blank. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Missing required field: originalName"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"413":{"description":"The advisory fileSize exceeds 500MB.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Video too large. Max 500MB."}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"CDN video creation failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Could not start the video upload"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/start-video-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"startVideoUpload"}},"/api/external/v1/creators/{creatorId}/vault/video-upload/complete":{"post":{"operationId":"completeVideoUploadForCreator","tags":["vault"],"summary":"Finish a video upload (step 3 of 3) (for a creator)","description":"Same as `completeVideoUpload` (POST /api/external/v1/vault/video-upload/complete), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"videoId":{"type":"string","description":"The `videoId` from step 1.","example":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9"},"originalName":{"type":"string","description":"Same file name you sent in step 1.","example":"teaser.mp4"},"completionToken":{"type":"string","description":"The token from step 1 (valid 8h). Proves this key started the upload."},"folderId":{"type":["string","null"],"description":"Optional folder — silently ignored if you don’t own it."}},"required":["videoId","originalName","completionToken"]},"examples":{"complete":{"summary":"Register the uploaded video","value":{"videoId":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9","originalName":"teaser.mp4","completionToken":"eyJ…"}}}}}},"responses":{"200":{"description":"Registered (or already registered — idempotent).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"item":{"$ref":"#/components/schemas/VideoVaultItem"}},"required":["success","item"]},"example":{"success":true,"item":{"id":"clxv9z8y70002item","fileName":"teaser.mp4","filePath":"https://vz-example.b-cdn.net/c2f7f9e2-…/playlist.m3u8?token=…","thumbnailPath":"https://vz-example.b-cdn.net/c2f7f9e2-…/thumbnail.jpg?token=…","fileType":"video","fileSize":52428800,"bunnyStreamId":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9","moderationStatus":"PENDING","moderationTags":[],"createdAt":"2026-08-01T10:20:00.000Z","aiEnhanced":false}}}}},"400":{"description":"Either field absent or blank. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Missing required fields: videoId and originalName"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The completionToken is wrong, for another key, or older than 8h — start over from step 1. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or expired upload token — please retry the upload"}}}},"409":{"description":"The CDN has not finished receiving the bytes — back off and retry the same call.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"The video upload has not finished — please retry."}}}},"413":{"description":"The stored byte count exceeds the cap — the upload is discarded.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Video too large. Max 500MB."}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Registration failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to register the uploaded video"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/complete-video-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"completeVideoUpload"}},"/api/external/v1/creators/{creatorId}/vault/video-status":{"post":{"operationId":"videoStatusForCreator","tags":["vault"],"summary":"Check video transcoding status (batch) (for a creator)","description":"Same as `videoStatus` (POST /api/external/v1/vault/video-status), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"videoIds":{"type":"array","items":{"type":"string","description":"A Bunny Stream GUID (vault item `bunnyStreamId`)."},"description":"Stream GUIDs to check (≤50 — extras silently dropped). Non-strings are filtered out; an empty array returns {\"statuses\":{}}.","maxItems":50}},"required":["videoIds"]},"examples":{"batch":{"summary":"Check two videos","value":{"videoIds":["c2f7f9e2-1111-4222-b333-4d55e6f7a8b9","0f3d9a11-2222-4333-a444-5e66f7a8b9c0"]}}}}}},"responses":{"200":{"description":"Status map keyed by the GUIDs you sent (unresolvable ids omitted).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"statuses":{"$ref":"#/components/schemas/VideoStatusMap"}},"required":["statuses"]},"example":{"statuses":{"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9":{"isReady":true,"isProcessing":false,"isFailed":false,"length":74},"0f3d9a11-2222-4333-a444-5e66f7a8b9c0":{"isReady":false,"isProcessing":true,"isFailed":false}}}}}},"400":{"description":"The body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/video-status","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"videoStatus"}},"/api/external/v1/creators/{creatorId}/media/uploads":{"post":{"operationId":"createMediaUploadForCreator","tags":["vault"],"summary":"Start a media upload session (for a creator)","description":"Same as `createMediaUpload` (POST /api/external/v1/media/uploads), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"filename":{"type":"string","description":"File name, stored on the vault item.","example":"beach.jpg","maxLength":255},"sizeBytes":{"type":"integer","description":"Exact file size in bytes. Image ≤ 30 MB, video ≤ 500 MB, audio ≤ 20 MB.","example":7904267},"contentType":{"type":"string","description":"MIME type; must match `kind` (image/*, video/*, audio/*).","example":"image/jpeg"},"folderId":{"type":["string","null"],"description":"Optional vault folder of this account."},"durationSeconds":{"type":"number","description":"Audio only: the voice note's length (capped at 3600s)."}},"required":["kind","filename","sizeBytes","contentType"]},"examples":{"image":{"summary":"An 8 MB photo","value":{"kind":"image","filename":"beach.jpg","sizeBytes":7904267,"contentType":"image/jpeg"}},"video":{"summary":"A video","value":{"kind":"video","filename":"teaser.mp4","sizeBytes":52428800,"contentType":"video/mp4"}}}}}},"responses":{"201":{"description":"Session opened: the session fields plus `parts` (image / audio) or `tus` (video).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Upload id."},"kind":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"status":{"type":"string","description":"`uploading` until you complete it; `processing` while a complete runs; `completed` once the vault item exists.","enum":["uploading","processing","completed","failed","expired"]},"fileName":{"type":"string","description":"The file name, stored on the vault item."},"contentType":{"type":"string","description":"The stored content type."},"sizeBytes":{"type":"integer","description":"The declared size."},"folderId":{"type":["string","null"],"description":"The vault folder the item goes in."},"partSize":{"type":["integer","null"],"description":"Image / audio: bytes per part (the last part is the remainder). Null for video."},"totalParts":{"type":["integer","null"],"description":"Image / audio: number of parts. Null for video."},"receivedParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers received so far."},"missingParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers still to upload."},"vaultItemId":{"type":["string","null"],"description":"The vault item, once completed."},"moderationStatus":{"type":["string","null"],"description":"The vault item’s moderation status, once completed.","enum":["PENDING","APPROVED","FLAGGED","REJECTED"]},"bunnyStreamId":{"type":["string","null"],"description":"Video: the Stream video id — poll [video-status](/developers/reference/video-status) with it."},"error":{"type":["object","null"],"properties":{"code":{"type":"string","description":"Machine-readable reason."},"message":{"type":["string","null"],"description":"Human-readable reason."}},"required":["code"],"description":"`{ code, message }` when the upload failed or expired."},"expiresAt":{"type":"string","description":"Upload the parts (or the tus bytes) and complete before this.","format":"date-time"},"createdAt":{"type":"string","description":"When the session was opened.","format":"date-time"},"completedAt":{"type":["string","null"],"description":"When it completed.","format":"date-time"},"parts":{"type":"array","items":{"type":"object","properties":{"partNumber":{"type":"integer","description":"1-based."},"sizeBytes":{"type":"integer","description":"Exact bytes this part must have."},"method":{"type":"string","description":"Always PUT."},"url":{"type":"string","description":"Where to PUT it (with your API key).","format":"uri"}},"required":["partNumber","sizeBytes","method","url"],"description":"One part."},"description":"Image / audio: PUT each part to its `url`."},"tus":{"type":"object","properties":{"endpoint":{"type":"string","description":"tus endpoint.","format":"uri"},"videoId":{"type":"string","description":"The Stream video id."},"libraryId":{"type":"string","description":"The Stream library id."},"signature":{"type":"string","description":"sha256 upload signature."},"expires":{"type":"integer","description":"Signature expiry (unix seconds)."},"headers":{"type":"object","description":"Send these as tus headers: AuthorizationSignature, AuthorizationExpire, VideoId, LibraryId."}},"required":["endpoint","videoId","libraryId","signature","expires","headers"],"description":"Video: tus upload credentials (the CDN API key itself is never exposed)."}},"required":["id","kind","status","fileName","contentType","sizeBytes","expiresAt","createdAt"]},"example":{"id":"mu_3f9c1a7be0d24c55a1e8b6f2","kind":"image","status":"uploading","fileName":"beach.jpg","contentType":"image/jpeg","sizeBytes":7904267,"folderId":null,"partSize":3145728,"totalParts":3,"receivedParts":[],"missingParts":[1,2,3],"vaultItemId":null,"moderationStatus":null,"bunnyStreamId":null,"error":null,"expiresAt":"2026-10-31T18:00:00.000Z","createdAt":"2026-10-31T10:00:00.000Z","completedAt":null,"parts":[{"partNumber":1,"sizeBytes":3145728,"method":"PUT","url":"https://www.dropfans.io/api/external/v1/media/uploads/mu_3f9c1a7be0d24c55a1e8b6f2/parts/1"},{"partNumber":2,"sizeBytes":3145728,"method":"PUT","url":"https://www.dropfans.io/api/external/v1/media/uploads/mu_3f9c1a7be0d24c55a1e8b6f2/parts/2"},{"partNumber":3,"sizeBytes":1612811,"method":"PUT","url":"https://www.dropfans.io/api/external/v1/media/uploads/mu_3f9c1a7be0d24c55a1e8b6f2/parts/3"}]}}}},"400":{"description":"Unknown `kind`. Also: `filename` missing or too long. Also: `sizeBytes` missing or not a positive integer. Also: `contentType` does not match `kind`. Also: Unknown folder, or another account’s. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"kind must be image, video or audio","code":"invalid_kind"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"413":{"description":"`sizeBytes` is over the limit for `kind`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"File too large. Max 30MB for image.","code":"file_too_large","maxBytes":31457280}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"The CDN did not create the video.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not start the video upload — retry later","code":"video_create_failed"}}}},"503":{"description":"Video (or, with media_uploads_unavailable, image / audio) uploads are switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Video uploads are not available right now","code":"video_uploads_unavailable"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-media-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"createMediaUpload"}},"/api/external/v1/creators/{creatorId}/media/uploads/{id}/parts/{partNumber}":{"put":{"operationId":"uploadMediaPartForCreator","tags":["vault"],"summary":"Upload one part (image / audio) (for a creator)","description":"Same as `uploadMediaPart` (PUT /api/external/v1/media/uploads/{id}/parts/{partNumber}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The upload `id` from POST /api/external/v1/media/uploads.","schema":{"type":"string"},"example":"mu_3f9c1a7be0d24c55a1e8b6f2"},{"name":"partNumber","in":"path","required":true,"description":"1-based part number, up to `totalParts`.","schema":{"type":"integer","minimum":1},"example":1}],"responses":{"200":{"description":"Part stored.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Upload id."},"partNumber":{"type":"integer","description":"The part you sent."},"sizeBytes":{"type":"integer","description":"Bytes received."},"receivedParts":{"type":"array","items":{"type":"integer","description":"Part number."},"description":"Parts received so far."},"missingParts":{"type":"array","items":{"type":"integer","description":"Part number."},"description":"Parts still missing — empty means you can complete."}},"required":["id","partNumber","sizeBytes","receivedParts","missingParts"]},"example":{"id":"mu_3f9c1a7be0d24c55a1e8b6f2","partNumber":1,"sizeBytes":3145728,"receivedParts":[1],"missingParts":[2,3]}}}},"400":{"description":"Part number out of range. Also: The part is not exactly the size it must have. Also: A video session. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Part number must be 1–3","code":"invalid_part_number"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"Unknown id, or an upload of another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Upload not found","code":"upload_not_found"}}}},"409":{"description":"The session is completed, failed or being completed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This upload is completed and takes no more parts","code":"upload_not_accepting_parts","status":"completed"}}}},"410":{"description":"Past `expiresAt`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This upload session has expired — start a new one","code":"upload_expired"}}}},"413":{"description":"The part is bigger than `partSize`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Parts are at most 3145728 bytes","code":"part_too_large","partSize":3145728}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/upload-media-part","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"uploadMediaPart"}},"/api/external/v1/creators/{creatorId}/media/uploads/{id}/complete":{"post":{"operationId":"completeMediaUploadForCreator","tags":["vault"],"summary":"Complete a media upload (for a creator)","description":"Same as `completeMediaUpload` (POST /api/external/v1/media/uploads/{id}/complete), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The upload `id` from POST /api/external/v1/media/uploads.","schema":{"type":"string"},"example":"mu_3f9c1a7be0d24c55a1e8b6f2"}],"responses":{"200":{"description":"Completed (or already completed).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Upload id."},"kind":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"status":{"type":"string","description":"`uploading` until you complete it; `processing` while a complete runs; `completed` once the vault item exists.","enum":["uploading","processing","completed","failed","expired"]},"fileName":{"type":"string","description":"The file name, stored on the vault item."},"contentType":{"type":"string","description":"The stored content type."},"sizeBytes":{"type":"integer","description":"The declared size."},"folderId":{"type":["string","null"],"description":"The vault folder the item goes in."},"partSize":{"type":["integer","null"],"description":"Image / audio: bytes per part (the last part is the remainder). Null for video."},"totalParts":{"type":["integer","null"],"description":"Image / audio: number of parts. Null for video."},"receivedParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers received so far."},"missingParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers still to upload."},"vaultItemId":{"type":["string","null"],"description":"The vault item, once completed."},"moderationStatus":{"type":["string","null"],"description":"The vault item’s moderation status, once completed.","enum":["PENDING","APPROVED","FLAGGED","REJECTED"]},"bunnyStreamId":{"type":["string","null"],"description":"Video: the Stream video id — poll [video-status](/developers/reference/video-status) with it."},"error":{"type":["object","null"],"properties":{"code":{"type":"string","description":"Machine-readable reason."},"message":{"type":["string","null"],"description":"Human-readable reason."}},"required":["code"],"description":"`{ code, message }` when the upload failed or expired."},"expiresAt":{"type":"string","description":"Upload the parts (or the tus bytes) and complete before this.","format":"date-time"},"createdAt":{"type":"string","description":"When the session was opened.","format":"date-time"},"completedAt":{"type":["string","null"],"description":"When it completed.","format":"date-time"}},"required":["id","kind","status","fileName","contentType","sizeBytes","expiresAt","createdAt"]},"example":{"id":"mu_3f9c1a7be0d24c55a1e8b6f2","kind":"image","status":"completed","fileName":"beach.jpg","contentType":"image/jpeg","sizeBytes":7904267,"folderId":null,"partSize":3145728,"totalParts":3,"receivedParts":[1,2,3],"missingParts":[],"vaultItemId":"clxv9z8y70003item","moderationStatus":"PENDING","bunnyStreamId":null,"error":null,"expiresAt":"2026-10-31T18:00:00.000Z","createdAt":"2026-10-31T10:00:00.000Z","completedAt":"2026-10-31T10:00:41.000Z"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"Unknown id, or an upload of another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Upload not found","code":"upload_not_found"}}}},"409":{"description":"Image / audio: parts are missing. Upload them and complete again. Also: Video: the CDN has not received all the bytes yet — back off and retry. Also: Another complete call is running for this session. Also: The session already failed — start a new one.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Upload the missing parts first: 3","code":"missing_parts","missingParts":[3]}}}},"410":{"description":"Past `expiresAt`.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This upload session has expired — start a new one","code":"upload_expired"}}}},"413":{"description":"The stored file is over the limit; the upload is discarded.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Video too large. Max 500MB.","code":"file_too_large"}}}},"415":{"description":"Image / audio: we cannot remove the file’s metadata safely (also 422 MALFORMED / UNSANITISABLE), so it is not stored.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unsupported image format. Please upload a JPEG, PNG, WebP, GIF, HEIC or AVIF.","code":"UNSUPPORTED_FORMAT"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Unexpected failure — the session goes back to `uploading`; retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Could not complete the upload — retry","code":"complete_failed"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/complete-media-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"completeMediaUpload"}},"/api/external/v1/creators/{creatorId}/media/uploads/{id}":{"get":{"operationId":"getMediaUploadForCreator","tags":["vault"],"summary":"Get a media upload (for a creator)","description":"Same as `getMediaUpload` (GET /api/external/v1/media/uploads/{id}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageVault`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The upload `id` from POST /api/external/v1/media/uploads.","schema":{"type":"string"},"example":"mu_3f9c1a7be0d24c55a1e8b6f2"}],"responses":{"200":{"description":"The session.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Upload id."},"kind":{"type":"string","description":"What you are uploading.","enum":["image","video","audio"]},"status":{"type":"string","description":"`uploading` until you complete it; `processing` while a complete runs; `completed` once the vault item exists.","enum":["uploading","processing","completed","failed","expired"]},"fileName":{"type":"string","description":"The file name, stored on the vault item."},"contentType":{"type":"string","description":"The stored content type."},"sizeBytes":{"type":"integer","description":"The declared size."},"folderId":{"type":["string","null"],"description":"The vault folder the item goes in."},"partSize":{"type":["integer","null"],"description":"Image / audio: bytes per part (the last part is the remainder). Null for video."},"totalParts":{"type":["integer","null"],"description":"Image / audio: number of parts. Null for video."},"receivedParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers received so far."},"missingParts":{"type":["array","null"],"items":{"type":"integer","description":"Part number."},"description":"Part numbers still to upload."},"vaultItemId":{"type":["string","null"],"description":"The vault item, once completed."},"moderationStatus":{"type":["string","null"],"description":"The vault item’s moderation status, once completed.","enum":["PENDING","APPROVED","FLAGGED","REJECTED"]},"bunnyStreamId":{"type":["string","null"],"description":"Video: the Stream video id — poll [video-status](/developers/reference/video-status) with it."},"error":{"type":["object","null"],"properties":{"code":{"type":"string","description":"Machine-readable reason."},"message":{"type":["string","null"],"description":"Human-readable reason."}},"required":["code"],"description":"`{ code, message }` when the upload failed or expired."},"expiresAt":{"type":"string","description":"Upload the parts (or the tus bytes) and complete before this.","format":"date-time"},"createdAt":{"type":"string","description":"When the session was opened.","format":"date-time"},"completedAt":{"type":["string","null"],"description":"When it completed.","format":"date-time"}},"required":["id","kind","status","fileName","contentType","sizeBytes","expiresAt","createdAt"]},"example":{"id":"mu_3f9c1a7be0d24c55a1e8b6f2","kind":"image","status":"completed","fileName":"beach.jpg","contentType":"image/jpeg","sizeBytes":7904267,"folderId":null,"partSize":3145728,"totalParts":3,"receivedParts":[1,2,3],"missingParts":[],"vaultItemId":"clxv9z8y70003item","moderationStatus":"PENDING","bunnyStreamId":null,"error":null,"expiresAt":"2026-10-31T18:00:00.000Z","createdAt":"2026-10-31T10:00:00.000Z","completedAt":"2026-10-31T10:00:41.000Z"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageVault` on that account. Also: Your app has the Vault [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"Unknown id, or an upload of another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Upload not found","code":"upload_not_found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-media-upload","x-dropfans-category":"vault","x-dropfans-agency-permission":"canManageVault","x-dropfans-mirror-of":"getMediaUpload"}},"/api/external/v1/creators/{creatorId}/drops":{"post":{"operationId":"createDropForCreator","tags":["drops"],"summary":"Create a sellable drop from vault items (for a creator)","description":"Same as `createDrop` (POST /api/external/v1/drops), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Drop title, shown at checkout. Falsy values are stored as null.","example":"Beach set — 6 photos"},"description":{"type":"string","description":"Checked for prohibited words, then discarded — never persisted or displayed."},"price":{"type":"number","description":"USD dollars. 0 = free; otherwise $5–$750.","example":25,"minimum":0,"maximum":750},"allowDownload":{"type":"boolean","description":"Images only: when true, buyers get a Download button serving a watermarked, metadata-stripped JPEG. Videos always stream behind DRM and are never downloadable. Off unless explicitly set.","default":false},"vaultItemIds":{"type":"array","items":{"type":"string","description":"A vault item you own."},"description":"1–10 vault item ids, in display order. The first becomes the cover.","maxItems":10}},"required":["price","vaultItemIds"]},"examples":{"paidDrop":{"summary":"A $25 three-item drop","value":{"name":"Beach set — 6 photos","price":25,"vaultItemIds":["clxv1a2b30001item","clxv1a2b30002item","clxv1a2b30003item"]}}}}}},"responses":{"200":{"description":"Created. Keep the productId — sales polling, previews and post attachment all key on it.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropCreated"},"example":{"productId":"clxdr0p000001prod","buyUrl":"https://www.dropfans.io/buy/clxdr0p000001prod","mediaCount":3}}}},"400":{"description":"`price` missing, not a number, NaN or negative. Also: Priced above 0 but below $5. Also: Priced above $750. Also: The name or description tripped the word filter — a three-field envelope unique to this endpoint (posts use a two-field 422 for the same class of failure). Also: Missing or empty media list. Also: More than 10 ids. Also: One of the items was deleted (hidden). Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid price"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"An id belongs to another creator. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"You do not own all selected vault items"}}}},"404":{"description":"An id does not exist.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"One or more vault items not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Write failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to create drop"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-drop","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"createDrop"},"get":{"operationId":"listDropsForCreator","tags":["drops"],"summary":"List the creator’s drops (for a creator)","description":"Same as `listDrops` (GET /api/external/v1/drops), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"limit","in":"query","required":false,"description":"Page size (out-of-range values are clamped).","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of drops.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"drops":{"type":"array","items":{"$ref":"#/components/schemas/DropSummary"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["drops"]},"example":{"drops":[{"id":"clxdr0p000001prod","name":"Beach set — 6 photos","description":null,"price":25,"currency":"USD","accessMode":"OPEN","allowDownload":false,"status":"APPROVED","mediaCount":3,"buyUrl":"https://www.dropfans.io/buy/clxdr0p000001prod","createdAt":"2026-08-15T09:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-drops","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"listDrops"}},"/api/external/v1/creators/{creatorId}/drops/{id}":{"get":{"operationId":"getDropForCreator","tags":["drops"],"summary":"Read back a drop (for a creator)","description":"Same as `getDrop` (GET /api/external/v1/drops/{id}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The product (drop) id from create-drop.","schema":{"type":"string"},"example":"clxdr0p000001prod"}],"responses":{"200":{"description":"The drop.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Drop"},"example":{"id":"clxdr0p000001prod","name":"Beach set — 6 photos","price":25,"currency":"USD","status":"APPROVED","moderationReason":null,"buyUrl":"https://www.dropfans.io/buy/clxdr0p000001prod","allowDownload":false,"mediaCount":3,"media":[{"vaultItemId":"clxv1a2b30001item","order":0,"fileType":"image","moderationStatus":"APPROVED","hasPreview":true},{"vaultItemId":"clxv1a2b30002item","order":1,"fileType":"image","moderationStatus":"APPROVED","hasPreview":true},{"vaultItemId":"clxv1a2b30003item","order":2,"fileType":"video","moderationStatus":"APPROVED","hasPreview":false}],"salesCount":2,"lastSaleAt":"2026-08-18T21:03:00.000Z","createdAt":"2026-08-15T09:00:00.000Z"}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such drop on this account (another creator’s drop also 404s — never 403).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-drop","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"getDrop"},"patch":{"operationId":"updateDropForCreator","tags":["drops"],"summary":"Edit a drop (for a creator)","description":"Same as `updateDrop` (PATCH /api/external/v1/drops/{id}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The product (drop) id.","schema":{"type":"string"},"example":"clxdr0p000001prod"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":["string","null"],"description":"Drop title, shown at checkout (cut at 200 characters).","example":"Beach set — 8 photos","maxLength":200},"description":{"type":["string","null"],"description":"Drop description (cut at 5,000 characters). Unlike create-drop, this one is stored.","maxLength":5000},"price":{"type":"number","description":"USD dollars. 0 = free; otherwise $5–$750. Rounded to cents.","example":30,"minimum":0,"maximum":750},"accessMode":{"type":"string","description":"`OPEN` = anyone can buy; `SUBS_FREE` = free for subscribers; `SUBS_ONLY_PAID` = only subscribers can buy.","enum":["OPEN","SUBS_FREE","SUBS_ONLY_PAID"]}}},"examples":{"reprice":{"summary":"Rename and reprice","value":{"name":"Beach set — 8 photos","price":30}}}}}},"responses":{"200":{"description":"The drop after the edit.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropUpdated"},"example":{"id":"clxdr0p000001prod","name":"Beach set — 8 photos","description":null,"price":30,"accessMode":"OPEN","moderationStatus":"APPROVED","currency":"USD","status":"APPROVED","buyUrl":"https://www.dropfans.io/buy/clxdr0p000001prod"}}}},"400":{"description":"`price` not a number or negative. Also: Priced above 0 but below $5. Also: Priced above $750. Also: Unknown accessMode. Also: Subscriber gating without an active tier. Also: `name` or `description` is not a string or null. Also: Name or description tripped the word filter. Also: The body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"price must be a number in USD (0 = free)"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such drop on this account (another creator’s drop also 404s).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-drop","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"updateDrop"},"delete":{"operationId":"deleteDropForCreator","tags":["drops"],"summary":"Delete a drop nobody has bought (for a creator)","description":"Same as `deleteDrop` (DELETE /api/external/v1/drops/{id}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The product (drop) id.","schema":{"type":"string"},"example":"clxdr0p000001prod"}],"responses":{"200":{"description":"Deleted.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The deleted drop’s id."},"deleted":{"type":"boolean","description":"Always true."}},"required":["id","deleted"]},"example":{"id":"clxdr0p000001prod","deleted":true}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such drop on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"409":{"description":"The drop has at least one order (paid or started).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This drop has orders, so buyers keep access to it and it cannot be deleted.","code":"has_orders"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-drop","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"deleteDrop"}},"/api/external/v1/creators/{creatorId}/drops/{id}/previews":{"post":{"operationId":"attachDropPreviewsForCreator","tags":["drops"],"summary":"Attach baked blur previews to a drop (for a creator)","description":"Same as `attachDropPreviews` (POST /api/external/v1/drops/{id}/previews), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The product (drop) id.","schema":{"type":"string"},"example":"clxdr0p000001prod"}],"requestBody":{"required":true,"description":"Field names embed the vault item id — one previewBlob per media item you want a preview on.","content":{"multipart/form-data":{"schema":{"type":"object","properties":{"previewBlob_<vaultItemId>":{"type":"string","contentMediaType":"application/octet-stream","description":"The baked JPEG teaser for that media item. Must be image/jpeg, ≤8MB."},"blurMeta_<vaultItemId>":{"type":"string","description":"Optional blur descriptor recorded alongside: \"full\", \"partial\" or \"pixelated:<intensity>\".","example":"pixelated:59"}}},"examples":{"previews":{"summary":"Baked previews for two media items","value":{"previewBlob_clxv1a2b30001item":"@preview-1.jpg","blurMeta_clxv1a2b30001item":"partial","previewBlob_clxv1a2b30002item":"@preview-2.jpg","blurMeta_clxv1a2b30002item":"pixelated:59"}}}}}},"responses":{"200":{"description":"`updated` = how many previews were actually stored. If it is lower than the number of parts you sent, the difference was silently skipped.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"updated":{"type":"integer","description":"Previews stored on this call.","example":2}},"required":["success","updated"]},"example":{"success":true,"updated":2}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The drop belongs to another creator. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"You do not own this drop"}}}},"404":{"description":"No such drop.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Unexpected failure — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to attach previews"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/attach-drop-previews","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"attachDropPreviews"}},"/api/external/v1/creators/{creatorId}/drops/check-status":{"post":{"operationId":"checkDropStatusForCreator","tags":["drops"],"summary":"Check which drops sold (batch) (for a creator)","description":"Same as `checkDropStatus` (POST /api/external/v1/drops/check-status), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"productIds":{"type":"array","items":{"type":"string","description":"A product id from create-drop."},"description":"Product ids to check (≤200 — extras silently dropped). Non-strings filtered out; an empty array returns {\"sales\":{}}.","maxItems":200}},"required":["productIds"]},"examples":{"batch":{"summary":"Check two drops","value":{"productIds":["clxdr0p000001prod","clxdr0p000002prod"]}}}}}},"responses":{"200":{"description":"Sales map — only sold products appear. Multiple paid orders on one product report the most recent.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"sales":{"$ref":"#/components/schemas/SalesMap"},"orders":{"$ref":"#/components/schemas/OrdersByProduct"}},"required":["sales","orders"]},"example":{"sales":{"clxdr0p000001prod":{"paid":true,"saleAmountCents":2500,"buyerEmail":"buyer@example.com"}},"orders":{"clxdr0p000001prod":[{"orderId":"clxor0001order","productId":"clxdr0p000001prod","accountId":"clx2f8a1b0001qw3k","externalRef":"tg_48213377","amountCents":2500,"currency":"USD","paidAt":"2026-10-17T16:20:00.000Z","paidWith":"card","status":"paid","buyer":{"id":"clxbu0001buyer","email":"buyer@example.com","telegramUserId":"48213377","telegramUsername":"fan_one"}}]}}}}},"400":{"description":"The body is not valid JSON. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to check drop status"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/check-drop-status","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"checkDropStatus"}},"/api/external/v1/creators/{creatorId}/orders":{"get":{"operationId":"listOrdersForCreator","tags":["drops"],"summary":"List paid orders (per-fan references) (for a creator)","description":"Same as `listOrders` (GET /api/external/v1/orders), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"productId","in":"query","required":false,"description":"Only orders for this drop.","schema":{"type":"string"},"example":"clxdr0p000001prod"},{"name":"externalRef","in":"query","required":false,"description":"Only orders bought through links carrying this reference.","schema":{"type":"string","maxLength":32,"pattern":"^[A-Za-z0-9_-]{1,32}$"},"example":"tg_48213377"},{"name":"since","in":"query","required":false,"description":"Only orders paid at or after this time.","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of orders.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/Order"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["orders"]},"example":{"orders":[{"orderId":"clxor0001order","productId":"clxdr0p000001prod","accountId":"clx2f8a1b0001qw3k","externalRef":"tg_48213377","amountCents":2750,"currency":"USD","paidAt":"2026-10-17T16:20:00.000Z","paidWith":"card","status":"paid","buyer":{"id":"clxbu0001buyer","email":"buyer@example.com","telegramUserId":"48213377","telegramUsername":"fan_one"}}],"nextCursor":null}}}},"400":{"description":"Malformed reference. Also: Unparseable `since`. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"externalRef must be 1–32 of A-Z a-z 0-9 _ -"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the Drops & checkout links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-orders","x-dropfans-category":"drops","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"listOrders"}},"/api/external/v1/creators/{creatorId}/posts":{"post":{"operationId":"createPostForCreator","tags":["posts"],"summary":"Publish a post to the For You feed (for a creator)","description":"Same as `createPost` (POST /api/external/v1/posts), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"caption":{"type":"string","description":"Post text. Required for kind=TEXT. Silently truncated to 2000 characters.","example":"im 5 min away, wyd?","maxLength":2000},"kind":{"type":"string","description":"Post shape. DROP is not a request value — send productId instead.","enum":["TEXT","MEDIA","SUBSCRIPTION","COMMUNITY"],"default":"TEXT"},"productId":{"type":"string","description":"Attach an existing approved drop. Forces kind=DROP. Must belong to you."},"media":{"type":"array","items":{"type":"object","properties":{"vaultItemId":{"type":"string","description":"A vault item you own (GET /api/external/v1/vault)."},"isPaid":{"type":"boolean","description":"Paid items are shown blurred and mint a PPV unlock. Note: posting via API bakes no custom blur preview — paid items fall back to a gaussian blur.","default":false},"price":{"type":"number","description":"USD. Required when isPaid is true. Minimum $5.","minimum":5},"order":{"type":"integer","description":"Display order. Defaults to array index."}},"required":["vaultItemId"],"description":"One gallery entry."},"description":"Required when kind=MEDIA.","maxItems":10},"scheduledAt":{"type":"string","description":"ISO-8601. At least 1 minute ahead, at most 30 days. Omit to publish now.","format":"date-time"}}},"examples":{"text":{"summary":"Text post","value":{"caption":"im 5 min away, wyd?"}},"mediaFree":{"summary":"Free image from the vault","value":{"kind":"MEDIA","caption":"rate my fit 1-10","media":[{"vaultItemId":"clxv1a2b30001item","isPaid":false,"order":0}]}},"mediaPaid":{"summary":"Free teaser + paid unlock, scheduled","value":{"kind":"MEDIA","caption":"can i show you??","scheduledAt":"2026-08-26T19:00:00Z","media":[{"vaultItemId":"clxv1a2b30001item","isPaid":false,"order":0},{"vaultItemId":"clxv1a2b30002item","isPaid":true,"price":10,"order":1}]}}}}}},"responses":{"201":{"description":"Post created. Check `status`: APPROVED means it is already live, PENDING means it is still in review and will go live by itself once it clears.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The new post id — poll GET /api/external/v1/posts/{id} with it.","example":"clxp0st000001feed"},"status":{"type":"string","description":"PENDING is normal, not an error: media posts wait on the NSFW pipeline and a flagged caption waits on a human.","enum":["PENDING","APPROVED"]},"pending":{"type":"boolean","description":"Convenience mirror of status === \"PENDING\"."},"scheduledAt":{"type":["string","null"],"description":"Echoed schedule time, or null for immediate posts.","format":"date-time"},"url":{"type":["string","null"],"description":"The creator’s profile URL (where the post appears once live). Null when the creator has no username yet.","format":"uri"}},"required":["id","status","pending"]},"example":{"id":"clxp0st000001feed","status":"PENDING","pending":true,"scheduledAt":null,"url":"https://www.dropfans.io/u/valeria"}}}},"400":{"description":"The body is not valid JSON. Also: kind=MEDIA without media. Also: More than 10 media entries. Also: A media entry lacks vaultItemId (index varies). Also: isPaid without a valid price (index varies). Also: scheduledAt is not a parseable date. Also: scheduledAt is in the past or under a minute ahead. Also: scheduledAt beyond 30 days. Also: kind=TEXT with an empty caption. Also: productId points at a drop still in moderation — check GET /api/external/v1/drops/{id}. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The key belongs to a CONSUMER account. Also: The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the For You posts [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Only creators can post"}}}},"404":{"description":"productId does not exist on this account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Drop not found"}}}},"422":{"description":"Caption tripped the prohibited-word filter — rewrite it and retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithMatchedWord"},"example":{"error":"Your post contains a word that isn’t allowed.","matchedWord":"…"}}}},"429":{"description":"Daily posting cap (5 per rolling 24h) reached. Retry-After header = seconds to wait. This is separate from the API rate limit (whose body carries code:\"rate_limited\").","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"You’ve reached the posting limit (5 per day). Try again in …"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-post","x-dropfans-category":"posts","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"createPost"},"get":{"operationId":"listPostsForCreator","tags":["posts"],"summary":"List your posts and their moderation status (for a creator)","description":"Same as `listPosts` (GET /api/external/v1/posts), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"page","in":"query","required":false,"description":"Page number, 1-based.","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","required":false,"description":"Posts per page (default 20, cap 50 — larger values clamped).","schema":{"type":"integer","default":20,"maximum":50}},{"name":"status","in":"query","required":false,"description":"Filter by moderation state (case-insensitive). Unrecognised values are ignored.","schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]}}],"responses":{"200":{"description":"Your posts, newest first, plus the current limits.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostListResponse"},"example":{"posts":[{"id":"clxp0st000001feed","kind":"MEDIA","caption":"rate my fit 1-10","status":"APPROVED","live":true,"scheduledAt":null,"publishedAt":"2026-08-18T19:00:00.000Z","createdAt":"2026-08-18T18:59:40.000Z","productId":null,"likes":14,"comments":3,"media":[{"id":"clxpm3d1a0001post","vaultItemId":"clxv1a2b30001item","isPaid":false,"order":0,"type":"image"}]}],"pagination":{"page":1,"limit":20,"total":63,"hasMore":true},"limits":{"postsPerDay":5,"maxCaptionChars":2000,"maxMediaPerPost":10,"maxScheduleDays":30,"minPaidPrice":5}}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the For You posts [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-posts","x-dropfans-category":"posts","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"listPosts"}},"/api/external/v1/creators/{creatorId}/posts/{id}":{"get":{"operationId":"getPostForCreator","tags":["posts"],"summary":"Check one post’s moderation status (for a creator)","description":"Same as `getPost` (GET /api/external/v1/posts/{id}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The post id.","schema":{"type":"string"},"example":"clxp0st000001feed"}],"responses":{"200":{"description":"The post.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"},"example":{"id":"clxp0st000001feed","kind":"MEDIA","caption":"rate my fit 1-10","status":"APPROVED","live":true,"scheduledAt":null,"publishedAt":"2026-08-18T19:00:00.000Z","createdAt":"2026-08-18T18:59:40.000Z","productId":null,"likes":14,"comments":3,"media":[{"id":"clxpm3d1a0001post","vaultItemId":"clxv1a2b30001item","isPaid":false,"order":0,"type":"image"}]}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the For You posts [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such post on your account. Deliberately 404 (not 403) for another creator’s post — ids cannot be probed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-post","x-dropfans-category":"posts","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"getPost"},"delete":{"operationId":"deletePostForCreator","tags":["posts"],"summary":"Delete a post (or cancel a scheduled one) (for a creator)","description":"Same as `deletePost` (DELETE /api/external/v1/posts/{id}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canManageDrops`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"The post id.","schema":{"type":"string"},"example":"clxp0st000001feed"}],"responses":{"200":{"description":"Deleted.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"},"example":{"ok":true}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canManageDrops` on that account. Also: Your app has the For You posts [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"No such post on your account (another creator’s post also 404s).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/delete-post","x-dropfans-category":"posts","x-dropfans-agency-permission":"canManageDrops","x-dropfans-mirror-of":"deletePost"}},"/api/external/v1/creators/{creatorId}/earnings":{"get":{"operationId":"getEarningsForCreator","tags":["earnings"],"summary":"Earnings stats, chart and recent transactions (for a creator)","description":"Same as `getEarnings` (GET /api/external/v1/earnings), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"startDate","in":"query","required":true,"description":"Window start, YYYY-MM-DD, interpreted in `tz`.","schema":{"type":"string","format":"date"},"example":"2026-08-01"},{"name":"endDate","in":"query","required":true,"description":"Window end (inclusive), YYYY-MM-DD, interpreted in `tz`.","schema":{"type":"string","format":"date"},"example":"2026-08-19"},{"name":"tz","in":"query","required":false,"description":"IANA timezone for day bucketing. **Invalid values silently fall back to UTC** — no error.","schema":{"type":"string","default":"UTC","format":"iana-timezone"},"example":"Europe/Stockholm"}],"responses":{"200":{"description":"Stats, chart and the newest transactions. All money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarningsResponse"},"example":{"stats":{"totalEarningsCents":182050,"grossEarningsCents":214180,"previousPeriodEarningsCents":141200,"previousPeriodGrossEarningsCents":166100,"transactionCount":41,"avgTransactionCents":4440,"uniqueCustomers":28,"typeTotals":{"drop":{"grossCents":150000,"netCents":127500,"count":30},"tip":{"grossCents":44180,"netCents":37550,"count":8},"subscription":{"grossCents":20000,"netCents":17000,"count":3}}},"chart":{"labels":["Aug 18","Aug 19"],"values":[12500,9800],"dates":["2026-08-18","2026-08-19"],"groupBy":"day","typedValues":{"drop":[10000,7500],"tip":[2500,2300],"subscription":[0,0]}},"transactions":[{"id":"clx0rd3r000001sale","productId":"clxdr0p000001prod","productName":"Beach set — 6 photos","amountCents":2000,"grossAmountCents":2500,"buyerEmail":"buyer@example.com","buyerName":null,"paidAt":"2026-08-18T21:03:00.000Z","type":"drop"}]}}}},"400":{"description":"Either date param is missing. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"startDate and endDate query params are required (YYYY-MM-DD)"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch earnings"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-earnings","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"getEarnings"}},"/api/external/v1/creators/{creatorId}/earnings/summary":{"get":{"operationId":"getEarningsSummaryForCreator","tags":["earnings"],"summary":"Earnings summary: totals, sources and a day / week series (for a creator)","description":"Same as `getEarningsSummary` (GET /api/external/v1/earnings/summary), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"startDate","in":"query","required":false,"description":"First local day (YYYY-MM-DD). Defaults to 29 days before `endDate`. At most 366 days per window.","schema":{"type":"string","format":"date"},"example":"2026-10-01"},{"name":"endDate","in":"query","required":false,"description":"Last local day (YYYY-MM-DD), inclusive. Defaults to today in `timezone`.","schema":{"type":"string","format":"date"},"example":"2026-10-31"},{"name":"granularity","in":"query","required":false,"description":"Series bucket: a local day, or a Monday-start week.","schema":{"type":"string","enum":["day","week"],"default":"day"}},{"name":"timezone","in":"query","required":false,"description":"IANA timezone for the days, weeks and \"this month\". `tz` is accepted too. Unlike GET /earnings, an unknown zone is a 400, not UTC.","schema":{"type":"string","default":"UTC","format":"iana-timezone"},"example":"Europe/Stockholm"}],"responses":{"200":{"description":"Totals, breakdown and series. All money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"startDate":{"type":"string","description":"The window’s first day.","format":"date"},"endDate":{"type":"string","description":"The window’s last day (inclusive).","format":"date"},"timezone":{"type":"string","description":"The timezone used."},"granularity":{"type":"string","description":"The series bucket.","enum":["day","week"]},"currency":{"type":"string","description":"Always USD."},"totals":{"type":"object","properties":{"allTime":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Since the account’s first sale."},"thisMonth":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"The current calendar month in `timezone`."},"period":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Your window — equals the sum of `series`."}},"required":["allTime","thisMonth","period"],"description":"`allTime`, `thisMonth` (the current month in `timezone`, up to today) and `period` (your window), each `{ grossCents, netCents, count }`."},"breakdownBySource":{"type":"object","properties":{"drop":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Drop sales."},"tip":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Tips."},"subscription":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Number of transactions."}},"required":["grossCents","netCents","count"],"description":"Subscription payments (first charges and renewals)."}},"required":["drop","tip","subscription"],"description":"`drop`, `tip` and `subscription` for your window, each `{ grossCents, netCents, count }`."},"series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"The local day, or the Monday the week starts on (can be before `startDate`).","format":"date"},"startsAt":{"type":"string","description":"When the bucket starts, clipped to the window.","format":"date-time"},"grossCents":{"type":"integer","description":"Buyer-paid minus VAT, before the platform fee."},"netCents":{"type":"integer","description":"The creator’s earnings after the platform fee."},"count":{"type":"integer","description":"Transactions in the bucket."}},"required":["date","startsAt","grossCents","netCents","count"],"description":"A bucket."},"description":"One point per day or week of the window, oldest first, zero-filled."}},"required":["startDate","endDate","timezone","granularity","currency","totals","breakdownBySource","series"]},"example":{"startDate":"2026-10-26","endDate":"2026-10-27","timezone":"Europe/Stockholm","granularity":"day","currency":"USD","totals":{"allTime":{"grossCents":2480000,"netCents":1984000,"count":912},"thisMonth":{"grossCents":214180,"netCents":182050,"count":41},"period":{"grossCents":22300,"netCents":18950,"count":7}},"breakdownBySource":{"drop":{"grossCents":15000,"netCents":12750,"count":4},"tip":{"grossCents":5300,"netCents":4500,"count":2},"subscription":{"grossCents":2000,"netCents":1700,"count":1}},"series":[{"date":"2026-10-26","startsAt":"2026-10-25T23:00:00.000Z","grossCents":12500,"netCents":10620,"count":4},{"date":"2026-10-27","startsAt":"2026-10-26T23:00:00.000Z","grossCents":9800,"netCents":8330,"count":3}]}}}},"400":{"description":"Unknown `timezone`. Also: Malformed or impossible date (e.g. 2026-02-31). Also: `startDate` is after `endDate`. Also: The window is longer than 366 days. Also: Any other `granularity`. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"timezone must be an IANA timezone name, e.g. Europe/Stockholm","code":"invalid_timezone"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Query failed — retry later.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch the earnings summary"}}}}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-earnings-summary","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"getEarningsSummary"}},"/api/external/v1/creators/{creatorId}/earnings/transactions":{"get":{"operationId":"listEarningsTransactionsForCreator","tags":["earnings"],"summary":"Full transaction ledger (paginated, net per transaction) (for a creator)","description":"Same as `listEarningsTransactions` (GET /api/external/v1/earnings/transactions), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"since","in":"query","required":false,"description":"Only transactions paid at or after this time.","schema":{"type":"string","format":"date-time"},"example":"2026-10-01T00:00:00Z"},{"name":"until","in":"query","required":false,"description":"Only transactions paid at or before this time.","schema":{"type":"string","format":"date-time"},"example":"2026-10-31T23:59:59.999Z"},{"name":"type","in":"query","required":false,"description":"Comma-separated subset of drop,tip,subscription. Default: all three.","schema":{"type":"string"},"example":"drop,tip"},{"name":"includeReversed","in":"query","required":false,"description":"Also return refunded and charged-back transactions.","schema":{"type":"boolean","default":false}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":100,"minimum":1,"maximum":200}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of transactions. All money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"transactions":{"type":"array","items":{"$ref":"#/components/schemas/LedgerTransaction"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["transactions"]},"example":{"transactions":[{"id":"clx0rd3r000001sale","type":"drop","productId":"clxdr0p000001prod","productName":"Beach set — 6 photos","externalRef":"tg_48213377","amountCents":2000,"netAmountCents":2000,"grossAmountCents":2500,"platformFeeCents":500,"taxCents":250,"totalChargedCents":2750,"currency":"USD","buyerEmail":"buyer@example.com","buyerName":null,"paidAt":"2026-10-18T21:03:00.000Z","status":"paid"}],"nextCursor":"MjAyNi0xMC0xOFQyMTowMzowMC4wMDBafGNseDByZDNyMDAwMDAxc2FsZQ"}}}},"400":{"description":"Unparseable `since` (or `until`). Also: Unknown type. Also: The cursor was not one we returned. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"since must be an ISO date"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-earnings-transactions","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"listEarningsTransactions"}},"/api/external/v1/creators/{creatorId}/tips":{"get":{"operationId":"listTipsForCreator","tags":["earnings"],"summary":"List paid tips (per-fan references) (for a creator)","description":"Same as `listTips` (GET /api/external/v1/tips), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"externalRef","in":"query","required":false,"description":"Only tips made through links carrying this reference.","schema":{"type":"string","maxLength":32,"pattern":"^[A-Za-z0-9_-]{1,32}$"},"example":"fan-48213377"},{"name":"since","in":"query","required":false,"description":"Only tips paid at or after this time.","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of tips.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"tips":{"type":"array","items":{"$ref":"#/components/schemas/Tip"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["tips"]},"example":{"tips":[{"tipId":"clxtp0001tip","accountId":"clx2f8a1b0001qw3k","externalRef":"fan-48213377","amountCents":1100,"currency":"USD","message":"For the new set 💕","paidAt":"2026-10-23T16:20:00.000Z","paidWith":"card","status":"paid","tipper":{"id":"clxbu0001buyer","email":"fan@example.com","telegramUserId":"48213377","telegramUsername":"fan_one"}}],"nextCursor":null}}}},"400":{"description":"Malformed reference. Also: Unparseable `since`. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"externalRef must be 1–32 of A-Z a-z 0-9 _ -"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Earnings & balance [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-tips","x-dropfans-category":"earnings","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"listTips"}},"/api/external/v1/creators/{creatorId}/links":{"get":{"operationId":"getLinksForCreator","tags":["links"],"summary":"The creator’s profile, tip and subscribe links (for a creator)","description":"Same as `getLinks` (GET /api/external/v1/links), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key).","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The creator’s links.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Links"},"example":{"username":"valeria","links":{"profile":{"id":"k3x9m2qa7d","type":"profile","url":"https://www.dropfans.io/buy/k3x9m2qa7d","telegram":"https://t.me/DropfansBot/app?startapp=k3x9m2qa7d","productId":null,"amountUsd":null,"externalRef":null,"createdAt":"2026-10-29T12:00:00.000Z"},"tip":{"id":"p0w8n4rt2c","type":"tip","url":"https://www.dropfans.io/buy/p0w8n4rt2c","telegram":"https://t.me/DropfansBot/app?startapp=p0w8n4rt2c","productId":null,"amountUsd":null,"externalRef":null,"createdAt":"2026-10-29T12:00:00.000Z"},"subscribe":{"id":"h5j1v9xs3e","type":"subscribe","url":"https://www.dropfans.io/buy/h5j1v9xs3e","telegram":"https://t.me/DropfansBot/app?startapp=h5j1v9xs3e","productId":null,"amountUsd":null,"externalRef":null,"createdAt":"2026-10-29T12:00:00.000Z"}},"web":{"profile":"https://www.dropfans.io/u/valeria","tip":"https://www.dropfans.io/u/valeria?tip=1","tipTemplate":"https://www.dropfans.io/u/valeria?tip={usd}","tipWithRefTemplate":"https://www.dropfans.io/u/valeria?tip={usd}&m={externalRef}","subscribe":"https://www.dropfans.io/u/valeria?subscribe=1","buyTemplate":"https://www.dropfans.io/buy/{productId}","buyWithRefTemplate":"https://www.dropfans.io/buy/{productId}?m={externalRef}"},"telegram":{"bot":"DropfansBot","profile":"https://t.me/DropfansBot/app?startapp=p_valeria","tip":"https://t.me/DropfansBot/app?startapp=t_valeria","tipTemplate":"https://t.me/DropfansBot/app?startapp=pt_{cents}_valeria","tipWithRefTemplate":"https://t.me/DropfansBot/app?startapp=tm_{cents}_{externalRef}_valeria","subscribe":"https://t.me/DropfansBot/app?startapp=s_valeria","buyTemplate":"https://t.me/DropfansBot/app?startapp=b_{productId}","buyWithRefTemplate":"https://t.me/DropfansBot/app?startapp=b_{productId}_{externalRef}"}}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: Your app has the Links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"409":{"description":"The creator has no username yet. Have the creator pick a handle in their Dropfans settings, then retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Set a username first","code":"username_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-links","x-dropfans-category":"links","x-dropfans-agency-permission":null,"x-dropfans-mirror-of":"getLinks"},"post":{"operationId":"createLinkForCreator","tags":["links"],"summary":"Create a link for a drop, a tip, a subscription or the profile (for a creator)","description":"Same as `createLink` (POST /api/external/v1/links), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key).","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"What the link opens.","enum":["buy","tip","subscribe","profile"]},"productId":{"type":"string","description":"The drop, for `buy` (required there, refused otherwise). Must belong to the account."},"amountUsd":{"type":"number","description":"Fixed tip amount for `tip` ($5–$750). Omit to let the fan pick."},"externalRef":{"type":"string","description":"Your per-fan reference, returned on the sale.","maxLength":32,"pattern":"^[A-Za-z0-9_-]{1,32}$"}},"required":["type"]},"examples":{"buy":{"summary":"One drop, one fan","value":{"type":"buy","productId":"cmv5tmpcm0015h4oucxkgc4ma","externalRef":"tg_48213377"}},"tip":{"summary":"A $20 tip link","value":{"type":"tip","amountUsd":20,"externalRef":"tg_48213377"}}}}}},"responses":{"200":{"description":"The link (new, or the existing one for this exact request).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"},"example":{"id":"q7m2c8zk4w","type":"buy","url":"https://www.dropfans.io/buy/q7m2c8zk4w","telegram":"https://t.me/DropfansBot/app?startapp=q7m2c8zk4w","productId":"cmv5tmpcm0015h4oucxkgc4ma","amountUsd":null,"externalRef":"tg_48213377","createdAt":"2026-10-29T12:00:00.000Z"}}}},"400":{"description":"Unknown `type`. Also `invalid_external_ref`, `invalid_amount` (out of range, or not a tip) and `invalid_product` (productId on a non-buy link). Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"type must be one of profile, tip, subscribe, buy","code":"invalid_type"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: Your app has the Links [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"`productId` is missing, unknown or another account’s.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Drop not found","code":"product_not_found"}}}},"409":{"description":"The creator has no username yet.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Set a username first","code":"username_required"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/create-link","x-dropfans-category":"links","x-dropfans-agency-permission":null,"x-dropfans-mirror-of":"createLink"}},"/api/external/v1/creators/{creatorId}/notifications":{"get":{"operationId":"getNotificationsForCreator","tags":["notifications"],"summary":"Read the Telegram notification status (for a creator)","description":"Same as `getNotifications` (GET /api/external/v1/notifications), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canEditProfile`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The current connection state.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationsStatus"},"example":{"telegramHandle":"valeria_tg","personalConnected":true,"groupConnected":false,"groupChatId":null,"groupName":null}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account. Also: Your app has the Telegram notifications [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"The key’s account no longer exists.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"User not found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-notifications","x-dropfans-category":"notifications","x-dropfans-agency-permission":"canEditProfile","x-dropfans-mirror-of":"getNotifications"},"put":{"operationId":"updateNotificationsForCreator","tags":["notifications"],"summary":"Update Telegram notification settings (for a creator)","description":"Same as `updateNotifications` (PUT /api/external/v1/notifications), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canEditProfile`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","description":"Which operation to perform.","enum":["save-handle","disconnect","add-group"]},"telegramHandle":{"type":"string","description":"save-handle only: the @handle (leading @ is stripped).","example":"valeria_tg"},"type":{"type":"string","description":"disconnect only: what to clear.","enum":["personal","group","all"]},"groupChatId":{"type":"string","description":"add-group only: the Telegram chat id of a group/channel the bot is in.","example":"-1001234567890"}},"required":["action"]},"examples":{"saveHandle":{"summary":"Save the creator’s handle","value":{"action":"save-handle","telegramHandle":"valeria_tg"}},"addGroup":{"summary":"Register a notification group","value":{"action":"add-group","groupChatId":"-1001234567890"}},"disconnect":{"summary":"Disconnect everything","value":{"action":"disconnect","type":"all"}}}}}},"responses":{"200":{"description":"Action applied. save-handle echoes `telegramHandle`; add-group echoes `groupName`; disconnect returns `{success:true}` alone.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true},"telegramHandle":{"type":"string","description":"save-handle only: the stored handle (without @)."},"groupName":{"type":"string","description":"add-group only: the group’s title as Telegram reports it."}},"required":["success"]},"example":{"success":true,"groupName":"Valeria sales"}}}},"400":{"description":"The body is not valid JSON. Also: save-handle without a handle. Also: save-handle with an empty handle after stripping @. Also: disconnect with a bad type. Also: add-group without a chat id. Also: Telegram does not know the chat, or the bot is not a member. Also: add-group with a personal chat id. Also: `action` is none of the three. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account. Also: Your app has the Telegram notifications [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/update-notifications","x-dropfans-category":"notifications","x-dropfans-agency-permission":"canEditProfile","x-dropfans-mirror-of":"updateNotifications"}},"/api/external/v1/creators/{creatorId}/register-telegram-chat":{"post":{"operationId":"registerTelegramChatForCreator","tags":["notifications"],"summary":"Register the creator’s personal notification chat (for a creator)","description":"Same as `registerTelegramChat` (POST /api/external/v1/register-telegram-chat), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canEditProfile`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"telegramChatId":{"type":"string","description":"The Telegram chat id of the creator’s DM with the notification bot. Stored as-is, unverified.","example":"123456789"}},"required":["telegramChatId"]},"examples":{"register":{"summary":"Register a personal chat","value":{"telegramChatId":"123456789"}}}}}},"responses":{"200":{"description":"Stored.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"400":{"description":"The body is not valid JSON. Also: Missing or non-string chat id. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canEditProfile` on that account. Also: Your app has the Telegram notifications [API category](/developers/concepts/api-categories) switched off.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/register-telegram-chat","x-dropfans-category":"notifications","x-dropfans-agency-permission":"canEditProfile","x-dropfans-mirror-of":"registerTelegramChat"}},"/api/external/v1/creators/{creatorId}/payouts/summary":{"get":{"operationId":"getPayoutSummaryForCreator","tags":["payouts"],"summary":"Payout balance, eligibility and status (for a creator)","description":"Same as `getPayoutSummary` (GET /api/external/v1/payouts/summary), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The summary. Money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayoutSummary"},"example":{"accountId":"clx2f8a1b0001qw3k","currency":"USD","pendingCents":12050,"availableCents":34210,"processingCents":0,"paidOutCents":187500,"sides":{"creator":{"pendingCents":12050,"availableCents":34210,"processingCents":0,"paidOutCents":175500},"agency":{"pendingCents":0,"availableCents":0,"processingCents":0,"paidOutCents":12000},"affiliate":{"pendingCents":0,"availableCents":0,"processingCents":0,"paidOutCents":0},"share":{"pendingCents":0,"availableCents":0,"processingCents":0,"paidOutCents":0}},"requestableCents":34210,"minimumPayoutCents":2000,"payoutsEnabled":true,"kycVerified":true,"defaultMethod":{"id":"clxpm0001method","type":"MASSPAY","isDefault":true,"nickname":null,"label":"Payout wallet · SWE","holderType":"INDIVIDUAL","createdAt":"2026-09-02T10:00:00.000Z","paxum":null,"masspay":{"country":"SWE","currency":null,"payerName":null,"activated":true},"bank":null},"openRequest":null,"inFlight":false,"upcoming":[{"availableOn":"2026-11-04","amountCents":4500}],"eligible":true,"ineligibleReasons":[]}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-payout-summary","x-dropfans-category":"payouts","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"getPayoutSummary"}},"/api/external/v1/creators/{creatorId}/payouts":{"get":{"operationId":"listPayoutsForCreator","tags":["payouts"],"summary":"Payout history (paginated) (for a creator)","description":"Same as `listPayouts` (GET /api/external/v1/payouts), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"since","in":"query","required":false,"description":"Only rows created (requests: made) at or after this time.","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"name":"until","in":"query","required":false,"description":"Only rows created at or before this time.","schema":{"type":"string","format":"date-time"}},{"name":"status","in":"query","required":false,"description":"Comma-separated subset of requested, approved, pending, processing, paid, failed, cancelled, rejected. Default: everything except failed / cancelled payout attempts.","schema":{"type":"string"},"example":"paid"},{"name":"kind","in":"query","required":false,"description":"Comma-separated subset of payout, manual, request. Default: all three.","schema":{"type":"string"}},{"name":"includeReversed","in":"query","required":false,"description":"Also return reversed wallet loads and their negative reversal rows.","schema":{"type":"boolean","default":false}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`nextCursor` from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of rows. Money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"payouts":{"type":"array","items":{"$ref":"#/components/schemas/Payout"},"description":"Newest first."},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}},"required":["payouts"]},"example":{"payouts":[{"id":"clxpr0001request","kind":"request","status":"requested","amountCents":34210,"currency":"USD","side":"creator","sides":{"creatorCents":34210,"agencyCents":0,"affiliateCents":0,"shareCents":0},"method":{"type":"MASSPAY","label":"Payout wallet · SWE"},"note":"October","failureMessage":null,"invoiceNumber":null,"requestId":null,"payoutId":null,"createdAt":"2026-10-30T09:12:00.000Z","initiatedAt":null,"paidAt":null,"failedAt":null,"reversedAt":null,"reversalOfId":null},{"id":"clxpo0001payout","kind":"payout","status":"paid","amountCents":52000,"currency":"USD","side":"combined","sides":{"creatorCents":40000,"agencyCents":12000,"affiliateCents":0,"shareCents":0},"method":{"type":"PAXUM_P2P","label":"Paxum · j***@example.com"},"note":null,"failureMessage":null,"invoiceNumber":1042,"requestId":"clxpr0000request","payoutId":null,"createdAt":"2026-10-15T08:00:00.000Z","initiatedAt":"2026-10-15T08:00:05.000Z","paidAt":"2026-10-15T08:03:41.000Z","failedAt":null,"reversedAt":null,"reversalOfId":null}],"nextCursor":null}}}},"400":{"description":"Unparseable `since` (`invalid_until` for `until`). Also: Unknown status (`invalid_kind` for an unknown kind). Also: `limit` out of range. Also: The cursor was not one we returned. Also: `X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"since must be an ISO date","code":"invalid_since"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-payouts","x-dropfans-category":"payouts","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"listPayouts"}},"/api/external/v1/creators/{creatorId}/payouts/{id}":{"get":{"operationId":"getPayoutForCreator","tags":["payouts"],"summary":"One payout or payout request (for a creator)","description":"Same as `getPayout` (GET /api/external/v1/payouts/{id}), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"},{"name":"id","in":"path","required":true,"description":"Row id from the list, a webhook or POST /payouts/requests.","schema":{"type":"string"}}],"responses":{"200":{"description":"The row. Money in cents.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payout"},"example":{"id":"clxpo0001payout","kind":"payout","status":"paid","amountCents":52000,"currency":"USD","side":"combined","sides":{"creatorCents":40000,"agencyCents":12000,"affiliateCents":0,"shareCents":0},"method":{"type":"PAXUM_P2P","label":"Paxum · j***@example.com"},"note":null,"failureMessage":null,"invoiceNumber":1042,"requestId":"clxpr0000request","payoutId":null,"createdAt":"2026-10-15T08:00:00.000Z","initiatedAt":"2026-10-15T08:00:05.000Z","paidAt":"2026-10-15T08:03:41.000Z","failedAt":null,"reversedAt":null,"reversalOfId":null}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"404":{"description":"Unknown id, or it belongs to another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Payout not found","code":"not_found"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/get-payout","x-dropfans-category":"payouts","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"getPayout"}},"/api/external/v1/creators/{creatorId}/payouts/methods":{"get":{"operationId":"listPayoutMethodsForCreator","tags":["payouts"],"summary":"Payout methods (masked) (for a creator)","description":"Same as `listPayoutMethods` (GET /api/external/v1/payouts/methods), acting for the creator in the path: a creator or AI persona your agency manages, or an account your app onboarded (your app owner’s own key). For a managed creator the agency needs `canViewStats`.","parameters":[{"name":"creatorId","in":"path","required":true,"description":"Account id from GET /api/external/v1/creators.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}],"responses":{"200":{"description":"The methods.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"X-Dropfans-Account":{"$ref":"#/components/headers/XDropfansAccountEcho"}},"content":{"application/json":{"schema":{"type":"object","properties":{"methods":{"type":"array","items":{"$ref":"#/components/schemas/PayoutMethodSummary"},"description":"Default first, then newest first."}},"required":["methods"]},"example":{"methods":[{"id":"clxpm0001method","type":"PAXUM_P2P","isDefault":true,"nickname":null,"label":"Paxum · j***@example.com","holderType":"INDIVIDUAL","createdAt":"2026-09-02T10:00:00.000Z","paxum":{"email":"j***@example.com","lookupStatus":"active","verificationStatus":"COMPLETED"},"masspay":null,"bank":null}]}}}},"400":{"description":"`X-Dropfans-Account` is not an account id. Also: Called under /v1/creators/{creatorId}/ with an `X-Dropfans-Account` naming another account.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"X-Dropfans-Account must be an account id (from GET /api/external/agency/creators), not a username.","code":"invalid_account_header"}}}},"401":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"403":{"description":"The creator in the path (or `X-Dropfans-Account`) is one this key cannot act for: no ACCEPTED management by your agency and not an account your app onboarded (or it no longer holds a key bound to your app), a key minted for one creator, or someone is suspended, banned or deleted. An unknown id gets the same answer. Also: For a managed creator: the agency lacks `canViewStats` on that account. Also: Your app has the Payouts [API category](/developers/concepts/api-categories) switched off (the default for new apps).","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This key cannot act for that account.","code":"account_not_managed"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"x-dropfans-docs":"https://www.dropfans.io/developers/reference/list-payout-methods","x-dropfans-category":"payouts","x-dropfans-agency-permission":"canViewStats","x-dropfans-mirror-of":"listPayoutMethods"}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"dpfn_ + 64 hex characters","description":"Your Dropfans API key, sent as `Authorization: Bearer dpfn_...`. By default a key acts for\nthe one account it belongs to. A verified agency’s own key can also act for any account\nthe agency manages by sending `X-Dropfans-Account: <account id>`. Keys are generated in\nthe Dropfans dashboard under Vault → API Connect (direct link: https://www.dropfans.io/dashboard/vault?apiConnect=1)\nand pick which app the key is for at mint. Treat keys like passwords — never paste one into a\nshared or public chat."}},"headers":{"XRateLimitTier":{"description":"Rate-limit tier of the key: personal, app or first_party (first_party is unlimited).","schema":{"type":"string","enum":["personal","app","first_party"]}},"XRateLimitLimit":{"description":"Requests allowed per minute for this key (absent on first_party).","schema":{"type":"integer"}},"XRateLimitRemaining":{"description":"Requests left in the current minute window.","schema":{"type":"integer"}},"XRateLimitReset":{"description":"Epoch seconds when the minute window resets.","schema":{"type":"integer"}},"XRateLimitLimitDay":{"description":"Requests allowed per UTC day for this key (absent on first_party).","schema":{"type":"integer"}},"XRateLimitRemainingDay":{"description":"Requests left in the current UTC day window.","schema":{"type":"integer"}},"XRateLimitResetDay":{"description":"Epoch seconds when the day window resets.","schema":{"type":"integer"}},"RetryAfter":{"description":"Seconds to wait before retrying (sent with 429s).","schema":{"type":"integer"}},"XDropfansAccountEcho":{"description":"The id of the account this request acted on — the key’s own account, or the managed account named in the X-Dropfans-Account request header. Assert it when acting for several accounts.","schema":{"type":"string"}}},"parameters":{"XDropfansAccount":{"name":"X-Dropfans-Account","in":"header","required":false,"deprecated":true,"description":"Deprecated: call the …ForCreator operation (/api/external/v1/creators/{creatorId}/…) instead; the header keeps working and such responses carry Deprecation and Link: rel=\"successor-version\". With a verified agency’s own key, the id of a creator or AI persona the agency manages (from GET /api/external/v1/agency/creators): the request then acts as that account, exactly as if it were sent with that account’s own key. Account ids only — usernames are refused (400 invalid_account_header). Checked on every request: the management must be ACCEPTED, nobody may be suspended, banned or deleted (else 403 account_not_managed), and the agency needs the endpoint’s permission on that account (else 403 permission_denied). Omit it to act as the key’s own account.","schema":{"type":"string","pattern":"^c[a-z0-9]{20,32}$"},"example":"cmh4v2q8k0003xy9z7w6v5u4t"}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Unauthorized","code":"unauthorized"}}}},"AppSuspended":{"description":"The app this key belongs to has been suspended by Dropfans. Every request fails with this until the app is reinstated — surface it to the creator and contact Dropfans.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"This integration has been suspended by Dropfans. Contact the app developer.","code":"app_suspended"}}}},"RateLimited":{"description":"Rate limit exceeded for the current minute or day window. Wait Retry-After seconds and retry.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"},"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"X-RateLimit-Limit-Day":{"$ref":"#/components/headers/XRateLimitLimitDay"},"X-RateLimit-Remaining-Day":{"$ref":"#/components/headers/XRateLimitRemainingDay"},"X-RateLimit-Reset-Day":{"$ref":"#/components/headers/XRateLimitResetDay"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorWithCode"},"example":{"error":"Rate limit exceeded","code":"rate_limited"}}}},"InvalidJson":{"description":"The request body is not valid JSON.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid JSON body"}}}},"NotFound":{"description":"The resource does not exist on this creator’s account. Another creator’s ids also 404 — never 403 — so ids cannot be probed.","headers":{"X-RateLimit-Tier":{"$ref":"#/components/headers/XRateLimitTier"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Not found"}}}}},"schemas":{"Me":{"type":"object","properties":{"id":{"type":"string","description":"The Dropfans user id of the account this request acted on — the key’s own account, or the managed account named in `X-Dropfans-Account`. Stable — safe to key your own records on.","example":"clx2f8a1b0001qw3k"},"username":{"type":["string","null"],"description":"The creator’s public @handle, without the @. Null until the creator picks one — several link surfaces (GET /api/external/v1/links, the post `url`) need it.","example":"valeria"},"name":{"type":["string","null"],"description":"Display name. Null when unset.","example":"Valeria"},"image":{"type":["string","null"],"description":"Profile image URL. Null when the creator has no avatar.","format":"uri"},"accountType":{"type":"string","description":"Account class of the account acted on. Posting to the For You feed requires CREATOR or AGENCY.","enum":["CONSUMER","CREATOR","AGENCY"],"example":"CREATOR"},"sellerStatus":{"type":"string","description":"Internal seller state, for support (PENDING_KYC, KYC_IN_REVIEW, KYC_REJECTED, VERIFIED_CREATOR, VERIFIED_AGENCY). Added 2026-10-15.","example":"VERIFIED_CREATOR"},"isAgency":{"type":"boolean","description":"True when the account is a verified agency (sellerStatus VERIFIED_AGENCY) — its own key can use the /api/external/v1/agency endpoints and `X-Dropfans-Account`. Added 2026-10-15.","example":false},"kycStatus":{"type":"string","description":"Coarse ID-check state. `covered_by_agency` = an AI persona whose verification rides on its agency’s. Added 2026-10-15.","enum":["not_started","session_created","in_review","processing","approved","rejected","covered_by_agency"],"example":"approved"},"key":{"type":"object","properties":{"name":{"type":"string","description":"The key’s label, chosen at mint (defaults to the app name, or \"Personal\").","example":"KVIQA"},"app":{"type":["object","null"],"properties":{"slug":{"type":"string","description":"Stable app identifier.","example":"kviqa"},"name":{"type":"string","description":"App display name.","example":"KVIQA"}},"description":"The integration this key was minted for. Null for a Personal key."},"tier":{"type":"string","description":"Rate-limit tier of this key — the same value the X-RateLimit-Tier response header carries.","enum":["personal","app","first_party"],"example":"app"},"managedBy":{"type":["object","null"],"properties":{"id":{"type":"string","description":"The agency’s user id."},"username":{"type":["string","null"],"description":"The agency’s @handle."},"name":{"type":["string","null"],"description":"The agency’s display name."}},"description":"The agency managing the account through this key: the key’s holder when `viaAgency` is true, else the agency that minted this key for the creator. Null for a creator’s own key."},"viaAgency":{"type":"boolean","description":"True when an agency’s own key is acting for a managed account — via /api/external/v1/creators/{creatorId}/… or `X-Dropfans-Account` (added 2026-10-26).","example":false},"via":{"type":"string","description":"How the key reached this account: `self` = its own account, `agency` = an agency acting for a managed creator, `app` = an app owner acting for an account its app onboarded (added 2026-11-01).","enum":["self","agency","app"],"example":"self"},"apiCategories":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ApiCategoryState"},"description":"The key’s app’s API category switches (see /developers/concepts/api-categories). Null for a Personal key, which has none. Added 2026-11-01."}},"description":"Metadata about the API key used on this request (added 2026-08-19)."}},"required":["id"]},"ApiCategoryState":{"type":"object","properties":{"id":{"type":"string","description":"Category id — the `category` of a 403 `api_category_disabled`.","example":"payouts"},"label":{"type":"string","description":"Human-readable name.","example":"Payouts"},"enabled":{"type":"boolean","description":"Whether your app may call this category’s endpoints.","example":false},"locked":{"type":"boolean","description":"True for categories that are always on (account).","example":false}},"required":["id","label","enabled","locked"]},"AgencyPermissions":{"type":"object","properties":{"canEditProfile":{"type":"boolean","description":"Profile, timezone, subscription tier and Telegram notification settings."},"canManageDrops":{"type":"boolean","description":"Drops, orders and posts."},"canManageVault":{"type":"boolean","description":"Vault media, folders, tags and video uploads."},"canViewStats":{"type":"boolean","description":"Earnings, tips, balance and subscription reads."},"canManageCoPerformers":{"type":"boolean","description":"Co-performer management (dashboard only — no API endpoint uses it yet)."}},"required":["canEditProfile","canManageDrops","canManageVault","canViewStats","canManageCoPerformers"]},"AgencyCreator":{"type":"object","properties":{"id":{"type":"string","description":"The account’s user id — the value for `X-Dropfans-Account`.","example":"cmh4v2q8k0003xy9z7w6v5u4t"},"managedCreatorId":{"type":"string","description":"Id of the management relationship (not an account id — never send it as `X-Dropfans-Account`)."},"username":{"type":["string","null"],"description":"Public @handle, without the @.","example":"luna_ai"},"name":{"type":["string","null"],"description":"Display name.","example":"Luna"},"image":{"type":["string","null"],"description":"Profile image URL.","format":"uri"},"kind":{"type":"string","description":"`ai_persona` = an AI persona the agency runs; `creator` = a real creator who accepted the agency.","enum":["creator","ai_persona"]},"status":{"type":"string","description":"Relationship status. Only ACCEPTED accounts are returned unless you pass `?status=all`; a retired persona is DEPARTED, an ended creator REVOKED or DEPARTED.","enum":["INVITE_SENT","INVITE_EXPIRED","ACCEPTED","REVOKED","DEPARTED"]},"active":{"type":"boolean","description":"True when `X-Dropfans-Account` works for this account right now: ACCEPTED, and the account is not suspended, banned or deleted."},"kycCoveredByAgency":{"type":"boolean","description":"True when the account’s ID check rides on the agency’s (AI personas)."},"sellerStatus":{"type":"string","description":"Internal seller state, for support.","example":"VERIFIED_CREATOR"},"permissions":{"$ref":"#/components/schemas/AgencyPermissions"},"profileUrl":{"type":["string","null"],"description":"Public profile URL. Null until the account has a username.","format":"uri"},"since":{"type":["string","null"],"description":"When the relationship was accepted.","format":"date-time"}},"required":["id","managedCreatorId","kind","status","active","kycCoveredByAgency","sellerStatus","permissions"]},"AgencyCreatorList":{"type":"object","properties":{"agency":{"type":"object","properties":{"id":{"type":"string","description":"The agency’s user id."},"username":{"type":["string","null"],"description":"The agency’s @handle."},"name":{"type":["string","null"],"description":"The agency’s display name."}},"required":["id"],"description":"The agency holding the key."},"creators":{"type":"array","items":{"$ref":"#/components/schemas/AgencyCreator"},"description":"Managed creators and AI personas, oldest relationship first."}},"required":["agency","creators"]},"PersonaCreated":{"type":"object","properties":{"id":{"type":"string","description":"The persona’s user id — use it in `X-Dropfans-Account`.","example":"cmh4v2q8k0003xy9z7w6v5u4t"},"managedCreatorId":{"type":"string","description":"Id of the agency ↔ persona relationship."},"username":{"type":"string","description":"The persona’s @handle.","example":"luna_ai"},"name":{"type":["string","null"],"description":"Display name (defaults to the username).","example":"Luna"},"kind":{"type":"string","description":"Always `ai_persona`.","enum":["ai_persona"]},"profileUrl":{"type":"string","description":"Public profile URL.","format":"uri"},"profileError":{"type":"string","description":"Present only when an extra profile field in the request was refused. The persona was still created — fix the field and send it with PATCH /api/external/v1/profile."}},"required":["id","managedCreatorId","username","kind","profileUrl"]},"AgencyInvite":{"type":"object","properties":{"inviteId":{"type":"string","description":"The invite’s id."},"inviteLink":{"type":"string","description":"Join link for the creator. They accept while signed in to their own Dropfans account.","format":"uri"},"expiresAt":{"type":"string","description":"When the link stops working (72 hours after creation).","format":"date-time"},"emailSent":{"type":"boolean","description":"True when Dropfans emailed the link to `email`."},"emailError":{"type":"string","description":"Present when `email` was given but sending failed — the invite still exists; share `inviteLink` yourself."}},"required":["inviteId","inviteLink","expiresAt","emailSent"]},"AgencyInviteRow":{"type":"object","properties":{"id":{"type":"string","description":"The invite’s id (`inviteId` when it was created).","example":"cmh5inv0001ab7k2p9q4r8s"},"status":{"type":"string","description":"`accepted` once a creator used the link (it stays accepted), `revoked` after DELETE, `expired` 72 hours after creation, else `pending`.","enum":["pending","accepted","expired","revoked"],"example":"pending"},"email":{"type":["string","null"],"description":"The address it was emailed to, or null.","format":"email"},"message":{"type":["string","null"],"description":"The personal note, or null."},"createdAt":{"type":"string","description":"When the invite was created.","format":"date-time"},"expiresAt":{"type":"string","description":"When the link stops working.","format":"date-time"},"acceptedAt":{"type":["string","null"],"description":"When a creator accepted it, or null.","format":"date-time"},"acceptedBy":{"type":["string","null"],"description":"The account id that accepted it, or null."}},"required":["id","status","createdAt","expiresAt"]},"RosterCreator":{"type":"object","properties":{"id":{"type":"string","description":"Account id — the `{creatorId}` of /api/external/v1/creators/{creatorId}/….","example":"cmh4v2q8k0003xy9z7w6v5u4t"},"username":{"type":["string","null"],"description":"Public @handle, without the @.","example":"valeria"},"name":{"type":["string","null"],"description":"Display name.","example":"Valeria"},"image":{"type":["string","null"],"description":"Profile image URL.","format":"uri"},"relationship":{"type":"string","description":"`managed` = a creator who accepted your agency; `ai_persona` = a persona your agency runs; `onboarded` = an account your app created with POST /accounts.","enum":["managed","ai_persona","onboarded"],"example":"ai_persona"},"active":{"type":"boolean","description":"Whether creator-scoped calls are accepted right now. False when the account is suspended, banned or deleted — or, for `onboarded`, when it no longer holds a key bound to your app (the creator revoked your access).","example":true},"permissions":{"$ref":"#/components/schemas/AgencyPermissions"},"creatorPath":{"type":"string","description":"Prefix for creator-scoped calls, e.g. `${creatorPath}/drops`.","example":"/api/external/v1/creators/cmh4v2q8k0003xy9z7w6v5u4t"},"profileUrl":{"type":["string","null"],"description":"Public profile URL, null until the account has a username.","format":"uri"},"since":{"type":["string","null"],"description":"When the management was accepted, or when your app created the account.","format":"date-time"}},"required":["id","relationship","active","permissions","creatorPath"]},"RevenueTotals":{"type":"object","properties":{"gross":{"type":"number","description":"USD **dollars**, buyer-paid minus VAT, excluding refunds and chargebacks.","example":1240.5},"net":{"type":"number","description":"USD dollars, the seller’s earnings after the platform fee.","example":992.4},"sales":{"type":"integer","description":"Paid drop orders.","example":31},"tips":{"type":"integer","description":"Paid tips.","example":12},"subscriptionPayments":{"type":"integer","description":"Subscription charges and renewals.","example":9}},"required":["gross","net","sales","tips","subscriptionPayments"]},"AgencyStats":{"type":"object","properties":{"startDate":{"type":"string","description":"First UTC day included.","format":"date","example":"2026-09-27"},"endDate":{"type":"string","description":"Last UTC day included.","format":"date","example":"2026-10-26"},"currency":{"type":"string","description":"Always \"USD\".","enum":["USD"]},"total":{"$ref":"#/components/schemas/RevenueTotals"},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The account’s user id."},"username":{"type":["string","null"],"description":"Public @handle."},"name":{"type":["string","null"],"description":"Display name."},"kind":{"type":"string","description":"`agency` = the agency’s own account; `creator` = a managed creator or AI persona.","enum":["agency","creator"]},"gross":{"type":"number","description":"USD dollars, as in RevenueTotals."},"net":{"type":"number","description":"USD dollars, as in RevenueTotals."},"sales":{"type":"integer","description":"Paid drop orders."},"tips":{"type":"integer","description":"Paid tips."},"subscriptionPayments":{"type":"integer","description":"Subscription charges and renewals."}},"required":["id","kind","gross","net","sales","tips","subscriptionPayments"],"description":"One account’s figures: id, username, name, kind plus the RevenueTotals fields."},"description":"The agency’s own account first, then every ACCEPTED managed account it may see stats for (canViewStats)."}},"required":["startDate","endDate","currency","total","accounts"]},"Profile":{"type":"object","properties":{"id":{"type":"string","description":"The account’s user id.","example":"cmh4v2q8k0003xy9z7w6v5u4t"},"username":{"type":["string","null"],"description":"Public @handle, without the @.","example":"luna_ai"},"displayName":{"type":["string","null"],"description":"Display name.","example":"Luna"},"bio":{"type":["string","null"],"description":"Profile bio."},"profileVisible":{"type":"boolean","description":"Whether the public profile is visible."},"location":{"type":["string","null"],"description":"Free-text location."},"websiteUrl":{"type":["string","null"],"description":"Website link."},"twitterHandle":{"type":["string","null"],"description":"X / Twitter handle."},"instagramHandle":{"type":["string","null"],"description":"Instagram handle."},"tiktokHandle":{"type":["string","null"],"description":"TikTok handle."},"snapchatHandle":{"type":["string","null"],"description":"Snapchat handle."},"threadsHandle":{"type":["string","null"],"description":"Threads handle."},"youtubeHandle":{"type":["string","null"],"description":"YouTube handle."},"telegramHandle":{"type":["string","null"],"description":"Telegram handle."},"whatsappNumber":{"type":["string","null"],"description":"WhatsApp number."},"imessageHandle":{"type":["string","null"],"description":"iMessage handle."},"primaryContactPlatform":{"type":["string","null"],"description":"Which contact platform the profile highlights."},"avatarUrl":{"type":["string","null"],"description":"Profile image. Signed URL, valid 24 hours — do not store it.","format":"uri"},"bannerUrl":{"type":["string","null"],"description":"Banner image. Signed URL, valid 24 hours — do not store it.","format":"uri"},"avatarModerationStatus":{"type":["string","null"],"description":"PENDING, APPROVED, REJECTED or FLAGGED for the profile image (a new image shows once approved); null when there is none."},"bannerModerationStatus":{"type":["string","null"],"description":"PENDING, APPROVED, REJECTED or FLAGGED for the banner image; null when there is none."}},"required":["id","profileVisible"]},"SubscriptionTier":{"type":"object","properties":{"priceUsd":{"type":"number","description":"USD **dollars** per interval. 0 = free subscription.","example":9.99},"currency":{"type":"string","description":"Always \"USD\".","enum":["USD"]},"interval":{"type":"string","description":"Billing interval.","enum":["monthly","weekly"]},"trialDays":{"type":"integer","description":"Free trial length in days (0 = none).","example":0},"description":{"type":["string","null"],"description":"What subscribers get."},"pitchMessage":{"type":["string","null"],"description":"Short pitch shown in the subscribe sheet."},"isActive":{"type":"boolean","description":"False = paused: no new sign-ups. Existing subscribers are unaffected."}},"required":["priceUsd","currency","interval","trialDays","isActive"]},"Subscription":{"type":"object","properties":{"tier":{"anyOf":[{"$ref":"#/components/schemas/SubscriptionTier"},{"type":"null"}],"description":"The subscription tier, or null when none is set up."},"subscribeUrl":{"type":["string","null"],"description":"The web link that opens the subscribe sheet. Null until the account has a username. (Only in GET.)","format":"uri"}}},"Timezone":{"type":"object","properties":{"timezone":{"type":"string","description":"IANA timezone name (e.g. \"Europe/Stockholm\"). Defaults to \"UTC\" when the creator never set one.","format":"iana-timezone","example":"Europe/Stockholm"}},"required":["timezone"]},"Balance":{"type":"object","properties":{"currency":{"type":"string","description":"Always \"USD\".","enum":["USD"]},"pending":{"type":"number","description":"USD **dollars** (not cents — unlike earnings and check-status). Creator side (own sales) still inside the chargeback hold window; not payable yet. For everything the account owns, read `total`.","example":120.5},"available":{"type":"number","description":"USD dollars, creator side. Cleared the hold. Can be negative.","example":300.1},"processing":{"type":"number","description":"USD dollars, creator side. Included in a payout that is currently being sent.","example":0},"paidOut":{"type":"number","description":"USD dollars, creator side. Lifetime total of completed payouts.","example":1755},"total":{"$ref":"#/components/schemas/BalanceBuckets"},"sides":{"type":"object","properties":{"creator":{"$ref":"#/components/schemas/BalanceBuckets"},"agency":{"$ref":"#/components/schemas/BalanceBuckets"},"affiliate":{"$ref":"#/components/schemas/BalanceBuckets"},"share":{"$ref":"#/components/schemas/BalanceBuckets"}},"required":["creator","agency","affiliate","share"],"description":"Added 2026-10-30. The four buckets per side, USD dollars; they sum to `total`. `sides.creator` equals the top-level buckets."}},"required":["currency","pending","available","processing","paidOut","total","sides"]},"VaultItem":{"type":"object","properties":{"id":{"type":"string","description":"Vault item id — use as `vaultItemId` when creating drops and MEDIA posts.","example":"clxv1a2b30001item"},"fileName":{"type":"string","description":"Original file name as uploaded.","example":"beach-set-01.jpg"},"filePath":{"type":"string","description":"Display asset URL. Images: the CDN display copy. Audio: a token-signed URL valid ~12 hours, directly fetchable. Videos: the Bunny Stream playback URL (DRM-locked — use `downloadUrl` to fetch bytes). **Empty string `\"\"` for items that are not APPROVED** (visible only with includePending=true): unapproved content may never be forwarded."},"thumbnailPath":{"type":["string","null"],"description":"Thumbnail URL. For videos this is always rebuilt as an absolute Bunny Stream thumbnail from the current CDN host. Null for audio (voice messages have no visual)."},"fileType":{"type":"string","description":"Media kind.","enum":["image","video","audio"]},"fileSize":{"type":["integer","null"],"description":"Size in bytes of the stored display asset.","example":482113},"durationSeconds":{"type":["integer","null"],"description":"Audio (voice message) length in seconds. Null for images and videos.","example":42},"bunnyStreamId":{"type":["string","null"],"description":"Bunny Stream GUID for videos — the id you poll with POST /api/external/v1/vault/video-status. Null for images and audio."},"createdAt":{"type":"string","description":"Upload time.","format":"date-time"},"folderId":{"type":["string","null"],"description":"Containing folder id, or null for unfiled (\"All\")."},"contentTags":{"type":"array","items":{"type":"string","description":"A content tag (≤64 chars)."},"description":"The item’s content tags (set via PATCH /api/external/v1/vault/{id}/tags)."},"downloadUrl":{"type":["string","null"],"description":"Token-signed, directly fetchable original — valid ~12 hours. Videos: the DRM-free Bunny Storage original (null for videos uploaded before dual-store existed — those cannot be fetched). Audio: the same signed voice file as `filePath`. **Always null for images** (fetch `filePath` instead) and for non-APPROVED items."},"moderationStatus":{"type":"string","description":"**Only present when the request had includePending=true.** Default responses contain APPROVED items only and omit this field entirely, keeping the shape byte-identical for older consumers.","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]}},"required":["id","fileName","filePath","fileType","createdAt","contentTags"]},"VaultItemUploaded":{"type":"object","properties":{"id":{"type":"string","description":"The new vault item id.","example":"clxv1a2b30001item"},"fileName":{"type":"string","description":"The `originalName` you sent.","example":"beach-set-01.jpg"},"filePath":{"type":"string","description":"CDN URL of the stored display asset (images/audio) or the Stream playback URL (videos)."},"thumbnailPath":{"type":["string","null"],"description":"Thumbnail URL. Null for audio."},"fileType":{"type":"string","description":"Media kind, echoing the request.","enum":["image","video","audio"]},"fileSize":{"type":["integer","null"],"description":"Stored size in bytes.","example":482113},"durationSeconds":{"type":["integer","null"],"description":"Voice-message length in seconds (audio only, when you sent it). Null otherwise."},"bunnyStreamId":{"type":["string","null"],"description":"Bunny Stream GUID (video uploads only)."},"createdAt":{"type":"string","description":"Creation time.","format":"date-time"}},"required":["id","fileName","filePath","fileType","createdAt"]},"VideoVaultItem":{"type":"object","properties":{"id":{"type":"string","description":"The new vault item id.","example":"clxv9z8y70002item"},"fileName":{"type":"string","description":"The `originalName` you sent.","example":"teaser.mp4"},"filePath":{"type":"string","description":"Signed playback URL, valid ~1 hour. For a long-lived URL, re-list the vault later."},"thumbnailPath":{"type":["string","null"],"description":"Signed Stream thumbnail (600px wide)."},"fileType":{"type":"string","description":"Always \"video\" here.","enum":["video"]},"fileSize":{"type":["integer","null"],"description":"Byte count Bunny reported for the finished upload.","example":52428800},"bunnyStreamId":{"type":["string","null"],"description":"The Stream GUID — poll POST /api/external/v1/vault/video-status with it while the video transcodes."},"moderationStatus":{"type":"string","description":"Starts PENDING — the NSFW pipeline finalizes it asynchronously. The item only appears in the default vault list once APPROVED.","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]},"moderationTags":{"type":"array","items":{"type":"string","description":"Moderation label."},"description":"Always empty at creation (moderation has not run yet)."},"createdAt":{"type":"string","description":"Creation time.","format":"date-time"},"aiEnhanced":{"type":"boolean","description":"True when the account is AI-labelled — every upload from such an account is force-marked AI."}},"required":["id","fileName","filePath","fileType","moderationStatus","moderationTags","createdAt","aiEnhanced"]},"Folder":{"type":"object","properties":{"id":{"type":"string","description":"Folder id.","example":"clxf0ld3r0001abcd"},"name":{"type":"string","description":"Folder name — unique per creator.","example":"Beach set"},"itemCount":{"type":"integer","description":"Items in the folder. NOTE: GET /api/external/v1/vault counts only items visible at that call’s moderation filter, while GET /api/external/v1/vault/folders counts every non-hidden item regardless of moderation status — the same folder can report two different counts.","example":12}},"required":["id","name","itemCount"]},"VaultListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/VaultItem"},"description":"The requested page, newest first."},"folders":{"type":"array","items":{"$ref":"#/components/schemas/Folder"},"description":"All of the creator’s folders (unpaginated), with counts under the current moderation filter."},"hasMore":{"type":"boolean","description":"True when more pages exist for the current filter."},"total":{"type":"integer","description":"Total items matching the filter.","example":128},"page":{"type":"integer","description":"Echoed page number (1-based).","example":1},"limit":{"type":"integer","description":"Echoed page size.","example":50}},"required":["items","folders","hasMore","total","page","limit"]},"VideoUploadCredentials":{"type":"object","properties":{"videoId":{"type":"string","description":"The Bunny Stream GUID created for this upload. Send it back to the complete step, and use it as the TUS `VideoId` metadata.","example":"c2f7f9e2-1111-4222-b333-4d55e6f7a8b9"},"tusEndpoint":{"type":"string","description":"The TUS upload endpoint (https://video.bunnycdn.com/tusupload). Upload the raw file bytes here with a TUS client.","format":"uri"},"libraryId":{"type":"string","description":"Bunny Stream library id — send as the `LibraryId` TUS header."},"signature":{"type":"string","description":"Presigned sha256 — send as the `AuthorizationSignature` TUS header. The Stream API key itself is never exposed."},"expires":{"type":"integer","description":"Unix timestamp (seconds) when the signature expires (~6 hours) — send as the `AuthorizationExpire` TUS header.","example":1755640800},"completionToken":{"type":"string","description":"HMAC token proving this upload was started by your key — required by the complete step. Valid 8 hours."}},"required":["videoId","tusEndpoint","libraryId","signature","expires","completionToken"]},"VideoStatusMap":{"type":"object","description":"Keyed by the Bunny Stream GUIDs you sent. Ids you don’t own, and ids whose Bunny lookup errored, are OMITTED (not reported as failed) — treat a missing key as \"still gated\".","additionalProperties":{"type":"object","properties":{"isReady":{"type":"boolean","description":"Transcoding finished — the video is playable and forwardable."},"isProcessing":{"type":"boolean","description":"Still transcoding — poll again later."},"isFailed":{"type":"boolean","description":"Encoding failed — re-upload."},"length":{"type":"integer","description":"Duration in seconds, once known.","example":74}},"required":["isReady","isProcessing","isFailed"],"description":"Keyed by the Bunny Stream GUIDs you sent. Ids you don’t own, and ids whose Bunny lookup errored, are OMITTED (not reported as failed) — treat a missing key as \"still gated\"."},"propertyNames":{"description":"Keys are the ids you sent ({videoId})."}},"Drop":{"type":"object","properties":{"id":{"type":"string","description":"The product (drop) id.","example":"clxdr0p000001prod"},"name":{"type":["string","null"],"description":"Drop title. Null when created without a name.","example":"Beach set — 6 photos"},"price":{"type":"number","description":"USD **dollars**. 0 means free.","example":25},"currency":{"type":"string","description":"Always \"USD\".","enum":["USD"]},"status":{"type":"string","description":"The drop’s overall moderation status. A drop built from already-APPROVED vault items is APPROVED at creation.","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]},"moderationReason":{"type":["string","null"],"description":"Why the drop was rejected or flagged. Null otherwise."},"buyUrl":{"type":"string","description":"With an app key: your app’s plain buy link id (`/buy/{linkId}`) — created by POST /drops; reads return it when it exists, else `/buy/{productId}` (a drop your app created still counts for it). With a personal key: `/buy/{productId}`. For a per-fan reference, create a link with POST /api/external/v1/links.","format":"uri","example":"https://www.dropfans.io/buy/clxdr0p000001prod"},"linkId":{"type":["string","null"],"description":"The link id in buyUrl (app keys only); comes back as linkId on the sale.","example":"q7m2c8zk4w"},"allowDownload":{"type":"boolean","description":"Images only: whether buyers get a Download button serving a watermarked, metadata-stripped JPEG. Videos are never downloadable (DRM stream). Defaults to false."},"mediaCount":{"type":"integer","description":"Number of media items attached.","example":6},"media":{"type":"array","items":{"type":"object","properties":{"vaultItemId":{"type":"string","description":"The source vault item."},"order":{"type":"integer","description":"Display position (0-based)."},"fileType":{"type":"string","description":"Media kind.","enum":["image","video","audio"]},"moderationStatus":{"type":"string","description":"Per-item moderation status.","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]},"hasPreview":{"type":"boolean","description":"True once a baked blur preview was attached via POST /api/external/v1/drops/{id}/previews."}},"required":["vaultItemId","order","fileType","moderationStatus","hasPreview"],"description":"One attached vault item."},"description":"Attached media in display order."},"salesCount":{"type":"integer","description":"Paid orders, excluding refunds and chargebacks (stricter than check-status, which does NOT exclude refunds).","example":2},"lastSaleAt":{"type":["string","null"],"description":"When the newest counted sale was paid. Null when never sold.","format":"date-time"},"createdAt":{"type":"string","description":"Creation time.","format":"date-time"}},"required":["id","price","currency","status","buyUrl","allowDownload","mediaCount","media","salesCount","createdAt"]},"DropCreated":{"type":"object","properties":{"productId":{"type":"string","description":"The new drop’s id — keep it: check-status, GET /drops/{id}, previews and post attachment all key on it.","example":"clxdr0p000001prod"},"buyUrl":{"type":"string","description":"With an app key: your app’s plain buy link id (`/buy/{linkId}`) — created by POST /drops; reads return it when it exists, else `/buy/{productId}` (a drop your app created still counts for it). With a personal key: `/buy/{productId}`. For a per-fan reference, create a link with POST /api/external/v1/links.","format":"uri","example":"https://www.dropfans.io/buy/clxdr0p000001prod"},"linkId":{"type":["string","null"],"description":"The link id in buyUrl (app keys only); comes back as linkId on the sale.","example":"q7m2c8zk4w"},"mediaCount":{"type":"integer","description":"How many vault items were attached.","example":3}},"required":["productId","buyUrl","mediaCount"]},"DropSummary":{"type":"object","properties":{"id":{"type":"string","description":"The product (drop) id.","example":"clxdr0p000001prod"},"name":{"type":["string","null"],"description":"Drop title.","example":"Beach set — 6 photos"},"description":{"type":["string","null"],"description":"Drop description (only set by editing — create-drop discards it)."},"price":{"type":"number","description":"USD **dollars**. 0 means free.","example":25},"currency":{"type":"string","description":"Always \"USD\".","enum":["USD"]},"accessMode":{"type":"string","description":"`OPEN` = anyone can buy; `SUBS_FREE` = free for subscribers; `SUBS_ONLY_PAID` = only subscribers can buy.","enum":["OPEN","SUBS_FREE","SUBS_ONLY_PAID"]},"allowDownload":{"type":"boolean","description":"Images only: buyers get a watermarked download."},"status":{"type":"string","description":"The drop’s moderation status.","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]},"mediaCount":{"type":"integer","description":"Attached media items.","example":3},"buyUrl":{"type":"string","description":"With an app key: your app’s plain buy link id (`/buy/{linkId}`) — created by POST /drops; reads return it when it exists, else `/buy/{productId}` (a drop your app created still counts for it). With a personal key: `/buy/{productId}`. For a per-fan reference, create a link with POST /api/external/v1/links.","format":"uri","example":"https://www.dropfans.io/buy/clxdr0p000001prod"},"linkId":{"type":["string","null"],"description":"The link id in buyUrl (app keys only); comes back as linkId on the sale.","example":"q7m2c8zk4w"},"createdAt":{"type":"string","description":"Creation time.","format":"date-time"}},"required":["id","price","currency","accessMode","allowDownload","status","mediaCount","buyUrl","createdAt"]},"DropUpdated":{"type":"object","properties":{"id":{"type":"string","description":"The product (drop) id.","example":"clxdr0p000001prod"},"name":{"type":["string","null"],"description":"Drop title."},"description":{"type":["string","null"],"description":"Drop description."},"price":{"type":"number","description":"USD **dollars**. 0 means free."},"accessMode":{"type":"string","description":"Who can buy.","enum":["OPEN","SUBS_FREE","SUBS_ONLY_PAID"]},"moderationStatus":{"type":"string","description":"Same value as `status`.","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]},"currency":{"type":"string","description":"Always \"USD\".","enum":["USD"]},"status":{"type":"string","description":"The drop’s moderation status.","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]},"buyUrl":{"type":"string","description":"With an app key: your app’s plain buy link id (`/buy/{linkId}`) — created by POST /drops; reads return it when it exists, else `/buy/{productId}` (a drop your app created still counts for it). With a personal key: `/buy/{productId}`. For a per-fan reference, create a link with POST /api/external/v1/links.","format":"uri"},"linkId":{"type":["string","null"],"description":"The link id in buyUrl (app keys only); comes back as linkId on the sale.","example":"q7m2c8zk4w"}},"required":["id","price","accessMode","moderationStatus","currency","status","buyUrl"]},"OrdersByProduct":{"type":"object","description":"Every paid order on that product, newest first — one entry per fan on a shared drop.","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/Order"},"description":"Every paid order on that product, newest first — one entry per fan on a shared drop."},"propertyNames":{"description":"Keys are the ids you sent ({productId})."}},"SalesMap":{"type":"object","description":"Keyed by the product ids you sent. Unsold and unknown ids are OMITTED — only entries with paid:true come back. Multiple paid orders on one product report the most recent. Refunded/charged-back orders are NOT excluded here (unlike earnings) — cross-check GET /api/external/v1/earnings for net truth.","additionalProperties":{"type":"object","properties":{"paid":{"type":"boolean","description":"Always true — unsold products simply do not appear.","example":true},"saleAmountCents":{"type":"integer","description":"Gross buyer-paid total in **cents** (order.totalCharged × 100).","example":2500},"buyerEmail":{"type":["string","null"],"description":"The buyer’s email when known, else null.","format":"email"}},"required":["paid","saleAmountCents"],"description":"Keyed by the product ids you sent. Unsold and unknown ids are OMITTED — only entries with paid:true come back. Multiple paid orders on one product report the most recent. Refunded/charged-back orders are NOT excluded here (unlike earnings) — cross-check GET /api/external/v1/earnings for net truth."},"propertyNames":{"description":"Keys are the ids you sent ({productId})."}},"Order":{"type":"object","properties":{"orderId":{"type":"string","description":"The order id. Unique per sale — dedupe on it.","example":"clxor0001order"},"productId":{"type":"string","description":"The drop that was bought.","example":"clxdr0p000001prod"},"accountId":{"type":"string","description":"The creator who sold it (the account behind the key).","example":"clx2f8a1b0001qw3k"},"externalRef":{"type":["string","null"],"description":"Your per-fan checkout reference from the link the buyer opened (`?m=` on the web, `b_{productId}_{ref}` in Telegram). Null when the buyer came without one. Not proof of identity — the buyer can edit the link.","example":"tg_48213377","maxLength":32,"pattern":"^[A-Za-z0-9_-]{1,32}$"},"linkId":{"type":["string","null"],"description":"The link id (POST /api/external/v1/links) it came through; null for template links. Its `externalRef` is the link’s.","example":"q7m2c8zk4w"},"amountCents":{"type":"integer","description":"Gross buyer-paid total in **cents** (VAT included).","example":2750},"netAmountCents":{"type":"integer","description":"What the creator keeps from this sale in **cents** (after the platform fee and VAT; before any agency split).","example":2000},"platformFeeCents":{"type":"integer","description":"Platform fee in cents.","example":500},"taxCents":{"type":"integer","description":"VAT in cents (retained, not paid out).","example":250},"currency":{"type":"string","description":"Always USD.","enum":["USD"],"example":"USD"},"paidAt":{"type":["string","null"],"description":"When the payment settled (UTC).","format":"date-time"},"paidWith":{"type":"string","description":"Card, or the buyer’s prepaid wallet credits.","enum":["card","credits"],"example":"card"},"status":{"type":"string","description":"Current state of the sale.","enum":["paid","refunded","charged_back"],"example":"paid"},"buyer":{"type":"object","properties":{"id":{"type":["string","null"],"description":"The buyer’s account id, when signed in."},"email":{"type":["string","null"],"description":"Billing / account email.","format":"email"},"telegramUserId":{"type":["string","null"],"description":"Telegram user id (as a string) when the buyer used the Mini App — cross-check it against your externalRef.","example":"48213377"},"telegramUsername":{"type":["string","null"],"description":"Telegram @username without the @, when known."}},"description":"Who paid. Every field may be null for a guest checkout."}},"required":["orderId","productId","accountId","amountCents","netAmountCents","platformFeeCents","taxCents","currency","paidWith","status","buyer"]},"Tip":{"type":"object","properties":{"tipId":{"type":"string","description":"The tip id. Unique per tip — dedupe on it.","example":"clxtp0001tip"},"accountId":{"type":"string","description":"The creator who was tipped (the account behind the key).","example":"clx2f8a1b0001qw3k"},"externalRef":{"type":["string","null"],"description":"Your per-fan reference from the tip link the fan opened (`&m=` on the web, `tm_{cents}_{ref}_{username}` in Telegram). Null when the fan came without one. Not proof of identity — the fan can edit the link.","example":"fan-48213377","maxLength":32,"pattern":"^[A-Za-z0-9_-]{1,32}$"},"linkId":{"type":["string","null"],"description":"The link id (POST /api/external/v1/links) it came through; null for template links. Its `externalRef` is the link’s.","example":"q7m2c8zk4w"},"amountCents":{"type":"integer","description":"Gross fan-paid total in **cents** (VAT included).","example":1100},"netAmountCents":{"type":"integer","description":"What the creator keeps from this tip in **cents** (after the platform fee and VAT; before any agency split).","example":850},"platformFeeCents":{"type":"integer","description":"Platform fee in cents.","example":150},"taxCents":{"type":"integer","description":"VAT in cents (retained, not paid out).","example":100},"currency":{"type":"string","description":"Always USD.","enum":["USD"],"example":"USD"},"message":{"type":["string","null"],"description":"The message the fan wrote with the tip, if any.","example":"For the new set 💕","maxLength":280},"paidAt":{"type":["string","null"],"description":"When the payment settled (UTC).","format":"date-time"},"paidWith":{"type":"string","description":"Card, or the fan’s prepaid wallet credits.","enum":["card","credits"],"example":"card"},"status":{"type":"string","description":"Current state of the tip.","enum":["paid","refunded","charged_back"],"example":"paid"},"tipper":{"type":"object","properties":{"id":{"type":["string","null"],"description":"The fan’s account id, when signed in."},"email":{"type":["string","null"],"description":"Billing / account email.","format":"email"},"telegramUserId":{"type":["string","null"],"description":"Telegram user id (as a string) when the fan used the Mini App — cross-check it against your externalRef.","example":"48213377"},"telegramUsername":{"type":["string","null"],"description":"Telegram @username without the @, when known."}},"description":"Who tipped. Every field may be null for a guest checkout."}},"required":["tipId","accountId","amountCents","netAmountCents","platformFeeCents","taxCents","currency","paidWith","status","tipper"]},"CrmAccount":{"type":"object","properties":{"accountId":{"type":"string","description":"The new account’s id.","example":"clxac0001acct"},"username":{"type":"string","description":"Public @handle (without @).","example":"valeria"},"displayName":{"type":["string","null"],"description":"Display name.","example":"Valeria"},"email":{"type":["string","null"],"description":"Sign-in email.","format":"email"},"accountType":{"type":"string","description":"What the account was created as.","enum":["creator","agency"]},"status":{"type":"string","description":"`pending_kyc` until the ID check is approved, then `active` (can sell and get paid).","enum":["pending_kyc","active"]},"sellerStatus":{"type":"string","description":"Internal seller state, for support (PENDING_KYC, KYC_IN_REVIEW, KYC_REJECTED, VERIFIED_CREATOR, VERIFIED_AGENCY)."},"kycStatus":{"type":"string","description":"ID-check state. `session_created` = link opened, not finished; `processing` = approved, compliance documents still being generated.","enum":["not_started","session_created","in_review","processing","approved","rejected"]},"profileUrl":{"type":"string","description":"Public profile URL.","format":"uri"},"createdAt":{"type":"string","description":"When the account was created.","format":"date-time"}},"required":["accountId","username","accountType","status","sellerStatus","kycStatus","profileUrl","createdAt"]},"CrmApp":{"type":"object","properties":{"id":{"type":"string","description":"Your app’s id.","example":"clxap0001app"},"name":{"type":"string","description":"App name, as creators see it.","example":"Acme CRM"},"logoUrl":{"type":["string","null"],"description":"App logo, or null.","format":"uri"},"status":{"type":"string","description":"Always `approved` here: a suspended app’s keys get 403 `app_suspended` on every endpoint.","enum":["approved"]},"commission":{"type":"object","properties":{"rate":{"type":"number","description":"Share of each sale (excl. tax) booked for your app owner, as a fraction: 0.05 = 5%.","example":0.05},"types":{"type":"array","items":{"type":"string","description":"Sale type.","enum":["drop","tip","subscription"]},"description":"Sale types that earn commission."}},"required":["rate","types"],"description":"Your commission terms."},"apiCategories":{"type":"array","items":{"$ref":"#/components/schemas/ApiCategoryState"},"description":"Your app’s API category switches: which parts of the API your keys may call (see /developers/concepts/api-categories). Added 2026-11-01."}},"required":["id","name","status","commission","apiCategories"]},"CrmStatsBucket":{"type":"object","properties":{"bucket":{"type":"string","description":"Bucket key in `tz` local time: `YYYY-MM-DDTHH` (hour), `YYYY-MM-DD` (day; for week the Monday), `YYYY-MM` (month). On a day the clocks go back, the repeated hour is one bucket.","example":"2026-10-28"},"start":{"type":"string","description":"The UTC instant the bucket begins, clamped to the start of the range (a week or month bucket can begin before startDate).","format":"date-time"},"revenueCents":{"type":"integer","description":"Sales through your app’s links in the bucket, US cents, excl. tax, before our platform fee. Refunded and charged-back sales are left out.","example":4500},"earningsCents":{"type":"integer","description":"Commission booked for your app owner on those sales, US cents. Booked, not necessarily paid out yet.","example":225},"transactions":{"type":"integer","description":"Number of those sales.","example":3},"newConnectedAccounts":{"type":"integer","description":"Accounts your app issued links for the first time in the bucket.","example":1}},"required":["bucket","start","revenueCents","earningsCents","transactions","newConnectedAccounts"]},"CrmStats":{"type":"object","properties":{"startDate":{"type":"string","description":"As requested.","format":"date","example":"2026-10-01"},"endDate":{"type":"string","description":"As requested.","format":"date","example":"2026-10-30"},"tz":{"type":"string","description":"The zone days and buckets are cut in.","format":"iana-timezone","example":"Europe/Stockholm"},"granularity":{"type":"string","description":"Bucket size used (the one you asked for, or the automatic pick).","enum":["hour","day","week","month"]},"currency":{"type":"string","description":"Currency of every *Cents field.","enum":["USD"]},"totals":{"type":"object","properties":{"revenueCents":{"type":"integer","description":"US cents, excl. tax, before our platform fee; reversals left out.","example":128000},"earningsCents":{"type":"integer","description":"Commission booked for your app owner, US cents.","example":6400},"transactions":{"type":"integer","description":"Sales in the range.","example":42},"newConnectedAccounts":{"type":"integer","description":"Accounts first connected in the range.","example":5},"connectedAccountsNow":{"type":"integer","description":"Accounts connected to your app right now (your app generated their links most recently). Not range-bound.","example":18}},"required":["revenueCents","earningsCents","transactions","newConnectedAccounts","connectedAccountsNow"],"description":"The whole range. Counts equal the sum of `series`; cent amounts are rounded once over the range, so they can differ from the summed buckets by a cent."},"series":{"type":"array","items":{"$ref":"#/components/schemas/CrmStatsBucket"},"description":"Every bucket of the range, oldest first, zero-filled."}},"required":["startDate","endDate","tz","granularity","currency","totals","series"]},"CrmTransaction":{"type":"object","properties":{"id":{"type":"string","description":"Our id of the sale (order, tip or subscription payment).","example":"clxor0001ord"},"type":{"type":"string","description":"What was sold. `subscription` is one payment (the first or a renewal).","enum":["drop","tip","subscription"]},"paidAt":{"type":"string","description":"When it was paid (UTC).","format":"date-time"},"transactionId":{"type":"string","description":"The payment processor’s transaction id when known, else our id."},"linkId":{"type":["string","null"],"description":"The link id (POST /api/external/v1/links) the drop or tip was bought through; null for subscription payments and older template links."},"amountCents":{"type":"integer","description":"Sale amount, US cents, excl. tax, before our platform fee.","example":1500},"crmEarnedCents":{"type":"integer","description":"Commission booked for your app owner on this sale, US cents. 0 when the commission was reversed (refund or chargeback).","example":75},"status":{"type":"string","description":"Current state of the sale.","enum":["paid","refunded","charged_back"]},"creator":{"type":"object","properties":{"id":{"type":"string","description":"Account id."},"username":{"type":["string","null"],"description":"@handle without the @."},"name":{"type":["string","null"],"description":"Display name."}},"required":["id"],"description":"The account that made the sale."}},"required":["id","type","paidAt","transactionId","amountCents","crmEarnedCents","status","creator"]},"CrmConnectedAccount":{"type":"object","properties":{"id":{"type":"string","description":"Account id.","example":"clxac0001acct"},"username":{"type":["string","null"],"description":"@handle without the @.","example":"valeria"},"name":{"type":["string","null"],"description":"Display name."},"kind":{"type":"string","description":"`account`: a creator on its own. `agency`: an agency, the sum of its `children`. `creator`: a creator whose links an agency asked for. `own`: an agency’s own sales as a creator.","enum":["account","agency","creator","own"]},"connected":{"type":"boolean","description":"True when your app generated the account’s links most recently (an agency: any of its rows)."},"connectedAt":{"type":["string","null"],"description":"When your app first issued links for it.","format":"date-time"},"movedAway":{"type":["object","null"],"properties":{"at":{"type":"string","description":"When the other CRM last generated its links.","format":"date-time"}},"required":["at"],"description":"Set when another CRM generated the account’s links after you did. Which CRM is never disclosed."},"links":{"type":"integer","description":"Link ids your app created for it.","example":4},"allTimeGrossCents":{"type":"integer","description":"Everything the account ever sold, through any CRM or none, US cents, excl. tax, reversals left out.","example":250000},"viaLinksCents":{"type":"integer","description":"Its sales through your app’s links, all-time, US cents, excl. tax, reversals left out.","example":64000},"crmEarnedCents":{"type":"integer","description":"Commission booked for your app owner on those sales, US cents.","example":3200},"agencyId":{"type":["string","null"],"description":"Only with `flat=true`: the agency the row belongs to, or null."},"children":{"type":"array","items":{"$ref":"#/components/schemas/CrmConnectedAccount"},"description":"Only on `agency` rows without `flat=true`: its creators and its `own` row."}},"required":["id","kind","connected","links","allTimeGrossCents","viaLinksCents","crmEarnedCents"]},"CrmAccountsTotals":{"type":"object","properties":{"links":{"type":"integer","description":"Link ids your app created, all accounts."},"allTimeGrossCents":{"type":"integer","description":"Sum of allTimeGrossCents, US cents."},"viaLinksCents":{"type":"integer","description":"Sum of viaLinksCents, US cents: everything ever sold through your app’s links."},"crmEarnedCents":{"type":"integer","description":"Sum of crmEarnedCents, US cents."}},"required":["links","allTimeGrossCents","viaLinksCents","crmEarnedCents"]},"WebhookConfig":{"type":"object","properties":{"url":{"type":["string","null"],"description":"Your https endpoint, or null when none is set.","format":"uri"},"events":{"type":"array","items":{"type":"string","description":"Event type."},"description":"Events delivered to the endpoint."},"hasSecret":{"type":"boolean","description":"Whether a signing secret exists."},"availableEvents":{"type":"array","items":{"type":"string","description":"Event type."},"description":"Every event you can subscribe to."},"recentDeliveries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Event id (also the DropFans-Event-Id header)."},"event":{"type":"string","description":"Event type."},"status":{"type":"string","description":"PENDING = retrying.","enum":["PENDING","DELIVERED","FAILED"]},"attempts":{"type":"integer","description":"Attempts so far."},"lastStatusCode":{"type":["integer","null"],"description":"Your endpoint’s last HTTP status."},"lastError":{"type":["string","null"],"description":"Last failure reason."},"createdAt":{"type":"string","description":"When the event was created.","format":"date-time"},"deliveredAt":{"type":["string","null"],"description":"When your endpoint accepted it.","format":"date-time"},"nextAttemptAt":{"type":["string","null"],"description":"Next retry, while PENDING.","format":"date-time"}},"description":"One delivery."},"description":"The last 20 deliveries, newest first."}},"required":["events","hasSecret","availableEvents","recentDeliveries"]},"PostMedia":{"type":"object","properties":{"id":{"type":"string","description":"Post-media row id."},"vaultItemId":{"type":"string","description":"The source vault item."},"isPaid":{"type":"boolean","description":"True for PPV items shown blurred until unlocked."},"order":{"type":"integer","description":"Display position (0-based)."},"type":{"type":"string","description":"Media kind (image/video)."}},"required":["id","vaultItemId","isPaid","order","type"]},"Post":{"type":"object","properties":{"id":{"type":"string","description":"Post id.","example":"clxp0st000001feed"},"kind":{"type":"string","description":"Post shape. DROP is derived from productId at creation — it is not an accepted request value.","enum":["TEXT","DROP","SUBSCRIPTION","COMMUNITY","MEDIA"]},"caption":{"type":["string","null"],"description":"Post text. Null for caption-less media posts."},"status":{"type":"string","description":"Moderation state. PENDING is normal for media posts and is not an error — poll until it becomes APPROVED.","enum":["PENDING","APPROVED","REJECTED","FLAGGED"]},"live":{"type":"boolean","description":"True only when the post is APPROVED and its publish time has passed."},"scheduledAt":{"type":["string","null"],"description":"When the post is scheduled to go live, or null for immediate posts.","format":"date-time"},"publishedAt":{"type":"string","description":"Effective publish time.","format":"date-time"},"createdAt":{"type":"string","description":"Creation time.","format":"date-time"},"productId":{"type":["string","null"],"description":"The attached drop, for kind=DROP. Null otherwise."},"likes":{"type":"integer","description":"Like count.","example":14},"comments":{"type":"integer","description":"Comment count.","example":3},"media":{"type":"array","items":{"$ref":"#/components/schemas/PostMedia"},"description":"Media entries in display order. Empty for TEXT posts."}},"required":["id","kind","status","live","publishedAt","createdAt","likes","comments","media"]},"PostLimits":{"type":"object","properties":{"postsPerDay":{"type":"integer","description":"Posts per creator per rolling 24 hours (currently 5).","example":5},"maxCaptionChars":{"type":"integer","description":"Caption length cap (currently 2000).","example":2000},"maxMediaPerPost":{"type":"integer","description":"Media items per post (currently 10).","example":10},"maxScheduleDays":{"type":"integer","description":"How far ahead a post can be scheduled, in days (currently 30).","example":30},"minPaidPrice":{"type":"integer","description":"Minimum USD price of a paid media item (currently 5).","example":5}},"required":["postsPerDay","maxCaptionChars","maxMediaPerPost","maxScheduleDays","minPaidPrice"]},"Pagination":{"type":"object","properties":{"page":{"type":"integer","description":"Echoed page (1-based).","example":1},"limit":{"type":"integer","description":"Echoed page size.","example":20},"total":{"type":"integer","description":"Total rows matching the filter.","example":63},"hasMore":{"type":"boolean","description":"True when more pages exist."}},"required":["page","limit","total","hasMore"]},"PostListResponse":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/Post"},"description":"Your posts, newest first."},"pagination":{"$ref":"#/components/schemas/Pagination"},"limits":{"$ref":"#/components/schemas/PostLimits"}},"required":["posts","pagination","limits"]},"EarningsStats":{"type":"object","properties":{"totalEarningsCents":{"type":"integer","description":"**NET** seller earnings in cents for the window (after platform fee).","example":182050},"grossEarningsCents":{"type":"integer","description":"Seller gross in cents (buyer-paid minus tax, before the platform fee) — matches the dashboard’s Gross toggle.","example":214180},"previousPeriodEarningsCents":{"type":"integer","description":"NET cents for the same-length window immediately before startDate."},"previousPeriodGrossEarningsCents":{"type":"integer","description":"Gross cents for the previous window."},"transactionCount":{"type":"integer","description":"Paid transactions in the window (drops + tips + subscription payments).","example":41},"avgTransactionCents":{"type":"integer","description":"Average NET cents per transaction."},"uniqueCustomers":{"type":"integer","description":"Distinct buyer emails in the window.","example":28},"typeTotals":{"type":"object","properties":{"drop":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Gross cents."},"netCents":{"type":"integer","description":"Net cents."},"count":{"type":"integer","description":"Transaction count."}},"required":["grossCents","netCents","count"],"description":"Totals for drop revenue."},"tip":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Gross cents."},"netCents":{"type":"integer","description":"Net cents."},"count":{"type":"integer","description":"Transaction count."}},"required":["grossCents","netCents","count"],"description":"Totals for tip revenue."},"subscription":{"type":"object","properties":{"grossCents":{"type":"integer","description":"Gross cents."},"netCents":{"type":"integer","description":"Net cents."},"count":{"type":"integer","description":"Transaction count."}},"required":["grossCents","netCents","count"],"description":"Totals for subscription revenue."}},"required":["drop","tip","subscription"],"description":"Per-type window totals (additive field, 2026-07-22)."}},"required":["totalEarningsCents","grossEarningsCents","previousPeriodEarningsCents","previousPeriodGrossEarningsCents","transactionCount","avgTransactionCents","uniqueCustomers","typeTotals"]},"EarningsChart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string","description":"Human-readable bucket label."},"description":"Chart x-axis labels, aligned with `values` and `dates`."},"values":{"type":"array","items":{"type":"integer","description":"GROSS cents for the bucket."},"description":"**GROSS** cents per bucket (gross so per-day merges against your own gross ledgers compare like for like)."},"dates":{"type":"array","items":{"type":"string","description":"YYYY-MM-DD bucket key."},"description":"Bucket keys in the caller’s tz. Weekly buckets use the week-start date, monthly the 1st."},"groupBy":{"type":"string","description":"Bucket size: day when the span is ≤31 days, week ≤90, else month.","enum":["day","week","month"]},"typedValues":{"type":"object","properties":{"drop":{"type":"array","items":{"type":"integer","description":"Gross cents."},"description":"Gross cents per bucket from drops."},"tip":{"type":"array","items":{"type":"integer","description":"Gross cents."},"description":"Gross cents per bucket from tips."},"subscription":{"type":"array","items":{"type":"integer","description":"Gross cents."},"description":"Gross cents per bucket from subscriptions."}},"required":["drop","tip","subscription"],"description":"Per-type GROSS cent series aligned 1:1 with `dates` (additive field, 2026-07-22)."}},"required":["labels","values","dates","groupBy","typedValues"]},"EarningsTransaction":{"type":"object","properties":{"id":{"type":"string","description":"The order / tip / renewal id (source-specific — matches nothing on the buyer’s side)."},"productId":{"type":"string","description":"The sold product’s id — **drop transactions only**; absent on tips and subscriptions. Join it back to your own drop records."},"productName":{"type":"string","description":"Product name, or the literal \"Tip\" / \"Subscription\".","example":"Beach set — 6 photos"},"amountCents":{"type":"integer","description":"NET seller earnings in cents.","example":2000},"grossAmountCents":{"type":"integer","description":"Gross cents (buyer-paid minus tax).","example":2500},"buyerEmail":{"type":["string","null"],"description":"Buyer email when known.","format":"email"},"buyerName":{"type":["string","null"],"description":"Buyer display name — tips and subscriptions only; always null on drops."},"paidAt":{"type":"string","description":"When it was paid.","format":"date-time"},"type":{"type":"string","description":"Revenue source.","enum":["drop","tip","subscription"]}},"required":["id","productName","amountCents","grossAmountCents","paidAt","type"]},"EarningsResponse":{"type":"object","properties":{"stats":{"$ref":"#/components/schemas/EarningsStats"},"chart":{"$ref":"#/components/schemas/EarningsChart"},"transactions":{"type":"array","items":{"$ref":"#/components/schemas/EarningsTransaction"},"description":"The newest 50 transactions across all three sources — a fixed cap, not a page. For the complete ledger use GET /api/external/v1/earnings/transactions."}},"required":["stats","chart","transactions"]},"LedgerTransaction":{"type":"object","properties":{"id":{"type":"string","description":"The order / tip / renewal id. Unique per transaction — dedupe on it.","example":"clx0rd3r000001sale"},"type":{"type":"string","description":"Revenue source.","enum":["drop","tip","subscription"],"example":"drop"},"productId":{"type":["string","null"],"description":"The sold drop — drops only, null on tips and subscriptions.","example":"clxdr0p000001prod"},"productName":{"type":"string","description":"Drop name, or the literal \"Tip\" / \"Subscription\".","example":"Beach set — 6 photos"},"externalRef":{"type":["string","null"],"description":"Your per-fan reference from the checkout or tip link, when there was one."},"linkId":{"type":["string","null"],"description":"The link id (POST /api/external/v1/links) the sale came through; null for template links and subscriptions.","example":"q7m2c8zk4w"},"amountCents":{"type":"integer","description":"NET seller earnings in cents — the same number /earnings calls amountCents.","example":2000},"netAmountCents":{"type":"integer","description":"Same as amountCents: what the creator keeps (after the platform fee and VAT; before any agency split).","example":2000},"grossAmountCents":{"type":"integer","description":"Seller gross in cents (buyer-paid minus VAT, before the fee).","example":2500},"platformFeeCents":{"type":"integer","description":"Platform fee in cents.","example":500},"taxCents":{"type":"integer","description":"VAT in cents.","example":250},"totalChargedCents":{"type":"integer","description":"What the buyer paid in cents (VAT included).","example":2750},"currency":{"type":"string","description":"Always USD.","enum":["USD"],"example":"USD"},"buyerEmail":{"type":["string","null"],"description":"Buyer email when known.","format":"email"},"buyerName":{"type":["string","null"],"description":"Buyer display name — tips and subscriptions only."},"paidAt":{"type":"string","description":"When it was paid (UTC).","format":"date-time"},"status":{"type":"string","description":"Always \"paid\" unless includeReversed=true.","enum":["paid","refunded","charged_back"],"example":"paid"}},"required":["id","type","productName","amountCents","netAmountCents","grossAmountCents","platformFeeCents","taxCents","totalChargedCents","currency","paidAt","status"]},"Link":{"type":"object","properties":{"id":{"type":"string","description":"The link id (10 of `a-z 0-9`). Comes back as `linkId` on sales through the link.","example":"q7m2c8zk4w"},"type":{"type":"string","description":"What the link opens.","enum":["buy","tip","subscribe","profile"],"example":"buy"},"url":{"type":"string","description":"The web link — `/buy/{id}`, no parameters.","format":"uri","example":"https://www.dropfans.io/buy/q7m2c8zk4w"},"telegram":{"type":["string","null"],"description":"The Telegram Mini App link (`startapp={id}`). Null when the shared Dropfans bot is not configured.","format":"uri","example":"https://t.me/DropfansBot/app?startapp=q7m2c8zk4w"},"productId":{"type":["string","null"],"description":"The drop of a `buy` link.","example":"cmv5tmpcm0015h4oucxkgc4ma"},"amountUsd":{"type":["number","null"],"description":"Fixed amount of a `tip` link; null = the fan picks.","example":null},"externalRef":{"type":["string","null"],"description":"Your per-fan reference, returned on the sale.","example":"tg_48213377"},"createdAt":{"type":"string","description":"When the link was created.","format":"date-time","example":"2026-10-29T12:00:00.000Z"}},"required":["id","type","url","createdAt"]},"Links":{"type":"object","properties":{"username":{"type":"string","description":"The creator’s @handle the links are built for.","example":"valeria"},"links":{"type":"object","properties":{"profile":{"$ref":"#/components/schemas/Link"},"tip":{"$ref":"#/components/schemas/Link"},"subscribe":{"$ref":"#/components/schemas/Link"}},"required":["profile","tip","subscribe"],"description":"Link ids for the account — the same ids on every call. Create buy links and fixed-amount tip links with POST /api/external/v1/links."},"web":{"type":"object","properties":{"profile":{"type":"string","description":"The creator’s public profile.","format":"uri","example":"https://www.dropfans.io/u/valeria"},"tip":{"type":"string","description":"Opens the profile with the tip sheet open.","format":"uri","example":"https://www.dropfans.io/u/valeria?tip=1"},"tipTemplate":{"type":"string","description":"Tip link with the amount prefilled — replace `{usd}` with whole US dollars. Amounts outside the allowed range open the sheet unfilled.","example":"https://www.dropfans.io/u/valeria?tip={usd}"},"tipWithRefTemplate":{"type":"string","description":"Tip link with a per-fan reference — replace `{usd}` (use `1` to let the fan pick the amount) and `{externalRef}` (1–32 of `A-Z a-z 0-9 _ -`). It comes back on the tip (tip.paid webhook, GET /api/external/v1/tips).","example":"https://www.dropfans.io/u/valeria?tip={usd}&m={externalRef}"},"subscribe":{"type":"string","description":"Opens the profile with the subscribe sheet already on screen.","format":"uri","example":"https://www.dropfans.io/u/valeria?subscribe=1"},"buyTemplate":{"type":"string","description":"Checkout link for any drop — replace `{productId}` with the id from create-drop.","example":"https://www.dropfans.io/buy/{productId}"},"buyWithRefTemplate":{"type":"string","description":"The same with a per-fan reference — replace `{externalRef}` (1–32 of `A-Z a-z 0-9 _ -`). It comes back on the order (drop.paid webhook, GET /api/external/v1/orders).","example":"https://www.dropfans.io/buy/{productId}?m={externalRef}"}},"required":["profile","tip","tipTemplate","tipWithRefTemplate","subscribe","buyTemplate","buyWithRefTemplate"],"description":"Deprecated, still served: web links built from templates with literal placeholders. Prefer `links` / POST /api/external/v1/links."},"telegram":{"type":["object","null"],"properties":{"bot":{"type":"string","description":"The shared bot username, without @.","example":"DropfansBot"},"profile":{"type":"string","description":"Opens the creator’s Mini App profile.","format":"uri","example":"https://t.me/DropfansBot/app?startapp=p_valeria"},"tip":{"type":"string","description":"Opens the Mini App tip sheet.","format":"uri","example":"https://t.me/DropfansBot/app?startapp=t_valeria"},"tipTemplate":{"type":"string","description":"Tip prefilled — replace `{cents}` with the amount in **cents** (the web template takes dollars; this one takes cents).","example":"https://t.me/DropfansBot/app?startapp=pt_{cents}_valeria"},"tipWithRefTemplate":{"type":"string","description":"Mini App tip with a per-fan reference — replace `{cents}` (`0` lets the fan pick the amount) and `{externalRef}`. **Here the reference is 1–20 of `A-Z a-z 0-9 -` (no underscore)**: it sits in front of the username, which may contain underscores, and Telegram caps the start parameter at 64 characters.","example":"https://t.me/DropfansBot/app?startapp=tm_{cents}_{externalRef}_valeria"},"subscribe":{"type":"string","description":"Opens the Mini App subscribe flow.","format":"uri","example":"https://t.me/DropfansBot/app?startapp=s_valeria"},"buyTemplate":{"type":"string","description":"Mini App checkout for any drop — replace `{productId}`.","example":"https://t.me/DropfansBot/app?startapp=b_{productId}"},"buyWithRefTemplate":{"type":"string","description":"Mini App checkout with a per-fan reference — replace `{productId}` and `{externalRef}` (1–32 of `A-Z a-z 0-9 _ -`).","example":"https://t.me/DropfansBot/app?startapp=b_{productId}_{externalRef}"}},"required":["bot","profile","tip","tipTemplate","tipWithRefTemplate","subscribe","buyTemplate","buyWithRefTemplate"],"description":"Deprecated, still served: Telegram Mini App deep links built from templates. **Null when the shared Dropfans bot is not configured.** Prefer `links` / POST /api/external/v1/links."}},"required":["username","links","web"]},"NotificationsStatus":{"type":"object","properties":{"telegramHandle":{"type":["string","null"],"description":"The creator’s saved Telegram @handle (without @), or null."},"personalConnected":{"type":"boolean","description":"True when a personal chat id is registered — sale notifications DM the creator."},"groupConnected":{"type":"boolean","description":"True when a group/channel is registered for notifications."},"groupChatId":{"type":["string","null"],"description":"The registered group chat id (e.g. \"-100…\"), or null."},"groupName":{"type":["string","null"],"description":"The registered group’s title, or null."}},"required":["personalConnected","groupConnected"]},"Success":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true.","example":true}},"required":["success"]},"Ok":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true. (This endpoint family returns {ok} where the vault family returns {success} — historical, kept for compatibility.)","example":true}},"required":["ok"]},"Error":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable message describing what went wrong.","example":"Vault item not found"}},"required":["error"]},"ErrorWithCode":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable message.","example":"Rate limit exceeded"},"code":{"type":"string","description":"Machine-readable code: unauthorized, app_suspended, first_party_only, api_category_disabled, rate_limited, username_required, invalid_account_header, account_not_managed, permission_denied, account_header_not_allowed, agency_key_required — plus endpoint-specific codes listed on each reference page.","example":"rate_limited"}},"required":["error","code"]},"ErrorWithMatchedWord":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable message.","example":"Your post contains a word that isn’t allowed."},"matchedWord":{"type":"string","description":"The prohibited word that tripped the filter — rewrite and retry."}},"required":["error","matchedWord"]},"ErrorWithField":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable message naming the offending field and word.","example":"Field \"name\" contains a prohibited word: \"…\""},"field":{"type":"string","description":"Which request field tripped the filter (\"name\" or \"description\")."},"matchedWord":{"type":"string","description":"The prohibited word."}},"required":["error","field","matchedWord"]},"BalanceBuckets":{"type":"object","properties":{"pending":{"type":"number","description":"USD **dollars**. Still inside the chargeback hold window.","example":120.5},"available":{"type":"number","description":"USD dollars. Payable. Can be negative.","example":342.1},"processing":{"type":"number","description":"USD dollars. Inside a payout being sent.","example":0},"paidOut":{"type":"number","description":"USD dollars. Lifetime paid out.","example":1875}},"required":["pending","available","processing","paidOut"]},"PayoutBuckets":{"type":"object","properties":{"pendingCents":{"type":"integer","description":"Integer **cents**. Money still inside the chargeback hold window; not payable yet.","example":12050},"availableCents":{"type":"integer","description":"Integer cents. Money that cleared the hold and is not in a payout yet. Can be negative (a refund of money already paid out is netted against future earnings).","example":34210},"processingCents":{"type":"integer","description":"Integer cents. Money inside a payout that is being sent.","example":0},"paidOutCents":{"type":"integer","description":"Integer cents. Lifetime money already paid out.","example":187500}},"required":["pendingCents","availableCents","processingCents","paidOutCents"]},"Payout":{"type":"object","properties":{"id":{"type":"string","description":"Id of the row. Unique across the three kinds — use it with GET /api/external/v1/payouts/{id}.","example":"clxpo0001payout"},"kind":{"type":"string","description":"`payout`: sent by Dropfans (Paxum, MassPay wallet load, or settled by an admin). `manual`: paid outside the platform and recorded by an admin. `request`: a payout request the account made that has not been fulfilled into a payout yet.","enum":["payout","manual","request"]},"status":{"type":"string","description":"Requests: `requested` → `approved` → (`processing` for Paxum, from the moment they are made) → `paid`, or `rejected` / `cancelled`. Payouts: `pending` (in a batch, not sent yet) → `processing` (sent) → `paid` or `failed`; `cancelled` when an attempt was dropped. Manual payouts are always `paid`.","enum":["requested","approved","pending","processing","paid","failed","cancelled","rejected"]},"amountCents":{"type":"integer","description":"Integer **cents**. What is paid out (negative only on a reversal row).","example":34210},"currency":{"type":"string","description":"Always \"USD\".","enum":["USD"]},"side":{"type":"string","description":"Which balance it draws from: `creator` (own sales), `agency` (income from managed creators / AI personas), `affiliate` (referral commission), `share` (partner shares of other accounts’ sales), or `combined` (several sides in one transfer — see `sides`).","example":"creator"},"sides":{"type":"object","properties":{"creatorCents":{"type":"integer","description":"Creator side, cents.","example":34210},"agencyCents":{"type":"integer","description":"Agency side, cents.","example":0},"affiliateCents":{"type":"integer","description":"Referral commission, cents.","example":0},"shareCents":{"type":"integer","description":"Partner shares, cents.","example":0}},"required":["creatorCents","agencyCents","affiliateCents","shareCents"],"description":"The amount split by side, integer cents. Adds up to `amountCents`."},"method":{"type":["object","null"],"properties":{"type":{"type":"string","description":"Provider method type.","enum":["PAXUM_P2P","MASSPAY","BANK_SWIFT"]},"label":{"type":"string","description":"Display label — the creator’s nickname, or e.g. \"Paxum · j***@example.com\", \"Payout wallet · SWE\", \"Bank transfer · ••••1234\". Never a full e-mail, IBAN or token.","example":"Paxum · j***@example.com"}},"required":["type","label"],"description":"The destination frozen when the payout or request was made, masked. Null for manual payouts."},"note":{"type":["string","null"],"description":"Requests: the note sent with the request. Manual payouts: the note the admin recorded for the payee. Otherwise null."},"failureMessage":{"type":["string","null"],"description":"Why a `failed` payout failed, as reported by the provider. Null unless `status` is `failed`."},"invoiceNumber":{"type":["integer","null"],"description":"Payout invoice number once the invoice exists. The invoice itself is in the dashboard.","example":1042},"requestId":{"type":["string","null"],"description":"kind `payout` / `manual`: the request this payout fulfilled, if any."},"payoutId":{"type":["string","null"],"description":"kind `request`: the payout or manual payout that fulfilled it, if any."},"createdAt":{"type":"string","description":"When the payout was created or the request made. The list is ordered by this.","format":"date-time"},"initiatedAt":{"type":["string","null"],"description":"When the payout was sent to the provider.","format":"date-time"},"paidAt":{"type":["string","null"],"description":"When it was paid. Null unless `status` is `paid` (requests carry it on the fulfilling payout instead).","format":"date-time"},"failedAt":{"type":["string","null"],"description":"When it failed. Null unless `status` is `failed`.","format":"date-time"},"reversedAt":{"type":["string","null"],"description":"Set on a paid wallet load that was sent back (spendback): the money is available again. Its negative twin has `reversalOfId`. Both are hidden from GET /payouts unless includeReversed=true.","format":"date-time"},"reversalOfId":{"type":["string","null"],"description":"Set on the negative row that reverses the payout with this id."}},"required":["id","kind","status","amountCents","currency","side","sides","createdAt"]},"PayoutMethodSummary":{"type":"object","properties":{"id":{"type":"string","description":"Payout method id.","example":"clxpm0001method"},"type":{"type":"string","description":"Provider method type.","enum":["PAXUM_P2P","MASSPAY","BANK_SWIFT"]},"isDefault":{"type":"boolean","description":"True for the method payouts go to."},"nickname":{"type":["string","null"],"description":"The creator’s own label for it."},"label":{"type":"string","description":"Display label, masked (see Payout.method.label).","example":"Paxum · j***@example.com"},"holderType":{"type":["string","null"],"description":"Whether it was set up for the person or the company.","enum":["INDIVIDUAL","BUSINESS"]},"createdAt":{"type":"string","description":"When the method was added.","format":"date-time"},"paxum":{"type":["object","null"],"properties":{"email":{"type":["string","null"],"description":"Masked Paxum e-mail, e.g. \"j***@example.com\".","example":"j***@example.com"},"lookupStatus":{"type":["string","null"],"description":"Whether the e-mail is a live Paxum account: active, inactive, not_found, unconfigured.","example":"active"},"verificationStatus":{"type":["string","null"],"description":"Paxum identity match against the ID check: PENDING, COMPLETED, MISMATCH, UNAVAILABLE."}},"description":"PAXUM_P2P only."},"masspay":{"type":["object","null"],"properties":{"country":{"type":["string","null"],"description":"ISO 3166-1 alpha-3 country.","example":"SWE"},"currency":{"type":["string","null"],"description":"Payout currency (ISO 4217), when chosen."},"payerName":{"type":["string","null"],"description":"Payout option name, when chosen."},"activated":{"type":"boolean","description":"True once the payee finished the wallet activation. Payout requests to a wallet need it."}},"required":["activated"],"description":"MASSPAY (payout wallet) only."},"bank":{"type":["object","null"],"properties":{"last4":{"type":["string","null"],"description":"Last 4 characters of the account number. The full IBAN / SWIFT is never returned.","example":"1234"},"country":{"type":["string","null"],"description":"Bank country (ISO alpha-2)."},"bankName":{"type":["string","null"],"description":"Bank name."}},"description":"BANK_SWIFT only."}},"required":["id","type","isDefault","label","createdAt"]},"PayoutSummary":{"type":"object","properties":{"accountId":{"type":"string","description":"The account this describes.","example":"clx2f8a1b0001qw3k"},"currency":{"type":"string","description":"Always \"USD\".","enum":["USD"]},"pendingCents":{"type":"integer","description":"Integer **cents**. Money the account owns (all sides) still inside the chargeback hold window; not payable yet.","example":12050},"availableCents":{"type":"integer","description":"Integer cents. Money the account owns (all sides) that cleared the hold and is not in a payout yet. Can be negative (a refund of money already paid out is netted against future earnings).","example":34210},"processingCents":{"type":"integer","description":"Integer cents. Money the account owns (all sides) inside a payout that is being sent.","example":0},"paidOutCents":{"type":"integer","description":"Integer cents. Lifetime money the account owns (all sides) already paid out.","example":187500},"sides":{"type":"object","properties":{"creator":{"$ref":"#/components/schemas/PayoutBuckets"},"agency":{"$ref":"#/components/schemas/PayoutBuckets"},"affiliate":{"$ref":"#/components/schemas/PayoutBuckets"},"share":{"$ref":"#/components/schemas/PayoutBuckets"}},"required":["creator","agency","affiliate","share"],"description":"The same four buckets per side, integer cents."},"requestableCents":{"type":"integer","description":"Integer cents a payout request would ask for right now: the available balance of every side that has money and no open request.","example":34210},"minimumPayoutCents":{"type":"integer","description":"Integer cents. The available balance must reach this before a payout can be requested. 0 = no minimum.","example":2000},"payoutsEnabled":{"type":"boolean","description":"False when Dropfans has paused payouts for the account."},"kycVerified":{"type":"boolean","description":"True once the account passed the ID check."},"defaultMethod":{"anyOf":[{"$ref":"#/components/schemas/PayoutMethodSummary"},{"type":"null"}],"description":"Where payouts go, masked. Null when no method is set up (the creator adds one in the dashboard)."},"openRequest":{"anyOf":[{"$ref":"#/components/schemas/Payout"},{"type":"null"}],"description":"The newest open payout request (requested, approved or processing), or null."},"inFlight":{"type":"boolean","description":"True while a payout is pending or processing."},"upcoming":{"type":"array","items":{"type":"object","properties":{"availableOn":{"type":"string","description":"YYYY-MM-DD (UTC).","format":"date","example":"2026-11-04"},"amountCents":{"type":"integer","description":"Integer cents released that day.","example":4500}},"required":["availableOn","amountCents"],"description":"One day."},"description":"Creator-side earnings and partner shares still on hold, by the UTC day they become available. Soonest first."},"eligible":{"type":"boolean","description":"True when POST /api/external/v1/payouts/requests would be accepted now."},"ineligibleReasons":{"type":"array","items":{"type":"string","description":"A reason code — the same `code` POST /payouts/requests answers with.","enum":["kyc_required","payouts_disabled","consumer_account","no_method","masspay_not_activated","below_minimum","request_open","in_flight"]},"description":"Every reason it would be refused, in the order the request checks them. Empty when eligible."}},"required":["accountId","currency","pendingCents","availableCents","processingCents","paidOutCents","sides","requestableCents","minimumPayoutCents","payoutsEnabled","kycVerified","inFlight","upcoming","eligible","ineligibleReasons"]},"MasspayProfile":{"type":"object","properties":{"accountType":{"type":"string","description":"BUSINESS when MassPay holds a legal business name for the payee.","enum":["INDIVIDUAL","BUSINESS"]},"businessName":{"type":"string","description":"Legal business name. Empty string when not set. Business accounts only.","example":"Jane Doe Media AB"},"firstName":{"type":"string","description":"First name. Empty string when not set. Required for a payout.","example":"Jane"},"middleName":{"type":"string","description":"Middle name. Empty string when not set. Optional."},"lastName":{"type":"string","description":"Last name. Empty string when not set. Required for a payout.","example":"Doe"},"email":{"type":"string","description":"Email. Empty string when not set. Required for a payout.","example":"jane@example.com"},"mobileNumber":{"type":"string","description":"Mobile number. Empty string when not set. Optional.","example":"+46 70 123 45 67"},"language":{"type":"string","description":"Language. Empty string when not set. Optional.","example":"en"},"dateOfBirth":{"type":"string","description":"Date of birth. Empty string when not set. Optional.","example":"1994-05-17"},"country":{"type":"string","description":"Country. Empty string when not set. Required for a payout.","example":"SWE"},"address1":{"type":"string","description":"Address line 1. Empty string when not set. Required for a payout.","example":"Storgatan 1"},"address2":{"type":"string","description":"Address line 2. Empty string when not set. Optional."},"city":{"type":"string","description":"City. Empty string when not set. Required for a payout.","example":"Stockholm"},"stateProvince":{"type":"string","description":"State / province. Empty string when not set. Required for a payout.","example":"Stockholm County"},"postalCode":{"type":"string","description":"Postal code. Empty string when not set. Required for a payout.","example":"111 22"}},"required":["accountType","businessName","firstName","middleName","lastName","email","mobileNumber","language","dateOfBirth","country","address1","address2","city","stateProvince","postalCode"]},"PayoutRequest":{"type":"object","properties":{"requests":{"type":"array","items":{"$ref":"#/components/schemas/Payout"},"description":"One payout request per side that had money and no open request (kind `request`)."}},"required":["requests"]}}}}