Skip to content

Billing & Plans

For self-hosters: billing is optional. With Stripe disabled, Doable runs as a free internal tool — no plans, no credits, no paywalls. The rest of this page is relevant only if you (the operator) enable Stripe, or if you're using a hosted Doable instance that does.

Plans

The default tiers in the codebase (packages/shared/src/constants.ts) are:

Plan Use case
Free Personal experimentation
Pro Solo creators with regular use
Business Teams with larger workloads, custom domains, more credits
Enterprise Custom — talk to the operator

Each plan defines limits like:

  • AI credits per month
  • Number of projects
  • Number of workspace members
  • Custom domains allowed
  • Integrations allowed

You can edit these freely — they're just JSON constants.

Credits

Doable bills AI usage in credits. Roughly: 1 credit ≈ 1k tokens, scaled by model cost. The exact mapping is in packages/db/src/queries/credits.ts.

When credits run out:

  • The chat panel shows an "out of credits" message.
  • New AI requests return { "error": "credit_exhausted" }.
  • Workspace owners are nudged to top up.

Credits can be:

  • Replenished monthly by your subscription plan.
  • Bought ad-hoc as credit packs (one-time charges).
  • Granted by an admin for promo / support reasons.

Subscriptions

Standard Stripe Checkout flow:

  1. Workspace Settings → Billing → Upgrade.
  2. Stripe Checkout opens.
  3. After payment, Stripe webhooks Doable; the workspace plan is upgraded.

To manage / cancel: Billing → Manage subscription opens the Stripe Customer Portal.

Setup for operators

In .env / docker/.env:

STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRO_MONTHLY_PRICE_ID=price_...
STRIPE_PRO_YEARLY_PRICE_ID=price_...
STRIPE_BUSINESS_MONTHLY_PRICE_ID=price_...
STRIPE_BUSINESS_YEARLY_PRICE_ID=price_...

In Stripe:

  • Create products + prices for each plan tier.
  • Add a webhook endpoint pointing to https://<api>/billing/webhook.
  • Copy the signing secret into STRIPE_WEBHOOK_SECRET.

Webhook events handled: see Webhooks → Stripe.

Disabling billing

Leave the Stripe env vars empty. The billing routes still respond, but:

  • Plan limits are not enforced.
  • Credit balances are tracked but never blocked.
  • The "Upgrade" UI is hidden.

This is the right setup for internal/company self-hosting.

Invoices & taxes

Both come from Stripe. Doable doesn't store invoices itself — users can download them from the Customer Portal.

Refunds

Issue from the Stripe dashboard. Refunds don't claw back credits already spent.

Changing the plan structure

The plan limits are hard-coded in packages/shared/src/constants.ts. Edit and re-deploy. No DB migration needed for limit changes; only for adding/removing plan tiers themselves.