Fanfux.app API Expansion
These endpoints let an independent frontend client use the same XNudes database core for account balance, subscription tier, generation history, cached image actions, and gallery feed data.
https://xnudes.app
Version: /api/v1
Auth: API key + Firebase bearer token
Response: JSON
Quick Start
Frontends should authenticate users with Firebase, pass the ID token to the API, and let the backend resolve or create the shared database user by verified email.
X-Fanfux-Api-Key on every call and
Authorization: Bearer <id_token> on user
profile and generation calls.
Minimal request flow
const partnerApiKey = "provided privately by XNudes";
const token = await firebase.auth().currentUser.getIdToken();
const profile = await fetch("https://xnudes.app/api/v1/user/profile", {
headers: {
"X-Fanfux-Api-Key": partnerApiKey,
Authorization: `Bearer ${token}`,
},
}).then((res) => res.json());
const reveal = await fetch("https://xnudes.app/api/v1/generation/reveal", {
method: "POST",
headers: {
"X-Fanfux-Api-Key": partnerApiKey,
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model_id: "00000000-0000-4000-8000-000000000000",
prompt_data: {
mood: "playful",
lighting: "soft studio",
outfit_style: "black dress",
},
is_hd: false,
}),
}).then((res) => res.json());
Authentication
Protected endpoints verify a Firebase ID token and require the Firebase user to have a verified email. All Fanfux API endpoints also require a private integration key.
Integration header
X-Fanfux-Api-Key: <partner_api_key>
User header
Authorization: Bearer <firebase_id_token>
Why both are needed
The integration key proves the caller is an approved client. The Firebase token proves which verified user is making the request, so the API can sync balance and subscription tier by email.
Key handling
The actual integration key is not published in these docs. If it is placed in browser JavaScript, users can inspect and copy it. For strongest protection, call these endpoints from your backend or proxy.
Returns profile identity, subscription tier, Stripe customer linkage, token balance, and free reveal usage.
Request
curl https://xnudes.app/api/v1/user/profile \
-H "X-Fanfux-Api-Key: $FANFUX_API_KEY" \
-H "Authorization: Bearer $FIREBASE_ID_TOKEN"
Response
{
"user": {
"id": "firebase-or-db-user-id",
"email": "user@example.com",
"name": "user@example.com",
"emailVerified": true,
"createdAt": "2026-06-22T08:00:00.000Z",
"updatedAt": "2026-06-22T08:00:00.000Z"
},
"subscription": {
"tier": "free",
"unlimitedTokensEndDate": null,
"stripeCustomerId": null
},
"balance": {
"tokens": 25,
"freeTokens": 2,
"totalTokens": 27
},
"generation": {
"freeRevealsUsed": 0,
"freeRevealsRemaining": 2
}
}
Reveals a model image. If the user has fewer than two free reveals used, the API returns the model static image immediately instead of starting a live GPU job.
| Field | Type | Required | Notes |
|---|---|---|---|
model_id or modelId |
UUID string | Yes | Must match a row in models. |
prompt_data or promptData |
JSON object | No | Accepts keys such as mood, lighting, and outfit style. |
is_hd or isHd |
Boolean | No | Live generations use higher image size and token cost when true. |
Request
curl https://xnudes.app/api/v1/generation/reveal \
-X POST \
-H "X-Fanfux-Api-Key: $FANFUX_API_KEY" \
-H "Authorization: Bearer $FIREBASE_ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model_id": "00000000-0000-4000-8000-000000000000",
"prompt_data": {
"mood": "playful",
"lighting": "soft studio",
"outfit_style": "black dress"
},
"is_hd": false
}'
Free static reveal response
{
"generationId": "11111111-1111-4111-8111-111111111111",
"modelId": "00000000-0000-4000-8000-000000000000",
"actionHash": "f3dc7e7a...",
"imageUrl": "https://...",
"cached": true,
"source": "static_reveal",
"freeRevealsUsed": 1,
"freeRevealsRemaining": 1
}
Live generation response after free reveals
{
"generationId": "22222222-2222-4222-8222-222222222222",
"workerImageId": "image-worker-id",
"modelId": "00000000-0000-4000-8000-000000000000",
"actionHash": "f3dc7e7a...",
"imageUrl": "https://...",
"cached": false,
"source": "live_generation",
"balance": {
"tokens": 23,
"freeTokens": 2,
"totalTokens": 25,
"unlimited": false
}
}
Generates or retrieves a customized image using deterministic
prompt hashing. The server computes
md5(model_id + ":" + JSON.stringify(normalized prompt_data))
and checks stored generations before using the GPU worker.
Request
curl https://xnudes.app/api/v1/generation/customize \
-X POST \
-H "X-Fanfux-Api-Key: $FANFUX_API_KEY" \
-H "Authorization: Bearer $FIREBASE_ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model_id": "00000000-0000-4000-8000-000000000000",
"prompt_data": {
"mood": "confident",
"lighting": "neon",
"outfit_style": "latex"
},
"is_hd": true
}'
Cached response
{
"generationId": "33333333-3333-4333-8333-333333333333",
"modelId": "00000000-0000-4000-8000-000000000000",
"actionHash": "0f6a9b6d...",
"imageUrl": "https://...",
"cached": true
}
Cache miss response
{
"generationId": "44444444-4444-4444-8444-444444444444",
"workerImageId": "image-worker-id",
"modelId": "00000000-0000-4000-8000-000000000000",
"actionHash": "0f6a9b6d...",
"imageUrl": "https://...",
"cached": false,
"balance": {
"tokens": 21,
"freeTokens": 2,
"totalTokens": 23,
"unlimited": false
}
}
Returns generated images ordered by hotness with age decay. This endpoint requires the integration key and accepts an optional limit. It does not require a Firebase user token.
limit is 100 and the default is 50.
Request
curl "https://xnudes.app/api/v1/gallery/photos?limit=25" \
-H "X-Fanfux-Api-Key: $FANFUX_API_KEY"
Response
{
"photos": [
{
"id": "55555555-5555-4555-8555-555555555555",
"modelId": "00000000-0000-4000-8000-000000000000",
"modelName": "Example Model",
"themeId": "66666666-6666-4666-8666-666666666666",
"themeName": "Featured",
"imageUrl": "https://...",
"promptData": {
"mood": "playful"
},
"isHd": false,
"likesCount": 25,
"ageInHours": 4.2,
"score": 1.62,
"createdAt": "2026-06-22T08:00:00.000Z"
}
]
}
Data Model
These are the database concepts exposed by the API. The API uses validated email to keep shared user balances consistent between Fanfux and XNudes.
| Table | Important fields | Purpose |
|---|---|---|
user |
email, tokens,
free_tokens, tier,
free_reveals_used,
stripe_customer_id
|
Shared identity, subscription tier, and token balance. |
themes |
id, name, is_premium_only |
Groups models and gates premium-only content. |
models |
id, theme_id, name,
base_image_url, likes_count
|
Source model cards and static free reveal images. |
user_generations |
user_id, model_id,
generated_image_url, prompt_data,
is_hd, action_hash
|
Generation history and cache lookup source. |
favorites |
user_id, generation_id, model_id |
Vault entries. Free accounts are limited to 10 rows; premium and elite tiers are unlimited. |
Errors
Error responses use JSON with an error string.
Treat unknown errors as retryable only when the HTTP status is
5xx.
| Status | Error | Meaning |
|---|---|---|
| 401 | missing_api_key, invalid_api_key |
Missing or invalid Fanfux integration key. |
| 503 | fanfux_api_key_not_configured |
The server has no Fanfux integration key configured. |
| 401 | missing_bearer_token, invalid_token |
Authentication header is missing or Firebase rejected the token. |
| 403 | email_not_verified |
Firebase user exists but the email is not verified. |
| 403 | premium_theme_required |
Free tier attempted to use a premium-only model theme. |
| 400 | invalid_json_body, invalid_model_id |
Request body is malformed or the model id is not a UUID. |
| 404 | model_not_found |
The requested model id does not exist. |
| 5xx | generation_failed, invalid_generation_response |
Generation service or storage failed. |
Implementation Notes
Details that frontend and backend teams should preserve when integrating another client.
- Do not rely on cross-domain cookies. Always pass the Firebase ID token and let the API resolve the account by verified email.
-
prompt_datais normalized before hashing, so key order does not change the cache key. - Storage URLs may be direct URLs, base64 payloads, or signed Supabase URLs generated by the API.
-
Premium-only themes require
subscription.tierto bepremiumorelite.