Subscriptions & memberships
Capability status: In active development
This guide inventories the staging implementation of shopper subscriptions sold by a tenant. The capability status above, the API source, and a complete released customer journey are separate evidence. Contracts in OpenAPI do not by themselves establish Production availability or Storefront Skill adoption. The broader subscription release and several consumer flows remain gated.
This is E5 recurring commerce: the tenant is the merchant of record and subscription billing targets its connected payment account. It is separate from platform billing, where a tenant pays cartonium for its software plan. A shopper subscription does not upgrade the tenant's cartonium plan.
One journey, separate sources of truth
A recurring offer combines a published plan, a recurring price, and optional catalog linkage. Checkout freezes the selected terms and returns a server-authored payment or card-setup handoff. Invoice events and reconciliation establish the durable outcome. Customer accounts then expose owned subscription history; the entitlement evaluator decides which benefits are honored now.
The ordinary BYO checkout one-time sequence is a different contract. Do not put recurring selections into its ordinary line shape or substitute its payment-session/free-confirmation calls for the subscription handoff.
All API paths below are under /api/v1. Confirm the API deployment, commerce
dataset, credentials, provider mode and schema identity with
Environments & schema identity. These are separate:
a Preview URL or Sandbox header does not prove payment readiness. Sandbox uses
isolated data and dedicated test-payment configuration, does not deliver
customer email, and does not duplicate the subscription backstop reconciliation.
It does not establish a complete recurring test flow. The following source map
explains existing contracts; it is not a launch or activation checklist.
Plans and recurring offers
| Staging read | Context | Result |
|---|---|---|
GET /public/subscription-plans | Anonymous, with x-organization-slug | Eligible public plans and a bounded price page for each plan |
GET /public/subscription-plans/:slug | Anonymous, with the tenant header | One eligible public or known API-only plan, with price pagination |
The list includes ACTIVE CUSTOMER plans with PUBLIC_STOREFRONT visibility
and eligible ACTIVE recurring prices synced to the tenant's current VERIFIED
connected account. Known-slug detail can also resolve API_BYO_ONLY plans;
those slugs are non-enumerable, not bearer secrets. Unpublished, merchant-only,
stale-account, unsynced, cross-tenant, or catalog-ineligible plans are absent
or return a neutral 404.
Public prices expose a local id, currency, unitAmountInCents, interval,
intervalCount, licensed usageType, and isDefault. Trial terms belong to
the plan. Provider identifiers and authoring metadata are excluded. A
product-backed plan has a server-resolved catalogTarget; membership or
service-access plans can have no catalog target. Catalog sellMode alone
does not prove that an eligible recurring offer exists.
Plan pages return { data, nextCursor }; the cursor continues as cursor.
Each plan's nextPriceCursor continues through the same plan's detail read as
priceCursor. Both cursors are opaque. An empty final price page can result
from eligible prices changing between reads; nextPriceCursor: null ends it.
Recurring checkout: the implemented boundary
POST /public/subscription-checkouts requires x-organization-slug, a live
tenant-bound CustomerSession, and a stable x-idempotency-key. The submitted
customer email must match that verified session. This authenticated recurring
start does not change the separate ordinary one-time guest-checkout contract.
See Customer accounts & sign-in for session handling.
Staged recurring checkout accepts only USD prices matching the tenant's
currency. A different currency, or a price/tenant currency mismatch, is refused
with 409 before any payment is created; public plan visibility does not prove
that a listed price can complete checkout.
| Input | Server-owned boundary |
|---|---|
recurringLines[]: planSlug, local priceId, quantity | At least one recurring selection; provider price ids and client-authored amounts are not accepted |
Optional oneTimeLines[] | Eligible catalog additions billed once on the first subscription invoice; prices resolve server-side |
customer (email, name, optional phone), addresses, selected shippingRateId | At least one shipping/billing tax address is required; physical carts also enforce destination and applicable rate requirements |
Optional marketingOptIn | Retained only when the tenant enabled checkout marketing opt-in |
| Stable idempotency key and the same complete input | Safe replay continues the existing attempt; reusing the key for changed input conflicts |
Recurring lines in one checkout must share account, currency, cadence, and frozen trial policy. Access/service subscriptions cannot mix with order-backed products or one-time additions in that checkout. A no-card trial cannot include a positive amount due today. Address/account topology can also refuse a combination rather than silently change an existing subscription's renewal location. Handle these conflicts without creating a parallel payment path.
The response contains the shared checkout summary, a fresh opaque checkout
token, and a handoff. Safe start replays can issue a new resume token; do
not assume the raw token is the attempt's idempotency identity.
| Handoff | Meaning in the staged contract |
|---|---|
PAYMENT | A server-prepared connected-account PaymentIntent for the amount due now |
SETUP | Card authorization without a charge; requiresContinuation identifies the remaining billing continuation |
NONE | No client confirmation to perform; the authoritative summary still determines whether to wait or show an outcome |
The handoff also supplies the relevant browser-safe publishable key, connected account, amount/currency, and recurring-card explanation. A zero-due card-upfront trial can require setup; zero due today does not imply a free order or completed subscription. No storefront creates its own provider subscription or payment object, or marks a payment/order complete from a browser callback.
Hosted and BYO continuation remain distinct
The staged hosted session UI has a subscription handoff consumer. Its separate continuation uses the opaque checkout capability and tenant context to resume the frozen input, without transferring a BYO customer-session cookie. A BYO start replay instead retains its authenticated identity, original input, and idempotency key. These are different authority boundaries.
Hosted continuation remains outside the adoptable Storefront Skill map. Its OpenAPI presence is not a recipe to redirect or implement it now. Use only the released consumer contract selected for the tenant; do not construct a hosted URL from the plan slug or a deployment hostname.
The hosted account surface does not currently provide a complete subscription
list/detail/reactivation UI. A checkout managementUrl can point to the general
account or sign-in surface; it does not prove subscription-management controls
exist there.
Invoice truth, account history, and recovery
invoice.paid and reconciliation are authoritative for invoice payment and its
downstream results. Read payment and order outcomes separately: an invoice-only
membership can legitimately need no fulfillment Order, while a product-backed
checkout can still be waiting for one. A failed or action-required renewal must
not be shown as confirmed fulfillment. A local canceled checkout does not by
itself prove provider cancellation or absence of future renewal.
The staged account API requires the customer session and tenant context:
GET /customer/account/subscriptions— owned subscriptions, with an opaquenextCursor.GET /customer/account/subscriptions/:publicRef— normalized lifecycle, current terms, sanitized renewal-location snapshots, and a recovery summary.GET /customer/account/subscriptions/:publicRef/billing-periods— normalized billing history, amounts/currency, and its own cursor.GET /customer/subscription-payment-recoveries— normalized recovery status, customer-safe message,nextRetryAt, and paid-only fulfillment eligibility.
Account subscription and period publicRef values are non-authorizing addresses.
Ownership still comes from the session. Recovery and server-to-server DTOs have
different identity fields; do not turn their local ids into shopper-facing URLs
or assume every response has the account projection's shape. Null amounts,
dates, or retry timestamps are not an invented zero, completed payment, or
promise of a retry schedule.
Pending adoption: the published reactivation contract clears a verified period-end cancellation; it does not restore arbitrary ended subscriptions. It remains excluded from generated storefront guidance. Do not infer cancel, pause, plan-change, or renewal-address mutations from a displayed status or address: those shopper commands are not currently published.
Recovery action/proof contracts also remain excluded from the adoptable map. Their source model is scanner-safe: a fragment action waits for explicit customer continuation, exchanges for a short-lived proof, and stays separate from ordinary account sign-in. Hosted code removes the fragment, holds proof server-side, and exposes only a non-authorizing browser handle. Payment preparation reuses the failed invoice's verified existing PaymentIntent; it creates no parallel charge, order, or fulfillment. Exchange does not consume the action or establish payment; authoritative invoice payment completes later. Replacement-link requests are neutral and do not accept a new recipient email.
Entitlements: display is not authority
Staged backend entitlement reads use a server-side only tenant API key with
entitlements:read. The tenant comes from the key. A current per-key check returns
the evaluator's current answer; an unknown or unhonored benefit is not access.
Allowance/service-credit spending requires the separate entitlements:consume
scope, current honor checks, a locked balance cap, and request idempotency.
A read credential cannot spend a balance.
Signed entitlement display tokens are a separate, pending adoption surface.
These Ed25519 JWS snapshots expire after ten minutes. Verification requires the signature,
alg: EdDSA, kid, expiry, iss: litecommerce, aud: entitlements:display,
and use: display; decoding the payload alone is not verification.
Missing signing configuration prevents minting and publishes an empty key set,
while plain reads can still work. The API never accepts even a verified token
as authorization: changing flows use current server truth and guarded commands.
Customer entitlement reads and public verification-key discovery remain explicitly excluded from Storefront Skill adoption. Preserve those boundaries until the complete recurring consumer guidance and release are established.
Related
- Plans & platform billing
- BYO checkout — the separate one-time contract
- Customer accounts — opaque customer sessions
- Storefront Skill — capability and adoption gates
- API reference — the exact contract for the selected schema