Billing
Flatstack has three plans, each a flat monthly price in GBP, VAT exclusive. Usage never adds a charge: going over a limit slows things down or blocks them instead.
Signing up
There are no free accounts and no trials. After you create a login, choose a plan and pay through Stripe Checkout. Your account exists once Stripe confirms the payment. Until then the login can only see the plan picker and checkout.
| Request | What it does |
|---|---|
GET /v1/billing/plans |
Lists the plans, prices in pence and limits. |
POST /v1/billing/checkout |
{ "planId" }. Returns { "url" } for Stripe Checkout. |
Changing plan
Only account owners can change billing.
| Request | What it does |
|---|---|
GET /v1/billing |
Current plan, any plan change scheduled for the end of the period, and the period end. |
POST /v1/billing/plan |
{ "planId" }. Upgrades apply now and you pay the difference for the rest of the period. Downgrades apply at the end of the period. |
POST /v1/billing/portal |
Returns { "url" } for the Stripe Customer Portal: card, invoices, tax details and cancellation. |
A downgrade is refused with 409 downgrade_blocked while you use more than the smaller plan allows. details.blockers lists each limit you’re over, with how many you have and how many the plan allows. Remove those, then try again.
{
"error": {
"code": "downgrade_blocked",
"message": "Current usage is over the smaller plan's limits. Remove what's listed in details, then downgrade.",
"details": {
"targetPlanId": "hobby",
"blockers": [{ "limit": "projects", "current": 2, "allowed": 1 }]
}
}
}
Add-ons
Add-ons are only ever bought by an owner, on purpose. Nothing is added automatically.
| Add-on | Price | What it adds | How long |
|---|---|---|---|
| Extra project | £5/month | One more project. Usage limits stay pooled across the account. | Until removed |
| Always-on Postgres | £15/month per project | Postgres never sleeps for that project, and it gets 500 CU-h of its own. | Until removed |
| Extra seat | £5/month | One more team member. | Until removed |
| Compute pack | £10 | 200 CU-h. | This billing period |
| Email pack | £5 | 25,000 emails. | This billing period |
| AI credit | £10, £25 or £50 | That much prepaid model usage through the AI gateway. | Until used |
Always-on Postgres and the compute pack need a plan with Postgres (Pro or Studio).
| Request | What it does |
|---|---|
GET /v1/billing/limits |
Your limits now: plan plus add-ons, with per-project extras. |
GET /v1/billing/add-ons |
Add-ons you can buy, the ones you hold, and your AI credit balance. |
POST /v1/billing/add-ons |
{ "addOnId", "quantity"?, "projectId"? }. Monthly add-ons start now and the rest of this month is charged straight away. Packs and AI credit return a Stripe Checkout url and apply once paid. |
DELETE /v1/billing/add-ons/{purchaseId} |
Removes a monthly add-on now, with no refund for the rest of the month. |
You can’t remove an add-on you’re using, such as an extra seat while every seat is filled. The request returns 409 add_on_in_use with details.blockers, as a blocked downgrade does.
If a payment fails
Stripe tries the card again over 7 days. Nothing changes while it does, apart from an email to the account’s owners and admins.
| Stage | When | Your projects | The dashboard and API |
|---|---|---|---|
| Payment failed | First failed payment | Work normally. | Everything works. |
| Locked | The last retry fails | Read-only: files, pages and reads work, writes return 402 account_locked. Sign-in (/auth/*) still works. |
Reads work. Writes return 402 account_locked. |
| Suspended | 30 days locked | Not served: 403 account_suspended. |
Reads and export work. Writes return 403 account_suspended. |
| Deleted | 30 days suspended | Gone. | Gone. |
Pay the invoice from the Customer Portal (POST /v1/billing/portal) at any point before deletion and the account is back as it was within a minute. Nothing is deleted while you’re locked, and nothing is deleted without two warning emails: 7 days and 1 day before. If either warning is late, deletion moves back so there’s always at least a day after the final one.
Cancelling
Cancel from the Customer Portal. The account works normally until the end of the period you’ve paid for. It then becomes read-only for 30 days, with writes returning 402 account_cancelled, so you can export everything. After the same two warning emails, the account and all its data are deleted.
While an account is read-only
Reads keep working everywhere, so the dashboard can show what’s happening and you can export. These writes still work too:
| Request | Why |
|---|---|
POST /v1/billing/portal |
Paying is how you get out. |
POST /v1/tokens, DELETE /v1/tokens/{tokenId} |
The CLI and MCP export with a token; revoking access is always allowed. |
DELETE /v1/members/{memberId}, DELETE /v1/members/invites/{inviteId}, POST /v1/members/leave |
Taking access away is always allowed. |
PUT /v1/notification-preferences |
Your email settings. |
Every other write returns the account’s error:
{
"error": {
"code": "account_locked",
"message": "Payment failed, so this project is read-only. Update the card in billing to restore writes.",
"docsUrl": "https://flatstack.dev/docs/errors/account_locked"
}
}
GET /v1/billing shows where the account is: accountStatus (active, past_due, past_due_locked, suspended or cancelled), and lockedAt, suspendedAt, cancelledAt and deleteAfter as ISO timestamps or null.
As Markdown: api/billing.md