Latest features: payments and commerce
- Version
- 4.0 preview
- Updated
Taking money is a subsystem now, not a folder of connectors. The payment layer was designed from requirements rather than grown from the old connector code: a payment is a record, every fact about it is an event, exactly one class may change its state, and providers declare what they need rather than carrying their own admin plumbing.
The five ideas
- A payment is a first-class record. One row per attempt against an order — provider, flow, state, amount in minor units, currency, the provider's reference. An order can have several attempts and the ledger shows them all.
- Every fact is an event. An append-only log of every state change, API call and response, webhook (verified or refused) and admin action, with redacted payloads. Nothing about a payment is ever knowable only from a file on disk.
- One state-writer. A single service enforces the legal transitions, verifies amounts against the order, and deduplicates webhooks by a unique key — replay-safe by schema, not by discipline. Providers never touch the database.
- Providers declare, the framework renders. A provider is one self-contained directory: identity, declarative config fields (the admin form renders itself), the flow it runs and the settlement channels it supports.
- The customer's money state is never taken from the request. A return URL carries ids, never
outcomes. A forged
?state=paiddoes nothing.
Three flows, and a taxonomy behind them
What the customer experiences comes in exactly three shapes — redirect (we send the browser to the
PSP and it comes back), onsite (the PSP's own JS renders the payment UI into our page; the card
number never touches CBX) and instructions (no interactive step — payment instructions with a
structured reference, settlement arrives later).
Every PSP form factor maps onto one of those three. New form factors get a mapping, not a fourth flow. And on-site card entry is always the PSP's JS rendering into our page — nothing that would put a card number through CBX is ever in scope.
Settlement arrives three ways
Return-verify, signed webhook, and polling — because in practice a provider gives you some subset of
those and never quite the one you planned on. configbox:payments:poll is the scheduled half, for
providers whose truth only becomes available by asking.
Fourteen providers — and their real status
The roster is deliberately geographic: one integration per market where a local rail is what customers actually use, rather than one global card processor and a shrug. It covers Stripe, PayPal, Mollie, Klarna, Adyen, Authorize.Net, Saferpay, Nexi, PayU, Square, Trustly, PostFinance, the Swiss QR-bill, and DemoPay — the fake, for development, demos and end-to-end tests.
The documentation states each provider's verification status rather than implying it. Some are shipped and live-verified; several are wired against the provider's documented API but have never seen merchant credentials, and say so. Read the roster before promising a client a rail.
- The provider roster, with each one's status
- Admin Guide: choose a payment provider · set up payment methods
Provider secrets are handled properly
Settings a provider declares as secret are encrypted at rest, with the key derived from the host platform's own secret — so a database dump alone cannot decrypt them; it takes the config file too. The admin form never echoes a stored secret: the field renders empty with a value is stored placeholder, the serialized record is redacted, and a blank submission means unchanged while a typed one replaces. Those two halves are one design — shipping only the no-echo field would make every save wipe the API key.
The admin side
A filterable payment ledger with a full event timeline per payment, the provider's references, and the actions an operator needs — mark settled, mark failed, add a note, check with the provider. Plus a recent-events view for when a webhook misbehaves, and a payment-methods form that leads with the provider and swaps its fields live.
Adding a provider
There is a conformance checklist, an explicit server-side contract, and a client-side contract for on-site flows — and the invariants the framework guarantees are each stated as something tested or testable rather than asserted.
The rest of commerce
Not new in this period, but the ground the above stands on, and worth the link from here:
- Commerce setup: groups, currencies, tax, geography, shipping, payment
- Running the shop: orders, customers, reviews, notifications
- Admin Guide: set up taxes · shipping · currencies · customer groups
- Process an order · set up order emails · quotations and saved carts
Next: catalog operations · platform & extensibility · back to Latest features