A FastAPI backend with Alpine.js SPA for image generation (FLUX.2-klein) running on Modal, integrated with Credyt.ai for billing and wallet management.
- 🎨 AI Image Generation - FLUX.2-klein model on GPU (A10G)
- 🔐 Auth0 Authentication - JWT-based user authentication
- 💰 Credyt.ai Billing - Customer management, usage tracking, and wallet adjustments
- 🎫 Capability URLs - Secure file access without authentication
- ⚡ Modal Serverless - Scalable deployment with auto-scaling
This application uses a custom "images" asset for usage-based billing:
- Initial Credits: When a user signs up, they're gifted 10 images - allowing them to create 10 images for free
- Shareable URLs: Once an image is generated, users receive a shareable URL to their creation
- Viral Growth Credits: For each unique visit to a shared image, the creator receives 0.1 image credits
- After 10 unique views, they earn another free image generation
- Credit Top-Up: If users run out of credits, they can purchase more through the self-service billing portal
This model encourages sharing and viral distribution while providing a sustainable monetization path.
┌─────────────────────────────────────────────────────────────┐
│ Alpine.js SPA (static/index.html) │
│ - Auth0 authentication │
│ - Credyt.ai-inspired dark theme │
└──────────────────────────┬──────────────────────────────────┘
│ HTTP/REST
▼
┌─────────────────────────────────────────────────────────────┐
│ api_backend.py (FastAPI on Modal) │
│ - Auth0Client (JWT validation) │
│ - CredytAPI (billing & wallet management) │
│ - /api/generate-image (POST) │
│ - /api/billing-portal (POST) │
│ - /files/{user_dir}/{uuid} (capability URLs) │
└──────────────────────────┬──────────────────────────────────┘
│ Modal RPC │ HTTPS API
▼ ▼
┌─────────────────────┐ ┌──────────────┐
│ flux_modal_app.py │ │ Credyt.ai API│
│ (GPU: A10G) │ │ - Customers │
│ FLUX.2-klein-9B │ │ - Events │
└─────────────────────┘ │ - Wallets │
│ - Billing │
└──────────────┘
.
├── api_backend.py # Main FastAPI application
├── auth0_client.py # Auth0 JWT authentication client
├── credyt_client.py # Credyt.ai API client
├── flux_modal_app.py # FLUX.2 GPU backend
├── download_flux_model.py # Model weight downloader
├── static/
│ └── index.html # Alpine.js SPA
└── credyt/
├── 01-asset.json # Credyt asset configuration
└── 02-product.json # Credyt product configuration
- Create an Auth0 account at https://auth0.com
- Create a new Single Page Application
- Configure Allowed Callback URLs:
https://your-modal-app.modal.run/ - Configure Allowed Logout URLs:
https://your-modal-app.modal.run/ - Configure Allowed Web Origins:
https://your-modal-app.modal.run/ - Create an API in Auth0 and note the Audience (API Identifier)
- Sign up at https://credyt.ai and get your API key
- Create an Asset (e.g., "IMG" for image credits) - see
credyt/01-asset.json - Create a Product with pricing and features - see
credyt/02-product.json - Note your Product ID (format:
prp_xxxxxxxxxxxxx)
# Auth0 configuration
modal secret create auth0-config \
AUTH0_DOMAIN=your-tenant.auth0.com \
AUTH0_AUDIENCE=https://your-api-identifier \
AUTH0_CLIENT_ID=your-spa-client-id
# Credyt.ai configuration
modal secret create credyt-config \
CREDYT_API_KEY=key_test_xxxxxxxxxxxxx \
CREDYT_BASE_URL=https://api.credyt.ai \
CREDYT_DEFAULT_PRODUCT_ID=prp_xxxxxxxxxxxxx \
CREDYT_TIMEOUT=10.0
# HuggingFace token (for model downloads)
modal secret create huggingface HF_TOKEN=hf_xxxxxxxxxxxxx# Download FLUX.2-klein-9B (requires license acceptance on HuggingFace)
modal run download_flux_model.py# Deploy FLUX.2 GPU backend
modal deploy flux_modal_app.py
# Deploy API + SPA
modal deploy api_backend.py# Run API backend in development mode (hot-reload)
modal serve api_backend.py| File | Description |
|---|---|
api_backend.py |
FastAPI ASGI app - main application logic |
auth0_client.py |
Auth0 JWT authentication client |
credyt_client.py |
Credyt.ai API client for billing/wallets |
static/index.html |
Alpine.js SPA with Credyt.ai-inspired dark theme |
flux_modal_app.py |
FLUX.2-klein GPU backend (A10G) |
download_flux_model.py |
Cache FLUX weights to Modal Volume |
When a user authenticates via Auth0, the system:
- Extracts the Auth0
subclaim (user ID) - Base64-encodes it for filesystem safety
- Uses it as
external_idto get or create a Credyt customer - Fetches user name and email from Auth0's userinfo endpoint
- Creates customer with default product subscription if needed
Customer Flow:
Auth0 User (sub: auth0|123456)
→ external_id: YXV0aDB8MTIzNDU2 (base64)
→ Credyt Customer ID: cus_xxxxxxxxxxxxx
Image Generation Event:
- Logs to Credyt when image is generated
- Event type:
api_request - Data:
{ "images_generated": 1 } - Subject: User's prompt
Wallet Adjustment (Gift):
- When image is accessed via capability URL
- Adds 0.1 IMG credits to customer wallet
- Reason:
gift - Uses stable transaction_id to prevent duplicates
Users can access Credyt's self-service billing portal via:
POST /api/billing-portal
{
"return_url": "https://your-app.com/success",
"failure_url": "https://your-app.com/error",
"ttl_in_seconds": 600
}Returns a session URL for subscription management.
| Method | Path | Description |
|---|---|---|
| POST | /api/generate-image |
Generate image with FLUX.2, log event to Credyt |
| POST | /api/billing-portal |
Create Credyt billing portal session |
| Method | Path | Description |
|---|---|---|
| GET | / |
Serve SPA |
| GET | /health |
Health check |
| GET | /api/auth-config |
Auth0 configuration for SPA |
| GET | /files/{user_dir}/{filename} |
Capability URL for generated files (adds wallet credit) |
| Volume Name | Path | Purpose |
|---|---|---|
flux-klein-weights |
/models |
FLUX.2-klein-9B model cache |
generated-files |
/generated |
Generated images (capability URLs) |