# Sign creators up from your own page

Approved apps can create creator accounts by API, send each creator through the ID check and start working with the returned key.

The creator never fills in our sign-up form. Creator sign-up is enabled per app, so ask us to switch it on for yours.

## 1. Collect their details

Your page collects the email, handle, display name, country of residence and subscription price. It also shows our Terms of Service, Privacy Policy and 2257 statement with an acceptance checkbox.

## 2. Create the account

Call this from your server with a key your app owner holds, and pass the creator’s browser IP and user agent from the moment they accepted.

curl:

```bash
curl -X POST "https://www.dropfans.io/api/external/v1/accounts" \
  -H "Authorization: Bearer $APP_OWNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "email": "valeria@example.com",
      "username": "valeria",
      "displayName": "Valeria",
      "residencyCountry": "SE",
      "subscription": {
        "priceUsd": 9.99,
        "interval": "monthly"
      },
      "legalAccepted": true,
      "acceptedFromIp": "203.0.113.7",
      "acceptedUserAgent": "Mozilla/5.0",
      "kycReturnUrl": "https://crm.example.com/onboarding/done"
    }'
```

Node:

```javascript
const res = await fetch('https://www.dropfans.io/api/external/v1/accounts', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.APP_OWNER_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "email": "valeria@example.com",
    "username": "valeria",
    "displayName": "Valeria",
    "residencyCountry": "SE",
    "subscription": {
      "priceUsd": 9.99,
      "interval": "monthly"
    },
    "legalAccepted": true,
    "acceptedFromIp": "203.0.113.7",
    "acceptedUserAgent": "Mozilla/5.0",
    "kycReturnUrl": "https://crm.example.com/onboarding/done"
  }),
});
console.log(await res.json());
```

Python:

```python
import os, requests

res = requests.post(
    "https://www.dropfans.io/api/external/v1/accounts",
    headers={"Authorization": f"Bearer {os.environ['APP_OWNER_KEY']}"},
    json={
      "email": "valeria@example.com",
      "username": "valeria",
      "displayName": "Valeria",
      "residencyCountry": "SE",
      "subscription": {
        "priceUsd": 9.99,
        "interval": "monthly"
      },
      "legalAccepted": True,
      "acceptedFromIp": "203.0.113.7",
      "acceptedUserAgent": "Mozilla/5.0",
      "kycReturnUrl": "https://crm.example.com/onboarding/done"
    },
)
print(res.json())
```

## 3. Keep what comes back

`apiKey` is bound to your app and shown once. You can upload and create drops straight away, but drops stay unsellable until the ID check is approved. `kycUrl` is valid for 24 hours; get a fresh one with `POST /accounts/{id}/kyc-session`.

## 4. Send them through the ID check

Redirect the creator to `kycUrl` in a full page or new tab, never an iframe. They come back to your `kycReturnUrl` with `?kyc=approved|declined|in_review`. Show the matching screen, but unlock nothing yet.

## 5. Wait for the decision

The decision arrives as an `account.kyc_updated` webhook. With `kycStatus: "approved"` the account is active and can sell and get paid.

Event data:

```json
{
  "accountId": "...",
  "username": "valeria",
  "kycStatus": "approved",
  "sellerStatus": "..."
}
```

## Next

- [Creator verification](https://2fans.dev/docs/handled/verification.md): How creators are verified: an ID document, face match and liveness check through Didit, with records kept by 2fans and status available in the API.
- [Webhooks](https://2fans.dev/docs/build/webhooks.md): Set one signed endpoint for your app and react to sales, refunds, subscriptions, payouts and ID-check results.

2fans was called Dropfans until October 2026, so the API host is still www.dropfans.io and keys still start with dpfn_.

Last updated 2026-11-02. All pages: https://2fans.dev/llms.txt.