TwelveAI logoTwelveAI
← All posts

A month on the rails: what we shipped

Seven releases, five currencies on one ledger, and our own banking app moved onto the rails we sell. A build log of the last month at TwelveAI, written from the inside.

Sep 23, 2026 · 6 min read · By The TwelveAI Team

PRODUCTTWELVEAI BLOG
A month on the rails: what we shipped

A month ago the TwelveAI engine could hold a conversation about money and hand the execution to whoever you plugged in. Today it holds the money too, in five currencies on one ledger, across seven releases.

The part that matters most to us is quieter than any of that. Our own banking app now runs end to end on the same rails we sell you. Same ledger, same API key, same sandbox, same limits. When something is awkward, we hit it before you do.

This is what happened in between, in the order it happened.

The rails themselves

We started with the ledger: wallets, dedicated account numbers once a BVN verifies, real bank transfers with the recipient's name checked first, and a fee that appears as its own line rather than hiding inside the amount. Then dollars and swaps on the same ledger, priced off live rates.

Every workspace got the whole thing in sandbox on day one, with its own test key. Not a mock with canned figures, but the same ledger arithmetic against fake money, so what you learn in sandbox is true in production.

Then the reporting: an overview with daily movement, wallet and transfer lists, a revenue view showing what a workspace earned on its own rails, and CSV export on every list.

Agents that finish the job

In parallel, the agents stopped being single-turn. A goal can now run in the background across several turns, with memory of what it has already done, a budget it cannot exceed, and the ability to stop and ask a person when it is genuinely unsure. That question lands in an approvals queue rather than becoming a guess.

Agents can also consult each other: one asks another a single read-only question inside a budget, instead of pretending to know.

Every reply became structured. Cards, tables, questions, confirmations and checklists are now first-class parts of a response, so an app can render a confirmation as a confirmation instead of parsing prose and hoping.

Bills, airtime and insights

Bills, airtime and data now pay straight from a workspace's float, and asking for them routes to the right agent instead of wandering into a product search. An insights pack reads spending by category and merchant off the same ledger the transfers wrote to.

We moved our own customers first

The hardest part was not building the rails. It was moving people onto them without anyone noticing.

So the first customer base we migrated was our own. TwelveAI runs a consumer banking app with real people holding real money in it, and in a single cutover we moved all of them onto the engine's rails: every account number preserved, every historical transaction still reachable, the engine ledger becoming the source of truth while the old wallets became a mirror of it. Not one account failed to move, and not one balance disagreed afterwards. Customers saw nothing, which was the entire goal.

We did it to ourselves first for the obvious reason. A migration path you have never walked is a promise, not a product. Now when we tell you your customers can come across without a glitch, we are describing a road we have already driven with our own money on it.

The work that made that possible is unglamorous and worth naming: a bridge so every existing balance change posts to the engine first, a reconcile command that proves the two sides agree, and a preflight that repairs anything stuck before the move rather than during it.

Running a platform, not just shipping one

Some of the month went on things nobody asks for until they are missing.

A workspace can now set its own price on top of ours, a flat markup per transfer and a margin on FX, both capped so a customer never meets a surprise charge. Workspaces can email their own customers from the console, through our sender or their own. Customers are named by their email rather than an opaque id, and each one carries a stable public id that can be shared without exposing your own numbering.

We also found and fixed the kind of bug that only shows up in production: an alert address that was configured on the server but never reached the running containers, which meant a month of operator alerts had been written to a log and sent to nobody. The morning digest now names any workspace that has quietly run out of balance, because the old alert could only fire on the way down and never after.

And this week

Multi-currency wallets, with naira and dollars live and three more built and waiting on the rail. A settings tab that gathers the few controls that change what a customer can hold and what they are charged, instead of leaving them scattered across tables.

Why we run on our own rails

Plenty of infrastructure companies never use what they sell. The gap shows up in small ways: an error message nobody has ever read, a migration nobody has ever run, a sandbox that behaves nothing like production.

We closed that gap deliberately. Our own app's chat goes through the same engine yours does. Its customers' money sits on the same ledger. Its balances are read by the same tools, under the same confirmations and the same limits.

The result is that a lot of this month's work started as our own annoyance. The sandbox opens with money in it because an empty sandbox taught us nothing. Fees appear as their own ledger line because a lump sum with a footnote was impossible to reconcile. Customers are named by their email because reading a list of opaque ids is miserable. Every one of those was a paper cut we felt, then fixed for everyone.

What we learned

Two things, both obvious in hindsight.

The first is that owning the ledger changes what the conversation can honestly say. An agent reading a number it cannot verify is a liability. An agent reading a number from a ledger you can reconcile is a product.

The second is that the safety rules worth having are the ones the system enforces rather than documents. A currency holding money cannot be switched off. A transfer cannot skip its confirmation. A sandbox cannot touch a real account number. Written down, those are promises. Enforced in code, they are properties.

Related reading