Create a creator account (sign-up from your page)
Creates a creator (or agency) account from your own sign-up page and returns the ID-check link to redirect the creator to.
/api/external/accountsNewCreates a creator (or agency) account from your own sign-up page and returns the ID-check link to redirect the creator to.
The 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, and selling is unlocked only once the account is active.
The 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.
Referral commission. Accounts you create are attributed to your app owner’s account, which earns the standard referral commission on their sales.
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.
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 has to be enabled for your app; ask us to enable it.
Authentication
Send the creator's API key as a bearer token: Authorization: Bearer dpfn_…. See Authentication & API keys.
Request body
Content type: application/json
| Name | Type | Required | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
email | string | Required | The creator’s email. It becomes their sign-in. 409 if it is already registered. Format: email | |||||||||
password | string | Optional | Optional. Leave it out and we email the creator a link to set one (valid 7 days). Either way they get a welcome email. Min length: 8 Max length: 200 | |||||||||
username | string | Required | Public @handle (letters, digits, underscores). 409 when taken. | |||||||||
displayName | string | Optional | Display name on the profile. Max length: 50 | |||||||||
bio | string | Optional | Profile bio. Max length: 500 | |||||||||
location | string | Optional | Optional profile location line. Max length: 100 | |||||||||
accountType | string | Optional | agency is for AI-creator operators that run several personas.One of: creator, agencyDefault: "creator" | |||||||||
residencyCountry | string | Required | Country of residence, ISO 3166-1 alpha-2. Used for payouts and tax. Pattern: ^[A-Z]{2}$ | |||||||||
avatarUrl | string | Optional | 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 | string | Optional | https URL of the profile banner. Same rules as avatarUrl. Format: uri | |||||||||
subscription | object | Optional | Optional subscription offer for the profile.Show child attributes
| |||||||||
legalAccepted | boolean | Required | Must be true: the creator accepted the Terms of Service, Privacy Policy and 2257 statement on your page. | |||||||||
acceptedFromIp | string | Required | The creator’s browser IP at acceptance. | |||||||||
acceptedUserAgent | string | Required | The creator’s browser user agent at acceptance. Max length: 500 | |||||||||
kycReturnUrl | string | Optional | https URL the creator returns to after the ID check. We append ?kyc=<status>.Format: uri |
{
"email": "[email protected]",
"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
| Name | Type | Description | ||||||
|---|---|---|---|---|---|---|---|---|
accountId | string | The new account’s id. | ||||||
username | string | Public @handle (without @). | ||||||
displayName | string | null | Display name. | ||||||
email | string | null | Sign-in email. Format: email | ||||||
accountType | string | What the account was created as. One of: creator, agency | ||||||
status | string | pending_kyc until the ID check is approved, then active (can sell and get paid).One of: pending_kyc, active | ||||||
sellerStatus | string | Internal seller state, for support (PENDING_KYC, KYC_IN_REVIEW, KYC_REJECTED, VERIFIED_CREATOR, VERIFIED_AGENCY). | ||||||
kycStatus | string | ID-check state. session_created = link opened, not finished; processing = approved, compliance documents still being generated.One of: not_started, session_created, in_review, processing, approved, rejected | ||||||
profileUrl | string | Public profile URL. Format: uri | ||||||
createdAt | string | When the account was created. Format: date-time | ||||||
apiKey | string | A key for the new account, bound to your app. Shown once. | ||||||
kycUrl | string | null | The ID-check link. Null if it could not be opened right now; then call create-kyc-session. Format: uri | ||||||
kycExpiresAt | string | null | The link is reused until then; ask for a new one after. Format: date-time | ||||||
referralCredited | boolean | True when the account was attributed to your app owner for referral commission. | ||||||
images | object | What happened to avatarUrl / bannerUrl: "saved", "failed" or null (not sent).Show child attributes
|
{
"accountId": "clxac0001acct",
"username": "valeria",
"displayName": "Valeria",
"email": "[email protected]",
"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"
}
}Errors
| Status | Body | When |
|---|---|---|
| 400 | {"error":"residencyCountry must be an ISO 3166-1 alpha-2 code (e.g. \"SE\").","code":"invalid_input","field":"residencyCountry"} | A field failed validation. `field` names it. |
| 409 | {"error":"There is already a DropFans account with this email. Sign in instead.","code":"email_taken"} | The email is registered. |
| 409 | {"error":"That profile link is taken. Pick another.","code":"username_taken"} | The handle is taken. |
| 401 | {"error":"Unauthorized","code":"unauthorized"} | Missing or invalid API key. |
| 403 | {"error":"This endpoint needs a key bound to an approved app.","code":"app_key_required"} | A Personal key was used. |
| 403 | {"error":"Use the app owner's key for this endpoint.","code":"owner_key_required"} | 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. |
| 403 | {"error":"This app is not enabled for this endpoint. Contact support.","code":"capability_missing"} | Creator sign-up has not been enabled for your app yet. |
| 429 | {"error":"At most 20 sign-ups per hour.","code":"rate_limited"} | Too many sign-ups from your app this hour. `Retry-After` says when to retry. |
Rate limiting
Every response carries the X-RateLimit-Tier header and, on limited tiers, the per-minute and per-day trios — read X-RateLimit-Remaining and X-RateLimit-Reset instead of hardcoding limits. Details in Rate limits.
Code samples
curl -X POST "https://www.dropfans.io/api/external/accounts" \
-H "Authorization: Bearer $DROPFANS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"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"
}'const res = await fetch(`https://www.dropfans.io/api/external/accounts`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"email": "[email protected]",
"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"
}),
});
console.log(await res.json());import os
import requests
res = requests.post(
"https://www.dropfans.io/api/external/accounts",
headers={"Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}"},
json={
"email": "[email protected]",
"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",
},
)
print(res.json())Questions? [email protected]
