Skip to content

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 readContextResult
GET /public/subscription-plansAnonymous, with x-organization-slugEligible public plans and a bounded price page for each plan
GET /public/subscription-plans/:slugAnonymous, with the tenant headerOne 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.

InputServer-owned boundary
recurringLines[]: planSlug, local priceId, quantityAt 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 shippingRateIdAt least one shipping/billing tax address is required; physical carts also enforce destination and applicable rate requirements
Optional marketingOptInRetained only when the tenant enabled checkout marketing opt-in
Stable idempotency key and the same complete inputSafe 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.

HandoffMeaning in the staged contract
PAYMENTA server-prepared connected-account PaymentIntent for the amount due now
SETUPCard authorization without a charge; requiresContinuation identifies the remaining billing continuation
NONENo 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 opaque nextCursor.
  • 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.