How the flow works
- A shopper checks out on a
checkoutMode: 'polar'storefront. Tuturuuu creates a Polar checkout and storespolar_checkout_idon theprivate.inventory_checkout_sessionsrow (statusreserved). - The shopper pays on Polar. Polar sends an
order.updatedwebhook to Tuturuuu. syncInventoryPolarOrdermarks the checkoutcompletedand, when the order ispaid, books the revenue into the workspace finance ledger (wallet_transactions) using the product’s finance category and the workspace default wallet. This is idempotent — a sale books at most one transaction.
Money and currency
Inventory commerce money (storefront listing prices, bundle prices,compare_at_price, checkout session/line amounts, settlement ledger entries,
and costing figures) is stored in integer minor units of the row’s
currency — cents for USD/EUR, but whole units for zero-decimal currencies like
JPY/VND. This matches how Polar represents amounts, so the product/bundle/
checkout sync passes the stored value straight through without scaling.
Conversion is centralized in @tuturuuu/utils/money:
majorToMinor(amount, currency)/minorToMajor(minor, currency)— convert at input/storage and read/display boundaries (currency-aware: USD ×100, JPY/VND ×1).formatMoneyFromMinor(minor, currency)— the canonical display formatter.- The shared
MoneyInput(@tuturuuu/ui/money-input) takes and emits minor units while editing in localized major units.
- The finance ledger (
wallet_transactions.amount) stores major units, sorecordInventorySaleFinanceTransactionconverts the checkout’s minor-unit total back to major units when booking revenue. - Promotions (
workspace_promotions.value) remain in major units (shared with finance invoices);promotions-polarmultiplies by 100 at the Polar boundary.
Inventory base prices use exact decimal major units, while Storefront listing, bundle, checkout, and Polar amounts use integer minor units. Convert only at the explicit provider boundary; never manually multiply a saved Inventory price before publishing it.
Bundles and listings ↔ Polar products
Publishing is automatic: creating or updating a listing/bundle schedules a best-effort push to Polar (a product with a fixed price per currency). Standalone bundles with no storefront publish against the workspace-level Polar integration and are priced in USD. Two-way sync:- App → Polar: name, description, and price sync on every write. Archiving a listing/bundle (or deleting it) archives its Polar product so it is no longer buyable; re-publishing un-archives it.
- Polar → App:
product.created/updatedwebhooks apply name, description, and price back onto the mapped inventory row.
Environment variables
Set these onapps/pay (reference by name only). Inventory-only deployments
that create Polar products also need the access token and sandbox/currency
configuration in their owning runtime:
For sandbox testing, create the credentials at
https://sandbox.polar.sh/dashboard/<org>/settings and the OAuth app /
organization token under User Settings → Developer.
Connect a workspace to Polar
- Open Inventory → Overview → Polar settings in the workspace.
- Choose the environment (sandbox or production) and paste the Polar organization access token. It is encrypted per workspace before storage; only the last 4 characters are ever shown again.
- Save. Tuturuuu validates the token and provisions a private
inventory_checkoutproduct in your Polar org.
Configure the Polar webhook
In the Polar dashboard for your org → Settings → Webhooks → Add Endpoint:-
URL — the canonical Pay webhook endpoint:
For local development, expose
localhostwith a tunnel (e.g.cloudflaredorngrok) and use the tunnel’s HTTPS URL with the same path. -
Format —
Raw. -
Events — subscribe at minimum to:
checkout.createdcheckout.updatedorder.createdorder.updated
-
Copy the webhook secret Polar generates and set it as
POLAR_WEBHOOK_SECRETonapps/pay. Signature verification fails closed if it does not match.
Verify a paid sale books finance
- Place a sandbox checkout on a
polarstorefront and complete payment. - Confirm Polar delivered the
order.updatedevent (Webhooks → Deliveries). - The checkout session flips to
completedwithpolar_status = paid. - A
wallet_transactionsrow appears in the workspace finance ledger for the sale total, linked back viainventory_checkout_sessions.finance_transaction_id.
default_wallet_id) — booking is skipped without one.