Plans
Every tenant is on a plan. The Plan enum has three values:
FREE_TRIAL | PRO | ENTERPRISE
A self-serve signup provisions on FREE_TRIAL. (The database column
default is PRO — that's the legacy value backfilled onto tenants created by
hand before self-serve existed; new self-serve tenants are explicitly set to
FREE_TRIAL at approval.)
Limits
Limits live in code (PLAN_LIMITS) and are surfaced to merchants at
GET /api/v1/merchant/limits (usage + cap per metric).
| Metric | FREE_TRIAL | PRO | ENTERPRISE |
|---|---|---|---|
| Catalog items | 25 | 500 | unlimited |
| Public API calls / UTC day | 1,000 | 10,000 | unlimited |
| Storage | 100 MiB | 1 GiB | unlimited |
| Staff seats | 1 | 5 | unlimited |
| Storefronts | 1 | 5 | unlimited |
Enforcement and error responses
Both FREE_TRIAL and PRO enforce their metered limits. ENTERPRISE
has no cap on these metrics. Resource limits and API request allowances use
different responses:
| Limit | Enforcement | Response when exceeded |
|---|---|---|
| Catalog items | Before an addition to the non-archived catalog count, including create or restore | 402 with code: "LIMIT_EXCEEDED" |
| Storage | When minting a signed upload URL and again against the actual object size on image confirmation | 402 with code: "LIMIT_EXCEEDED" |
| Staff seats | Before inviting a teammate | 402 with code: "LIMIT_EXCEEDED" |
| Public API calls | Per tenant, on metered public requests | 429 with code: "RATE_LIMIT_EXCEEDED" |
The API allowance uses a fixed UTC day, resetting at UTC midnight, rather
than a rolling 24-hour window. Its 429 includes details.resetsAt,
details.retryAfterSeconds, and a matching Retry-After header. Respect that
wait before another request; a quota refusal is not a resource-limit 402.
Resource caps reject additions that would exceed the limit; they do not delete
existing data. Concurrent additions can pass their checks before either write
finishes, so a cap is not an atomic reservation guarantee. Once usage is over
the cap, further additions are blocked until usage is reduced or the cap changes.
The storefronts cap remains forward-looking and is not enforced on any plan.
Staging addition: included hosted-page allowance
The staging contract also meters calls from cartonium-hosted pages within
the total API allowance: 100 per UTC day on FREE_TRIAL, 1,000 on PRO,
and unlimited on ENTERPRISE. These are included calls, not an extra allowance.
Exhausting either ceiling returns 429; a hosted-allowance refusal includes
details.limitKey: "hostedApiCallsPerDay".
In that contract, GET /merchant/limits reports
limits.hostedApiCallsPerDay, usage.hostedApiCallsToday, and
hostedApiApplicable. The applicability flag describes the current checkout
mode; false does not erase previously recorded hosted usage. This staging
addition is separate from the existing public API allowance above.
Platform billing
Platform billing is E7: a tenant pays cartonium for its SaaS plan. Shopper subscriptions are E5: a customer pays a tenant through that tenant's connected payment account. These have separate billing identities, credentials and lifecycles.
The contracts below are implemented on staging. Their presence in the API reference does not establish Production availability or enable billing for an environment. Published prices, provider readiness and the organization's current billing state still determine which actions can run.
Merchant billing endpoints require an authenticated merchant bearer token,
x-organization-slug, and an Owner or Admin membership in that organization.
Shopper sessions and storefront API keys do not authorize these operations.
Storefront Sandbox selection does not isolate platform billing. The API deployment and the payment provider's test/live mode are separate; a storefront Sandbox header does not select payment test mode.
GET /api/v1/public/plan-pricing is an anonymous, organization-independent
projection of published, sellable CURRENT plan prices. Missing prices are
omitted; the result can be empty. Use returned currency, unitAmount (minor
units) and opaque quoteId when displaying an offer. Purchase requests
revalidate those terms; cached pricing is not authority to charge or grant access.
The implemented endpoint families are distinct:
| Family | Contract |
|---|---|
/api/v1/merchant/platform-billing | Read the current provider-subscription billing state. |
…/address | Read or update the billing address and its usability. A successful update does not prove provider synchronization completed. |
…/subscribe, …/resume-payment | Existing provider-subscription purchase and exact invoice recovery. |
…/payment-method, …/payment-method/confirm | Start card replacement for an existing provider subscription, then verify the successful setup and apply that card to the subscription. |
…/invoices | Read cursor-paged invoice history for the existing provider subscription. Returned hosted invoice/PDF URLs are credentials: do not log them or put them in shared caches. |
…/plan-change/*, …/cancel, …/reactivate | Provider-subscription changes and period-end cancellation controls. |
…/purchases/* | Local first-purchase quotes, review, consent, method setup, initial payment, recovery and local invoices. |
…/agreements/* | Local recurring agreements, period-end cancellation intent and exact renewal recovery. |
Existing provider subscriptions retain their matching contracts.
resume-payment recovers an existing INCOMPLETE or PAST_DUE invoice without
adopting a new public offer; reactivate reverses a scheduled cancellation.
Neither is a replacement first purchase. The local purchase/agreement family
does not automatically migrate existing subscriptions.
The local first-purchase request currently supports positive-price USD pro
with monthly or yearly cadence. A quote, recurring-use consent, verified
method setup, initial payment and committed activation are separate facts.
Read returned activation state and the agreement's currentPlan; a browser
redirect, saved method or historical payment success does not establish
current paid access. ACTIVATION_HELD does not grant new paid access.
Preserve the original purchase, preparation and quote operation keys after a
lost begin response. Continue using the exact returned references, fingerprints
and generations for review, consent and recovery. Re-read retained state after
a conflict; never replace a payment whose outcome is uncertain. Provider
readiness AVAILABLE does not prove provider acceptance or authorize an action.
A returned handoff clientSecret is transient and belongs only to its exact
setup or payment confirmation. Never log, persist or cache it. Retained status
reads do not return that credential.
Broader local plan administration, discounts, zero-due purchases and negotiated Enterprise billing have separate implementation and activation gates. Accepted product direction does not make those shapes supported by these purchase requests, change the current limits above, or announce a billing launch.
Signup
Request access through litecommerce.io. Enterprise requests are reviewed by the cartonium team.
Related
- Request access — how a tenant gets created
- Tenants & context — what a tenant scopes
- Shopper subscriptions — recurring customer purchases from a tenant