Why Polar?
- Usage-Based Metering - Bill per character generated
- Transparent Pricing - Clear costs for developers and customers
- Sandbox Mode - Test with card
4242 4242 4242 4242 - No Monthly Fees - Only pay when you earn
- Developer-Friendly API - Simple integration via
@polar-sh/sdk
Prerequisites
- Polar account (sign up free)
- Stripe account (connected via Polar for payments)
Quick Setup
Create Polar account
- Go to Polar
- Sign up with GitHub or email
- Connect your Stripe account when prompted
Polar handles payments via Stripe. You’ll need a Stripe account for production billing.
Create product
In Polar Dashboard, create a new product:
- Click Products → Create Product
- Configure product details:
- Name:
Resonance TTS - Description:
AI-powered text-to-speech with voice cloning - Type: Subscription
- Billing Period: Monthly
- Name:
- Click Create
Add usage meter
Attach a meter to track character usage:
- Open your product
- Go to Meters → Add Meter
- Configure meter:
- Name:
Characters Generated - Slug:
characters - Unit:
characters - Pricing:
- Base price: $0 (or monthly fee)
- Per-unit price: $0.0001 per character (adjust based on costs)
- Example: 10,000 characters = $1.00
- Name:
- Click Save
Adjust pricing based on your Chatterbox TTS costs on Modal. Modal charges ~$0.60/hour for A10G GPU with 5-minute scaledown.
Generate API token
Create an access token for the Polar API:
- Go to Settings → API Tokens
- Click Create Token
- Name:
resonance-api-token - Scopes: Select all (or minimum:
products:read,checkouts:write,customers:read) - Click Create
- Copy the token (starts with
polar_at_)
Polar Client Configuration
Resonance uses the official@polar-sh/sdk for API calls.
Client Setup
src/lib/polar.ts
src/lib/polar.ts:4.
Configuration:
accessToken- API token from Polar Dashboardserver- Usesandboxfor testing,productionfor live payments
Billing Router
The tRPC billing router handles checkout, customer portal, and usage status.Checkout Flow
src/trpc/routers/billing.ts
src/trpc/routers/billing.ts:7.
Flow:
- User clicks “Subscribe” in UI
- tRPC calls
createCheckoutwith organization ID - Polar creates checkout session
- User is redirected to Polar checkout page
- After payment, user returns to
successUrl
Customer Portal
src/trpc/routers/billing.ts
src/trpc/routers/billing.ts:24.
Features:
- View invoices and payment history
- Update payment method
- Cancel subscription
- Download receipts
Usage Status
src/trpc/routers/billing.ts
src/trpc/routers/billing.ts:39.
Returns:
hasActiveSubscription- Whether user has an active subscriptioncustomerId- Polar customer ID (null if not yet created)estimatedCostCents- Current billing cycle usage in cents
Usage Metering
Resonance reports character usage to Polar after each generation.Reporting Usage
Whenever TTS is generated, the character count is reported:src/trpc/routers/.
Usage is aggregated by Polar and billed at the end of each billing period.
Character Counting
Resonance counts all characters in the input text, including:- Letters and numbers
- Spaces and punctuation
- Special markup (e.g.,
[chuckle],[pause])
"Hello world [chuckle]" = 21 characters
Customer Lifecycle
1. Initial Checkout
2. Generation with Metering
3. Customer Portal Access
Sandbox vs Production
Sandbox Mode
Use for development and testing:.env.local
- Test card:
4242 4242 4242 4242(any future expiry, any CVC) - No real charges
- Separate customer database from production
- Full API functionality
Sandbox mode uses Stripe test mode behind the scenes.
Production Mode
Use for live payments:.env.production
- Connected Stripe account with real bank details
- Tax settings configured
- Terms of service and privacy policy links
Pricing Examples
Example Pricing Model
Free Tier Option
To offer a free tier, create two products:- Free Tier - No payment required, limit usage in app code
- Pro Tier - Paid subscription with metering
hasActiveSubscription from getStatus():
Webhooks (Optional)
For real-time billing events, configure webhooks:Webhooks are optional. The
getStatus() query provides current subscription state on-demand.Testing Billing
Sandbox Checkout Flow
Complete checkout
Use test card:
- Card number:
4242 4242 4242 4242 - Expiry: Any future date
- CVC: Any 3 digits
- ZIP: Any 5 digits
Simulating Usage
Generate test generations with varying text lengths:Troubleshooting
Checkout creation fails
- Verify
POLAR_ACCESS_TOKENis correct - Check
POLAR_PRODUCT_IDexists and is active - Ensure product has a meter configured
- Confirm Stripe account is connected (for production)
Usage not tracked
Checklist:- Verify
polar.metrics.create()is called after generation - Check meter slug matches:
characters - Ensure
externalCustomerIdis the Clerk org ID - Look for errors in server logs
Customer not found
- Customers are created automatically on first checkout
getStatus()returnshasActiveSubscription: falseif customer doesn’t exist- Prompt user to subscribe
Sandbox card declined
Use the exact test card:4242 4242 4242 4242
Other test cards for specific scenarios:
- Decline:
4000 0000 0000 0002 - Insufficient funds:
4000 0000 0000 9995
Cost Estimation
Modal GPU Costs
Chatterbox TTS runs on Modal with NVIDIA A10G GPU:- GPU: ~$0.60/hour
- Scaledown: 5 minutes idle before shutdown
- Cold start: ~30 seconds
- 100 generations/hour ≈ 36 seconds per generation
- GPU active time: ~1 hour
- Cost: $0.60/hour
- Per generation: $0.006
Pricing Strategy
To cover costs with margin:- Actual Modal costs (varies by usage pattern)
- Desired profit margin
- Competitive pricing
Related Documentation
Clerk Auth
Organization IDs for customer scoping
Environment Variables
Required Polar environment variables
Modal Deployment
GPU costs and optimization
Polar Documentation
Official Polar documentation