Taxes
Availability: In active development.
This guide describes the current API contracts. A documented endpoint or a successful readiness check does not activate a tenant or establish that every environment is configured to use it.
cartonium calculates checkout tax server-side under the tenant's selected policy. Connected-account calculations use the tenant's own Stripe account; the storefront supplies catalog references and addresses, never a tax amount. The bound checkout total is authoritative for payment.
Select the tenant's tax policy
Merchant settings expose checkoutSettings.taxMode through
GET /api/v1/merchant/settings and PATCH /api/v1/merchant/settings. Settings
writes require settings:manage, merchant authentication, and tenant context.
| Mode | Checkout behavior |
|---|---|
stripe_tax | Require an available connected-account provider. When a tax calculation is needed, the tenant's payment account and Tax setup must also be ready. Failure refuses the operation instead of silently calculating zero tax. |
manual_no_tax | Record zero calculated tax with an explicit disclosure that cartonium did not calculate it. This requires an audited merchant responsibility acknowledgement. |
| Absent (legacy) | Tenants with no stored mode retain legacy provider dispatch. With no provider, or one that does not apply to the organization, tax can remain zero; this policy does not fail closed like an explicitly stored stripe_tax. Save an explicit policy rather than relying on the legacy fallback. |
For a previously unset policy, saving Checkout settings in Admin persists
stripe_tax by default, even when the selector is unchanged. The legacy
absent-policy behavior is compatibility for existing settings, not a fallback
for an explicitly selected policy.
Selecting manual_no_tax requires
checkoutSettings.manualTaxResponsibilityAccepted: true. A tenant Owner or
Admin must establish the acknowledgement; the server records its evidence.
Delegated settings permission alone cannot create that acknowledgement.
Selecting this mode does not declare the sale tax-exempt, and it is never an
automatic fallback for a failed stripe_tax calculation.
Check connected-account readiness
GET /api/v1/merchant/settings/tax-readiness requires a merchant JWT,
x-organization-slug, and settings:manage. It reports connected-provider
readiness independently of the selected tax mode:
status | Meaning |
|---|---|
ready | The provider is available, the payment account is verified, and its Tax settings are active. |
tenant_setup_required | The connected account or its Tax setup is incomplete. |
platform_unavailable | The connected-provider check is unavailable in this environment. |
read_unavailable | The check failed; readiness is unknown. |
The response also includes mode (live, test, or unknown) and
checkedAt. This is Stripe's mode, distinct from taxMode and the
Preview/Production API deployment. Test readiness does not prove live
readiness. This is a technical preflight, not certification of registrations,
product classification, filing, or the tax amount of a later checkout. Bind
checks again before committing.
Hosted tax preview — acceptance pending
Staging contains POST /api/v1/public/checkout/sessions/:token/tax-preview
as a companion to hosted payment entry. It remains outside the released BYO
contract while exact-build acceptance and release are pending. Its presence in
OpenAPI, and the core Taxes availability label above, do not release this
companion route for storefront adoption. BYO integrations continue to use bind
for the authoritative tax-inclusive total.
The implemented preview estimates an ordinary one-time checkout from draft lines, coupon, complete tax address and current shipping selection. It does not support booking or subscription checkout. Shipping is the tax address for a physical cart; a no-delivery cart uses billing. The estimate includes the server-resolved shipping charge.
Preview can create a provider Tax Calculation, but it does not save checkout or address changes, reserve a coupon, extend expiry, bind the total, create a payment or cancel an existing payment. Returned amounts remain provisional; an existing explicit due-now amount can differ from the estimated total. Neither authorizes payment. Bind calculates afresh.
Manual/no-tax results carry taxDisclosure; its supplied label and message
explain that cartonium did not calculate tax. Zero tax or a null disclosure
does not establish exemption. This staged behavior is described for context,
not as a BYO installation recipe.
Bind the final total
Bind independently reprices and recalculates tax before committing the tax-inclusive total. It does not treat an earlier preview as payment authority. Ordinary one-time bind still requires complete billing; physical carts also need their complete delivery address and applicable shipping selection. Customer identity and prepared-payment recovery rules remain those in BYO checkout.
When no positive merchandise amount remains after discounts and charged
shipping is zero, no provider calculation is needed. A stored stripe_tax
policy still requires platform tax availability. Paid shipping remains part of
the calculation even when the merchandise is fully discounted.
After a successful ordinary one-time bind, branch on the summary's
requiresFreeConfirmation: true uses confirm-free for a zero total or a
positive total below the payment provider's per-currency minimum; false uses
payment-session. Do not compare amounts to a client-side threshold. Booking and
subscription checkouts have no no-charge completion path and retain their own
handoff contracts.
Handle refusals
| Response | Integration action |
|---|---|
400 | Correct the reported input error, including an incomplete address or invalid shipping selection. |
409 TENANT_TAX_NOT_CONFIGURED | Ask the merchant to complete the selected policy's setup or acknowledgement. Do not substitute zero tax. |
409 RESOURCE_CONFLICT with details.reason: "CHECKOUT_TAX_POLICY_CHANGED" | Refresh and bind against the current policy. |
Neutral 404 | The token cannot serve this operation. It does not prove an earlier purchase failed. |
429 | Follow the API's quota refusal and Retry-After guidance. |
Tax-calculation 502 | The requested tax calculation failed. Offer an explicit retry while preserving existing checkout/payment recovery rules. |
503 PLATFORM_TAX_UNAVAILABLE | Merchant/support configuration must be restored; do not treat this as a zero-tax result or generic readiness retry. |
These failures do not authorize a replacement payment or bypass the selected tax policy. Use the API reference for exact schemas and Tenant payment accounts for connected-account setup.