A server route creates a drop and returns its link, you send the buyer there to pay on the 2fans checkout, and a signed webhook tells you when they’ve paid. Keep the key on the server.
1. Create the link
Keep DROPFANS_API_KEY in your server environment. The items must already be in the creator's vault.
// app/api/drop/route.ts
export async function POST(req: Request) {
const { name, price, vaultItemIds } = await req.json();
const res = await fetch('https://www.dropfans.io/api/external/v1/drops', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.DROPFANS_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ name, price, vaultItemIds }),
});
if (!res.ok) return Response.json(await res.json(), { status: res.status });
const { productId, buyUrl } = await res.json();
return Response.json({ productId, buyUrl });
}
Send the buyer to buyUrl. Add ?m=<your reference> to tie the sale to your own chat or user.
2. Verify the webhook
Webhooks need an approved app. Read the raw body before parsing it.
// app/api/webhooks/2fans/route.ts
import crypto from 'node:crypto';
function verify(rawBody: string, header: string, secret: string) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(t + '.' + rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 ?? '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
export async function POST(req: Request) {
const raw = await req.text();
const signature = req.headers.get('DropFans-Signature') ?? '';
if (!verify(raw, signature, process.env.TWOFANS_WEBHOOK_SECRET!)) {
return new Response('Bad signature', { status: 400 });
}
const event = JSON.parse(raw);
if (event.type === 'drop.paid') {
// Queue the work and dedupe on event.data.orderId.
}
return new Response('ok');
}
Answer within 5 seconds and do the work afterwards. Without an approved app, poll POST /drops/check-status instead.
3. Let your agent do it
Give your coding agent Let your AI set it up. It opens each page, you handle the ID check, and it writes the rest.
Key facts
- How it works
- Your CRM creates a link and sends it in the chat. The buyer pays on the 2fans checkout and unlocks content hosted on 2fans.
- Fee
- 15% of each sale; the creator keeps 85%. No monthly, setup or listing fee.
- App commission
- Approved apps earn 5% of every sale made through their links, for life. It’s paid out of our fee, never taken from the creator.
- Payouts
- Earnings land in the creator’s 2fans balance and are released 14 days after each sale. From $20, they can request a payout as crypto, a bank transfer or to a card through MassPay, or to Paxum. All of it is included with the API.
- What you can sell
- Pay-per-view drops, weekly or monthly subscriptions, and tips, each with its own link you can send in Telegram or any chat.
- Prices
- Free, or $5 to $750 per drop, in USD. A drop holds up to 10 items.
- Content
- Photos, video, audio, PDFs and other digital media, including 18+ content and declared AI-generated content.
- Creator checks
- Creators verify with an ID document, face match and liveness check. Uploads need an approved check.
- App access
- For software other people’s creators connect to. A person reviews each application, usually within a few business days. 300 requests a minute and 50,000 a day, per key.
Create a pay-per-view link
curl -X POST "https://www.dropfans.io/api/external/v1/drops" \
-H "Authorization: Bearer $DROPFANS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Beach set", "price": 15, "vaultItemIds": ["VAULT_ITEM_A", "VAULT_ITEM_B"] }'{ "productId": "…", "buyUrl": "https://www.dropfans.io/buy/…", "mediaCount": 2 }