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.