This backend provides a speech synthesis API with comprehensive usage tracking, multi-tier subscriptions, and non-expiring credit packs.
index.ts - Main Hono app with route definitions and webhook endpointsmiddleware/auth.ts - User identification, authentication, and plan detection (RevenueCat + admin key)middleware/usage.ts - Dual-bucket usage tracking, allocation, and rate limitingdatabase/usage.ts - Monthly usage tracking operationsdatabase/credits.ts - Non-expiring credits ledger systemplans/config.ts - Central configuration for plans and credit packsX-Environment: SANDBOX or X-Environment: PRODUCTION?environment=sandbox or ?environment=productionADMIN_ACCESS_KEY environment variableBearer {customer_id} or Customer {customer_id}Tracks all character usage:
id - Auto-incrementing primary keycustomer_id - Customer identifier from RevenueCatcharacter_count - Number of characters in the requestrequest_timestamp - ISO timestamp of the requestcreated_at - Database insertion timestampLedger of all credit additions:
id - Auto-incrementing primary keycustomer_id - Customer identifiersource - Type of grant (free_grant, iap, admin, refund)product_lookup_key - RevenueCat product ID for purchasesrevenuecat_tx_id - Transaction ID for idempotencycharacters_granted - Number of characters granted (negative for refunds)price_usd - Price paid for the creditsgranted_at - Timestamp of grantenvironment - Environment of the grant (SANDBOX or PRODUCTION)Ledger of non-expiring credit consumption:
id - Auto-incrementing primary keycustomer_id - Customer identifierusage_id - Foreign key to customer_usage_v1characters_consumed - Number of non-expiring characters usedconsumed_at - Timestamp of consumptionConverts text to speech using LemonFox API.
Headers:
Authorization: Bearer {customer_id} or Authorization: Bearer {admin_key}X-Environment: SANDBOX (optional, defaults to PRODUCTION)Query Parameters:
environment=sandbox (optional, alternative to header)Body:
{ "voice": "voice_name", "input": "text to convert" }
Response:
{ "audio": "base64_encoded_audio", "word_timestamps": [ { "word": "hello", "start": 0.0, "end": 0.5 } ] }
Get comprehensive usage statistics and credit balances.
Headers:
Authorization: Bearer {customer_id} or Authorization: Customer {customer_id}X-Environment: SANDBOX (optional, defaults to PRODUCTION)Query Parameters:
environment=sandbox (optional, alternative to header)Response (Plus/Pro users):
{ "user_tier": "premium", "monthly_limit": 900000, "current_usage": 150000, "remaining_characters": 750000, "usage_percentage": 17, "reset_date": "2024-02-01T00:00:00.000Z", "plan_renewal_date": "February 5, 2024", "plan_term": "monthly", "plan_term_in_days": 30, "plan_key": "plus", "plan_gross_cost": 2.99, "trialing": false, "credits": { "subscription": { "plan_key": "plus", "monthly_limit": 900000, "current_usage": 150000, "remaining_characters": 750000, "usage_percentage": 17, "reset_date": "2024-02-01T00:00:00.000Z" }, "non_expiring_tokens": { "balance": 70000, "total_granted": 95000, "total_consumed": 25000, "purchases": [ { "source": "free_grant", "characters": 45000, "price_usd": 0 }, { "source": "iap", "product_lookup_key": "credit_pack_1hr", "characters": 25000, "price_usd": 2.99 } ] } } }
Response (Free users):
{ "user_tier": "free", "lifetime_limit": 45000, "current_usage": 15000, "remaining_characters": 30000, "usage_percentage": 33, "message": "Subscribe for monthly credits or purchase additional credits.", "plan_renewal_date": null, "plan_term": null, "plan_term_in_days": null, "plan_key": null, "plan_gross_cost": null, "trialing": false, "credits": { "subscription": null, "non_expiring_tokens": { "balance": 30000, "total_granted": 45000, "total_consumed": 15000, "purchases": [ { "source": "free_grant", "characters": 45000, "price_usd": 0 } ] } } }
Webhook endpoint for RevenueCat to notify about IAP purchases and refunds.
Headers:
Authorization: {REVENUECAT_WEBHOOK_AUTH} - Must match environment variableHandled Events:
NON_RENEWING_PURCHASE - Grants credits for credit pack purchasesREFUND - Deducts credits for refunded purchases (negative grant)Environment Handling:
Response:
{ "success": true }
Get current credit balance.
Headers:
Authorization: Bearer {customer_id}X-Environment: SANDBOX (optional, defaults to PRODUCTION)Query Parameters:
environment=sandbox (optional, alternative to header)Response:
{ "customer_id": "customer_123", "balance": 45000, "total_granted": 45000, "total_consumed": 0 }
Health check endpoint.
Response:
{ "status": "ok", "timestamp": "2024-01-01T00:00:00.000Z" }
ADMIN_ACCESS_KEY - Admin authentication keyREVENUECAT_API_KEY - RevenueCat API key for subscription verificationREVENUECAT_WEBHOOK_AUTH - Static auth key for webhook endpointLEMONFOX_API_KEY - LemonFox API key for speech synthesisPDFVECTOR_API_KEY - PDFVector API key for PDF extractionPDF_PARSER_API_KEY - Admin API key for the primary OCR PDF endpoint400 - Bad request (no input text provided)401 - Missing or invalid authorization403 - No active subscription or subscription verification failed429 - Character limit exceeded (both subscription and non-expiring credits exhausted)500 - Internal server errorrevenuecat_tx_id are ignored (INSERT OR IGNORE)customer_usage_v1customer_usage_v1 for all usagecredit_debits_v1 for non-expiring portion only