MuseMVP

MuseMVP Base: Next.js for Node and Cloudflare. MuseMVP Flare: an AI SaaS template that runs entirely on Cloudflare. Authentication, billing and administration included.

Product
  • Home
  • Pricing
  • Templates
Resources
  • Docs
  • Blog
  • Changelog
Legal
  • Privacy
  • Terms
  • Community
Open-Launch Top 1 Daily WinnerOpen-Launch Top 1 Daily WinnerVerified DR - Verified Domain Rating for musemvp.comVerified DR - Verified Domain Rating for musemvp.comMuseMVP - Featured on Startup FameMuseMVP - Featured on Startup FameFazier badgeFazier badgeLiftOff award badgeLiftOff award badge

© 2026 MuseMVP. All rights reserved.

MuseMVP
  • Pricing
  • Docs
  • Blog
  • Changelog
Buy MuseMVP Flare
MuseMVP Docs
MuseMVP Docs
OverviewTech StackGet SourceQuick StartProject Structure
DatabaseAPIAuthenticationBillingObject StorageEmail
AI OverviewImagesVideo and VoiceChat and SummariesCredits and Cost Control
Deployment
AI

Credits and Cost Control

The credit ledger, plans and credit packs, server-side refusals, the daily budget, refunds and admin recovery.

The ledger

Every balance change is a row in the append-only ledger table in D1. The balance is the sum of its rows. Each row id encodes the user, the kind and the source, so a retry, a queue redelivery or a double click writes the same id and is ignored:

KindId patternWritten when
grant{user}:grant:{source}Welcome credits after email verification, a paid order, an audited admin grant
reserve{user}:reserve:{task}Before a generation is sent to a provider
release{user}:release:{task}Once, when a reserved generation fails, is canceled or is refunded

A successful generation keeps its reservation; there is no second charge at completion. Rows also carry reason and ref, which the usage page at /app/usage turns into readable lines. Any new writer must set them, and a reversing row copies them from the row it reverses.

Never deduct credits in a component or before the request, and never charge again inside a queue retry. Change balances only through these ledger writers.

Selling credits

The sellable catalog is in packages/config/src/index.ts:

EntrykindDefault
Proplan, recurring1,000 credits a month
Lifetimeplan, one-time10,000 credits
1,000 creditspack, one-time1,000 credits; set requiresPlan to sell packs only to plan holders

Packs are always one-time. The credits are fixed on the order at checkout, so editing the catalog later does not change what an existing order grants. Fill in each gateway's product ids and enable gateways as described in Billing setup.

Server-side refusals

Every generation is priced on the server and refused before anything is reserved:

StatusCodeWhen
402balance and next stepThe balance is below the price; the body says whether a plan or a pack is the next step
429too_many_active_tasksThe user already has ai.maxActiveTasks unfinished tasks
503capacity_reachedToday's estimated upstream spend plus this task would pass ai.dailyBudgetUsd

Disabling a button in the UI is not a substitute for these checks.

Daily budget

Each catalog model carries an estimated costUsd. Reserving a task adds its estimate to the spend since UTC midnight; the cap is shared by all users and protects your provider bill from abuse or a pricing mistake. Mock runs count as free. Set ai.dailyBudgetUsd to 0 to turn the cap off, and keep provider-side limits as well.

The margin check keeps prices honest: a model is valid only when credits × cheapest credit price ≥ costUsd × (1 + ai.minGrossMargin). Re-run pnpm test:unit after changing a price or a pack.

Failures and refunds

  • A retryable provider failure is attempted again up to ai.maxAttempts (3). A final failure releases the credits once.
  • A provider content refusal releases the credits while ai.refundOnContentRefusal is true.
  • Every five minutes the cron reclaims expired leases, releases tasks that ran out of attempts or time (video after 30 minutes) and redispatches the outbox.

Admin recovery

Admins see recent AI tasks at /app/admin, backed by GET /api/admin/ai_tasks: status, attempts, error category, cost and whether credits were returned. POST /api/admin/ai-refund with { "taskId": "..." } returns the credits of a finished task once; a second call answers 409 not_refundable. Admin grants through POST /api/admin/credits are audited.

Verify

  1. Generate with too few credits and confirm 402 and an unchanged balance.
  2. Start more than ai.maxActiveTasks generations and confirm 429.
  3. Lower ai.dailyBudgetUsd in a live test and confirm 503.
  4. Cancel a queued task, or let a live task fail, and confirm exactly one release row. pnpm test:workers covers retries and refunds.
  5. Refund a finished task as an admin twice and confirm the second call is refused.

Default OpenAI pricing

The default image model costs 20 credits per output (80 for four images), chat costs 1 credit per message, summaries cost 5, and speech costs max(1, ceil(characters / 1000 × 5)). Prompt enhancement remains free within its per-user rate limit.

Image tasks reserve an estimated $0.15 per output; reported OpenAI token usage replaces the estimate after completion. Speech reserves an estimate of $0.035 per 1,000 characters because WAV responses do not include token usage. These are application cost estimates, not a promise about your provider bill. The daily task budget covers the media-task pipeline; it is not a global cap on chat, summaries or prompt enhancement. Keep provider-side spending limits too.

Chat and Summaries

Streaming chat on OpenAI, conversation history, document summaries on Queues, prices and limits.

Theme

Customize the current shadcn/Base UI components, semantic tokens, and Geist/Fraunces typography.

On this page

The ledgerSelling creditsServer-side refusalsDaily budgetFailures and refundsAdmin recoveryVerifyDefault OpenAI pricing

One payment. Tax included.

MuseMVP Flare

TanStack Start on Cloudflare, with four AI studios built in.

$69

Buy MuseMVP Flare