Product

The rules your payments depend on, enforced by the ledger.

TulaDB is three things in one self-hosted product: a ledger engine that enforces your money rules on every write, operations tooling to run it, and an Iceberg analytics pipeline that reports from it. Each section below pairs a business promise with the mechanism that enforces it.

One balance
Every rail posts to the same account
Posts once
Resends deduplicated by each rail's own reference
Hard floors
Limits checked in the same step as the write
Refusals kept
With the engine's or the rail's own code

Where it sits

In front of the core you already have.

Replacing a core to join an instant rail is a multi-year programme. TulaDB goes in front of it instead: the rail talks to the posting ledger; the core keeps its products, statements and interest, and is updated from the ledger's history; finance reconciles from the lake.

Rail adapters

Map each rail's messages onto transfers, holds and refusals. A Real-Time Rail reference adapter is planned and will be built with design partners; it is not available today.

TulaDB

One real-time balance per account, with holds, limits and refusals, for every rail.

Core

Updated from committed history on its own schedule, through a feed built for your core.

Lake

Iceberg export for reconciliation, reporting and the intraday liquidity curve.

Working with your core

Which system owns which balance, agreed before the pilot starts.

A posting layer in front of a core is a two-way arrangement. Instant payments post in TulaDB first; some postings still originate in the core, such as fees, interest, cheques and card settlement. The first design-partner step is agreeing which balances TulaDB owns, how opening balances are loaded, and how each side feeds the other.

Shipped
Committed history, every recorded decline and, optionally, both accounts' balances after each posting, exported to Apache Iceberg. The ledger itself searches by rail, account and time.
Built per partner
The feed from TulaDB into your specific core, and the feed of core-originated postings and opening balances into TulaDB.
Not yet
Packaged connectors for named core systems.

Limits & liquidity

A floor no payment can cross, not a report that says you crossed it.

On an instant rail the payments that drain a position settle before any report arrives. So the position is an account, and its limit is checked by the engine in the same step as each write, one write per account at a time: two payments in the same millisecond cannot both pass a check and jointly breach it.

Settlement-position floor

A floor on the position account. A payment that would cross it is refused and recorded.

Reserved obligations

Hold known outflows on the position; holds nobody settles expire automatically.

Per-client caps

A net debit cap per sponsored client, changeable intraday in one call.

Per-transaction cap

A ledger-wide maximum refuses any single movement above it.

The intraday curve

Balances after every posting, exported to the lake, rebuild the position at every moment.

Double-entry core

The books balance by construction, not by a nightly job.

A reconciliation break found weeks later is a cost: investigation, write-offs, an auditor's question. Here every mutation is an atomic pair: a debit and its matching credit, applied under account-level sequencing. Posted and pending balances are tracked distinctly, account limits are enforced in the ledger, and duplicate operations resolve deterministically rather than double-applying.

Invariant: across any consistent read, the sum of debits equals the sum of credits. The balance isn't reconciled after the fact. It's a property of the write.

Atomic debit & credit

Both legs post together or not at all. There are no half-applied transfers.

Posted vs. pending balances

Available balance reflects holds; posted balance reflects settled value.

Account-level sequencing

Deterministic ordering per account keeps concurrent activity explainable.

Enforced account limits

Limit checks live in the ledger, not in whichever service happened to write.

Reservation lifecycle

Money in flight is held, never spent twice and never lost.

An instant payment is sent, then accepted or rejected; a card is authorized, then captured. In between, the funds must be unavailable to every other rail and recoverable if the payment fails. A reserve holds the debit side without posting the credit. A commit releases the hold and posts the credit. A rollback releases the hold and posts nothing. Each transition is a durable, ordered outcome — so a hold can never quietly leak into an unbalanced state.

TransitionDebit sideCredit sideOutcomeGuarantee
reservehold placednot postedPENDINGAvailable balance drops; posted balance unchanged
commithold releasedpostedPOSTEDExactly one settlement, idempotent under retry
rollbackhold releasednoneVOIDEDFunds return to available; trail preserved
rejectunchangedunchangedREJECTEDDurable record of the declined decision
RequestEffect

transfer · op-id 7f3a…

First delivery

APPLIED

transfer · op-id 7f3a…

Retry after timeout

DEDUPED

transfer · op-id 7f3a…

Duplicate from queue

DEDUPED

One operation identity → one financial effect, however many times it arrives.

Idempotency

A resent message is not a second payment.

Durable operation identity makes retries safe. The same stable caller identity returns the same outcome instead of creating duplicate effects. Timeouts, at-least-once queues and client retries don't turn into double charges or phantom credits. Give each rail its own source identifier and each rail's resends are deduplicated by the reference that rail already uses.

Deterministic duplicate checks derive financial identity from source identifier, ledger, currency and transaction reference.

Operations console & tooling

Run it without writing the runbooks first.

The tooling a payments team otherwise builds after its first incidents ships with the engine. The proof →

Operator console

Viewers read, operators move money, admins change ledger shape, and the server enforces it. Every change is audit-logged, and the console can be set to refuse any action it cannot record.

Alerts with runbooks

156 alert rules, 64 of them paging, each linked to a runbook — available to design partners; not in the 0.0.1-preview downloads. They cover stuck holds, retry storms, decline spikes and disks that will fill.

Backups & restore

Online backups with verification, point-in-time restore when log archiving is on, and scheduled restore drills that prove the backups work.

Upgrades without downtime

Rolling upgrades node by node, with a check that says whether rolling back is still safe before you finalise.

Protection under load

With the limiter enabled, overload slows new payments with a retryable answer; posting or releasing an existing hold is never shed.

Fits your telemetry

Prometheus metrics, six Grafana dashboards, OpenTelemetry traces and structured logs.

Iceberg analytics

Finance works from the lake, and the lake is exactly the ledger.

Committed history and every recorded decline stream to Apache Iceberg, off the payment path, on AWS S3 Tables or Google BigLake. Each commit carries its range and a SHA-256 receipt; the ledger keeps history until the export has it; the console reconciles the lake against the ledger on a schedule and holds reports until they match. The proof →

No duplicates, no gaps

The exporter stops rather than skip a range.

Reconciled against the ledger

Scheduled reconcile and repair; reports wait for complete data.

SQL over the lake

Read-only queries from the console, or any Iceberg engine you already run.

Balances in every row

Optional post-posting balances rebuild any account's intraday curve.

Scope boundary

What TulaDB owns, and what stays above it.

TulaDB is not a payment switch, ISO 20022 parser, fraud engine, compliance workflow, or customer orchestration system. Those stay above the ledger, rail adapters included. TulaDB owns deterministic financial state: balances, holds, limits, postings, rejected outcomes, idempotency, and recovery. Liquidity alerts, forecasting, sweeps and payment queueing are not built.

Not a message parser

Payment and ISO message handling stay at the integration edge; the ledger receives validated financial intent.

Not workflow orchestration

Customer journeys, compliance flows, routing, and approvals stay in application services above the ledger.

The ledger underneath

Balances, holds, limits, postings, refusals as records, deduplicated retries and recovery, enforced on every write.

Developer preview

Evaluate it against your rail, your core and your liquidity rules.

Install locally to see the mechanisms run, then scope a shadow-mode pilot: TulaDB beside your existing posting, reconciled every day, with nothing customer-facing depending on it.