# Earnings, balances and payouts

Show earnings and balances in your product, set up crypto, bank or Paxum payouts, and request them through the API without sending creators to 2fans.

Earnings and balance reads are on by default. Setting up methods and requesting payouts needs an app key with the Payouts category, which starts switched off, so ask us to enable it. A personal key can read payouts but not change them; those creators request payouts in the 2fans dashboard. All money is in USD cents.

## 1. Read earnings

`startDate` and `endDate` are required. `stats.totalEarningsCents` is what the creator keeps, `stats.grossEarningsCents` is what buyers paid, and refunds and chargebacks are left out.

curl:

```bash
curl "https://www.dropfans.io/api/external/v1/earnings?startDate=2026-08-01&endDate=2026-08-19&tz=Europe/Stockholm" \
  -H "Authorization: Bearer $DROPFANS_API_KEY"
```

Node:

```javascript
const res = await fetch('https://www.dropfans.io/api/external/v1/earnings?startDate=2026-08-01&endDate=2026-08-19&tz=Europe/Stockholm', {
  headers: { Authorization: 'Bearer ' + process.env.DROPFANS_API_KEY },
});
const { stats, chart, transactions } = await res.json();
```

Python:

```python
import os, requests

HEADERS = {"Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}"}
res = requests.get("https://www.dropfans.io/api/external/v1/earnings?startDate=2026-08-01&endDate=2026-08-19&tz=Europe/Stockholm", headers=HEADERS)
data = res.json()
```

## 2. Read the balance

`GET /balance` shows where the money sits: `pending` (in the release hold), `available` (payable), `processing` (in a payout run) and `paidOut` (lifetime). `GET /payouts/summary` adds the minimum, the payout method and whether a request would be accepted right now.

curl:

```bash
curl "https://www.dropfans.io/api/external/v1/payouts/summary" \
  -H "Authorization: Bearer $DROPFANS_API_KEY"
```

Node:

```javascript
const res = await fetch('https://www.dropfans.io/api/external/v1/payouts/summary', {
  headers: { Authorization: 'Bearer ' + process.env.DROPFANS_API_KEY },
});
console.log(await res.json());
```

Python:

```python
import os, requests

HEADERS = {"Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}"}
res = requests.get("https://www.dropfans.io/api/external/v1/payouts/summary", headers=HEADERS)
print(res.json())
```

## 3. Add Paxum

The email has to belong to an active Paxum account. `isDefault` makes it the method payouts go to. The account has to have passed the ID check.

curl:

```bash
curl -X POST "https://www.dropfans.io/api/external/v1/payouts/methods" \
  -H "Authorization: Bearer $DROPFANS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "type": "PAXUM_P2P",
      "paxumEmail": "jane@example.com",
      "nickname": "Main Paxum",
      "isDefault": true
    }'
```

Node:

```javascript
const res = await fetch('https://www.dropfans.io/api/external/v1/payouts/methods', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.DROPFANS_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "type": "PAXUM_P2P",
    "paxumEmail": "jane@example.com",
    "nickname": "Main Paxum",
    "isDefault": true
  }),
});
console.log(await res.json());
```

Python:

```python
import os, requests

res = requests.post(
    "https://www.dropfans.io/api/external/v1/payouts/methods",
    headers={"Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}"},
    json={
      "type": "PAXUM_P2P",
      "paxumEmail": "jane@example.com",
      "nickname": "Main Paxum",
      "isDefault": True
    },
)
print(res.json())
```

## 4. Or set up the wallet for crypto, bank and card

Crypto, bank transfer and card are cash-out options inside a MassPay wallet, chosen by the creator when they cash out. Send the profile to create the wallet. `country` is a three-letter code, and `dateOfBirth` is optional.

curl:

```bash
curl -X POST "https://www.dropfans.io/api/external/v1/payouts/masspay/profile" \
  -H "Authorization: Bearer $DROPFANS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "accountType": "INDIVIDUAL",
      "firstName": "Jane",
      "lastName": "Doe",
      "email": "jane@example.com",
      "country": "SWE",
      "address1": "Storgatan 1",
      "city": "Stockholm",
      "stateProvince": "Stockholm County",
      "postalCode": "111 22"
    }'
```

Node:

```javascript
const res = await fetch('https://www.dropfans.io/api/external/v1/payouts/masspay/profile', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.DROPFANS_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "accountType": "INDIVIDUAL",
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "jane@example.com",
    "country": "SWE",
    "address1": "Storgatan 1",
    "city": "Stockholm",
    "stateProvince": "Stockholm County",
    "postalCode": "111 22"
  }),
});
console.log(await res.json());
```

Python:

```python
import os, requests

res = requests.post(
    "https://www.dropfans.io/api/external/v1/payouts/masspay/profile",
    headers={"Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}"},
    json={
      "accountType": "INDIVIDUAL",
      "firstName": "Jane",
      "lastName": "Doe",
      "email": "jane@example.com",
      "country": "SWE",
      "address1": "Storgatan 1",
      "city": "Stockholm",
      "stateProvince": "Stockholm County",
      "postalCode": "111 22"
    },
)
print(res.json())
```

## 5. Have the creator activate the wallet once

This is the one step a person has to do. Before the first payout, the creator opens `activationUrl` once in a browser, which is a MassPay requirement. It’s a MassPay page, not 2fans. The link expires, so fetch it right before you show it and never store it.

curl:

```bash
curl "https://www.dropfans.io/api/external/v1/payouts/masspay/activation" \
  -H "Authorization: Bearer $DROPFANS_API_KEY"
```

Node:

```javascript
const res = await fetch('https://www.dropfans.io/api/external/v1/payouts/masspay/activation', {
  headers: { Authorization: 'Bearer ' + process.env.DROPFANS_API_KEY },
});
console.log(await res.json());
```

Python:

```python
import os, requests

HEADERS = {"Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}"}
res = requests.get("https://www.dropfans.io/api/external/v1/payouts/masspay/activation", headers=HEADERS)
print(res.json())
```

Response:

```json
{
  "provisioned": true,
  "activated": false,
  "activationUrl": "https://payee.masspay.io/activate/…"
}
```

## 6. Request the payout

This requests the full available balance; partial payouts aren’t possible. The `Idempotency-Key` header is required, so a retry can’t pay twice. We review each request and send it, and `payout.*` webhooks report each stage.

curl:

```bash
curl -X POST "https://www.dropfans.io/api/external/v1/payouts/requests" \
  -H "Authorization: Bearer $DROPFANS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "note": "October" }'
```

Node:

```javascript
const res = await fetch('https://www.dropfans.io/api/external/v1/payouts/requests', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.DROPFANS_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ note: 'October' }),
});
const { requests } = await res.json();
```

Python:

```python
import os, uuid, requests

res = requests.post(
    "https://www.dropfans.io/api/external/v1/payouts/requests",
    headers={
        "Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={"note": "October"},
)
print(res.json()["requests"])
```

## Who can do what

| | Personal key | App key with the Payouts category |
| --- | --- | --- |
| Read balances and history | Yes | Yes |
| Add payout methods | No, use the dashboard | Yes |
| Request a payout | No, use the dashboard | Yes |

A payout request acts for the key's own account, so use the key made for that creator. An agency can read a managed creator's payouts but can't request a payout for them.

## Next

- [How payouts work](https://2fans.dev/docs/handled/payouts.md): Earnings land in the creator’s 2fans balance. From $20 they can request a payout as crypto, a bank transfer or to a card through MassPay, or to Paxum, all included with 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.