Kessai (Japanese 決済, settlement) is a gateway-agnostic payment contract for Drupal, and the engine that fulfills it. It owns the money side of a payment and leaves the domain decisions, what to charge and what a paid payment means, to the site. A site can run the engine itself, or drive one running on another host.
What it provides
- A payment entity recording amount, state, kind, payment account, the provider reference, the checkout session, an optional stored payment method, kept only when the payer agreed to it, and an optional subject: a type and an id in the consumer’s own words, which need not be an entity on this site. Beside the amount it keeps what actually happened to it: how much has been claimed, how much of a hold has been released, and how much has gone back.
- Money in any currency. Every amount is a figure and the ISO 4217 currency it is in. It has as many decimals as that currency has: cents for a euro, none for a yen, thousandths for a Kuwaiti dinar. An amount its currency cannot hold, such as half a yen, is refused where it is built, before it reaches a payment or a provider. Each payment account says which currencies it accepts.
- Payment accounts, not gateways. A payment records the account at a provider it goes through, rather than the provider itself. A checkout offers the accounts this site holds, never the list of gateway plugins.
- A record per movement of money. A claim takes money off an authorization, a release frees a hold nobody collected, and a refund gives back money that was. Each is a row of its own carrying its amount, its state, the provider’s own reference for it and the caller’s word for what it was, so two endings that move the same total stay legible apart. A caller can name each request with a key of its own: asked again, the request is answered by the movement it made, or by its refusal, and the money moves once. Because each is recorded separately, all three can be partial: one guarantee can yield a fee now and a damage claim later.
- A gateway plugin type, with an offline manual gateway bundled. Optional operations live on capability interfaces a gateway opts into, so the engine asks whether an operation is supported instead of calling it and trusting the answer.
- A locked, idempotent state machine over pending, authorized, captured, released, refunded, canceled, failed and expired. Every transition is a compare-and-set under a lock, so a duplicate provider callback is a no-op and two concurrent callers cannot both charge.
- Deadlines and expiry. Each account decides how long its payments last, and the least time a payer needs to complete one. A site can bound a whole checkout with a maximum deadline, and an account can let a site extend its deadline, so a transfer’s three days can become five for one booking. A cron reaper sweeps the lapsed payments. A payment that reached a provider is asked about before it is written off, within a per-run budget, so a payer whose browser return and webhook both failed is not recorded expired for a payment they actually made.
- Checkout sessions in the engine. The provider session is modeled once, so one session per payment is reused while it is open and no gateway has to cache its own.
- Events for every outcome: initiated, authorized, captured, released, canceled, failed, expired and refunded, plus partially released and partially refunded for the cases that leave the payment where it was. Released is a hold given back in full; canceled is a pending payment the payer backed out of. Four more announce money a provider reports on a payment that had already ended without any, and that money going back, so a late charge is never silently dropped. Consumers react to those without the engine knowing anything about the domain.
- An administration section for the accounts this site holds at its providers, the payments and the money moved against them, and the engine settings. On an account settled by hand, an operator records a payment taken offline as received, from the payments list, without writing code.
Gateways report outcomes through a browser return, a server-to-server webhook, or an operator action. Whichever arrives first records the state change and announces it; the others are no-ops.
Submodules
- Kessai Engine: takes payments on this site: the state machine, and the records it writes.
- Kessai Client: takes this site’s payments through a Kessai on another host, over its API. Nothing a consumer module does changes, and events cross too.
- Kessai Server: exposes this site’s engine to named consumers on other hosts, over an API. Each consumer is pointed at a single account and sees only its own payments.
- Kessai Worldline: the Worldline Direct gateway, hosted checkout and card on file.
- Kessai Simulator: a fake gateway for development and testing.
- Kessai Audit Trail: records payment events into an audit trail.
- Kessai Views: administration views for payments and for each kind of movement against them.
Requirements
Drupal 11.3 or newer, Drupal 12 included, and the bcmath PHP extension. Some submodules need more:
- Kessai Client and Kessai Worldline: the Key module.
- Kessai Worldline: the Worldline Direct PHP SDK.
- Kessai Server: the Consumers and Simple OAuth modules.
- Kessai Audit Trail: the Audit Trail module.
Status
Kessai is in alpha, close to beta. Its entities, base fields, config, routes and interfaces are what beta will ship. Until then a release comes with no update path: a site reinstalls kessai_engine, or migrates its payments by hand as the release notes describe.
Working with Orchestra
Kessai pairs with Orchestra: its orchestra_payment submodule turns a workflow wait node into a payment step, for a booking, an order or a membership.
Project information
- Ecosystem: Yoyaku Booking Engine, Orchestra Workflow Engine, Audit Trail
1 site reports using this module
- Created by mably on , updated
Stable releases for this project are covered by the security advisory policy.
There are currently no supported stable releases.
Releases
Development version: 1.x-dev updated 13 Nov 2026 at 23:16 UTC


