Create a sellable drop from vault items
Packages up to 10 vault items into a drop and returns a checkout URL.
/api/external/dropsPackages up to 10 vault items into a drop and returns a checkout URL.
Price 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/links' telegram.buyTemplate.
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.
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 |
|---|---|---|---|
name | string | Optional | Drop title, shown at checkout. Falsy values are stored as null. |
description | string | Optional | Checked for prohibited words, then discarded — never persisted or displayed. |
price | number | Required | USD dollars. 0 = free; otherwise $5–$750. Min: 0 Max: 750 |
allowDownload | boolean | Optional | Whether buyers may download the files after purchase. Default: true |
vaultItemIds | string[] | Required | 1–10 vault item ids, in display order. The first becomes the cover. Max items: 10 |
{
"name": "Beach set — 6 photos",
"price": 25,
"vaultItemIds": [
"clxv1a2b30001item",
"clxv1a2b30002item",
"clxv1a2b30003item"
]
}Responses
| Name | Type | Description |
|---|---|---|
productId | string | The new drop’s id — keep it: check-status, GET /drops/{id}, previews and post attachment all key on it. |
buyUrl | string | Web checkout URL to hand to the buyer. For a Telegram Mini App link, substitute the productId into telegram.buyTemplate from GET /api/external/links. Format: uri |
mediaCount | integer | How many vault items were attached. |
{
"productId": "clxdr0p000001prod",
"buyUrl": "https://www.dropfans.io/buy/clxdr0p000001prod",
"mediaCount": 3
}Errors
| Status | Body | When |
|---|---|---|
| 400 | {"error":"Invalid price"} | `price` missing, not a number, NaN or negative. |
| 400 | {"error":"The minimum price is $5. Set the price to free or at least $5."} | Priced above 0 but below $5. |
| 400 | {"error":"The maximum price on Dropfans is $750. To request an increase, contact [email protected]."} | Priced above $750. |
| 400 | {"error":"Field \"name\" contains a prohibited word: \"…\"","field":"name","matchedWord":"…"} | 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). |
| 400 | {"error":"vaultItemIds must be a non-empty array"} | Missing or empty media list. |
| 400 | {"error":"Maximum 10 media items allowed per drop"} | More than 10 ids. |
| 400 | {"error":"Cannot use hidden vault items"} | One of the items was deleted (hidden). |
| 401 | {"error":"Unauthorized","code":"unauthorized"} | Missing or invalid API key. |
| 403 | {"error":"You do not own all selected vault items"} | An id belongs to another creator. |
| 404 | {"error":"One or more vault items not found"} | An id does not exist. |
| 500 | {"error":"Failed to create drop"} | Write failed — retry later. |
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/drops" \
-H "Authorization: Bearer $DROPFANS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Beach set — 6 photos",
"price": 25,
"vaultItemIds": [
"clxv1a2b30001item",
"clxv1a2b30002item",
"clxv1a2b30003item"
]
}'const res = await fetch(`https://www.dropfans.io/api/external/drops`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.DROPFANS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Beach set — 6 photos",
"price": 25,
"vaultItemIds": [
"clxv1a2b30001item",
"clxv1a2b30002item",
"clxv1a2b30003item"
]
}),
});
console.log(await res.json());import os
import requests
res = requests.post(
"https://www.dropfans.io/api/external/drops",
headers={"Authorization": f"Bearer {os.environ['DROPFANS_API_KEY']}"},
json={
"name": "Beach set — 6 photos",
"price": 25,
"vaultItemIds": [
"clxv1a2b30001item",
"clxv1a2b30002item",
"clxv1a2b30003item",
],
},
)
print(res.json())Notes
The drop's moderation status is computed from its media at creation (REJECTED/FLAGGED wins, else PENDING if any item is pending, else APPROVED). Read it back with GET /api/external/drops/{id}.
Questions? [email protected]
