A valid payment can still go to the wrong person: an exercise in fencing in an AI agent

Published 8 October 2026

I lead payment teams, and the most tempting pitch for AI agents in banking I've come across is also the simplest: payments get rejected all day, people fix them by hand, so let an agent fix them. It sounds like the perfect first job for an agent, as nobody loves the exception queue (I certainly don't :D).

I came across a report from a CFTE roundtable on how banks move from copilots, which help a person, to agents, which act on their own. Rather than stay abstract, I tried to design one agent end to end: one that repairs rejected payments. My conclusion is that it can be built, but it does much less than "repairs rejected payments" suggests, and most of the work sits around it rather than in it.

Why rejects are a good place to start

A reject is the earliest kind of R-transaction: a bank refuses a payment instruction before settlement because it cannot process it, say a wrong format or an invalid account number. No money has moved yet. That makes it the safest point in a payment's life to let an agent act, because a mistake can still be caught before it costs anything.

Rules first, the agent for the rest

Many rejects already have a fixed answer, and ISO 20022 gives each one a standard reason code. Account closed? Don't retry, send it back. Insufficient funds? Don't retry either. These need a rules engine, which is cheaper, testable and explainable, not an agent.

The agent earns its place only with what a fixed rule cannot handle: free text in the wrong field, a date written in a local format, that kind of mess. And when people approve the same repair every time, it leaves the agent and becomes a rule, or the client sending those files is asked to fix them at the source. The agent's job should shrink over time, not grow.

flowchart LR
    R[Rejected payment] --> K{Known reason code?}
    K -->|yes| F[Fixed rule]
    K -->|no| A[Agent proposes a repair]
    A --> V{Checks outside the agent}
    V -->|passes| S[Resubmitted]
    V -.->|fails| H[Operations team]

Only the dotted line reaches a person: repairs that fail the checks.

A valid message can still be wrong

This is the part that changed how I think about it. A validator checks the form of a message, not its meaning. An IBAN with a typo fails its check digits, and an agent could "fix" it by changing a digit until the check passes. The result is a perfectly valid IBAN that belongs to someone else, and the payment goes to the wrong person with no error anywhere.

So the boundary is not "how much do we trust the agent", it's which fields it may touch. It may change how something is written (character sets, date formats, code values) and never who pays whom or how much: payer, payee, account, amount and currency are off limits. A separate check compares the repaired message with the original and rejects any change to those fields, so the rule holds whatever the agent does.

Measuring the right thing

The obvious metric is the share of repairs that pass validation. It's also the wrong one. A repair that passes and comes back days later as a return or a recall is a failure that no success rate shows. The real measures are what happens to repaired payments afterwards, and the near misses: every time the field check stops the agent from touching a protected field, nothing went wrong, so nothing would be counted, yet it's the agent trying exactly the shortcut of the valid but wrong IBAN.

Those failures are the most valuable data the bank has, as I wrote in The junior work we think we're saving. Here they feed a fixed set of test cases and new rules, never the agent itself: no failures as examples in its prompt and no training on them, otherwise the tests only measure what it memorised.

The people behind it

If only the hard cases reach people, the operations team loses the routine work it used to learn on, and a few years later fewer people can check the agent. Two practices help: a small blind sample, where someone repairs a reject before seeing the agent's proposal, and a few planted wrong proposals in the queue. If people overrule the agent less often, either it got better or they stopped looking, and the planted ones tell the two apart.

Who stands behind a repair

Whatever the agent does, the bank answers for it: to its customer when a payment goes wrong, and to the regulator when a repair hides a sanctions match. Buying the model from a vendor doesn't move that responsibility. So the agent belongs to the head of the operations team whose queue it takes over, and its business case has to count the cost of checking it (the exception queue, the samples, the returns) next to the hours it saves. Count only the hours, and you get the savings now and the costs later, somewhere else.

What I take away

The interesting design work isn't in the agent. It's in the rules that keep its job small, the check that fences it in, the metrics that look past validation, and the people who stay able to say no. An agent that does less, inside walls it doesn't control, is one a bank can actually stand behind.

The blog's author