---
title: "The agent was ready. The bank wasn't."
standfirst: "I asked an AI agent to pay my kids' kindergarten invoices. It turned out to be the most careful party in the payment. The banking infrastructure around it was the weak part."
author: "Jan Cervinka"
author_url: "https://hello-purple.com/authors/jan-cervinka/"
date_published: "2026-09-24T10:23:23.811Z"
canonical: "https://hello-purple.com/reports/the-agent-was-ready-the-bank-wasnt/"
track: "Real stories"
layout: "essay"
publisher: "Hello Purple"
publisher_note: "Hello Purple is a technology publisher from Purple Technology. Its Reports describe what was built and how; they are not financial advice and do not offer or invite the use of any financial service."
llms_txt: "https://hello-purple.com/llms.txt"
interactive: "https://hello-purple.com/reports/the-agent-was-ready-the-bank-wasnt/interactive/"
---

# The agent was ready. The bank wasn't.

> I asked an AI agent to pay my kids' kindergarten invoices. It turned out to be the most careful party in the payment. The banking infrastructure around it was the weak part.

*Interactive edition: The payment the agent assembles, check by check, and the one door in Czech banking it can walk through. https://hello-purple.com/reports/the-agent-was-ready-the-bank-wasnt/interactive/*

## TL;DR

- An AI agent now pays my kindergarten invoices: it reads the four PDFs, checks payee and duplicates, queues one batch, and I sign once.
- On the checks that catch a swapped account number or a double payment, the agent is already more careful than I am.
- Fio is the only Czech bank that lets a private customer initiate payments by API. Everywhere else, that door is for licensed providers or businesses.
- Europe's open banking is open to intermediaries, not to people. FinTS in Germany and bunq in the Netherlands are the other two doors.
- Verdict: the capability arrived before the permission system. The question is no longer whether an agent can pay, but what authority it may hold.

Every month, my children's kindergarten sends me four invoices. I have two kids there, and for each of them I get one invoice for meals and one for tuition.

I often forget to pay them.

This is not because the payments are difficult. Each one is too small a task to command attention and too important to ignore. Open an email, download four PDFs, copy the account numbers, amounts and reference numbers, check them, submit them, approve them. Nothing in the sequence is hard. That is exactly the kind of work a computer should remove from a person's life.

So I asked an AI agent to do it.

The result works. The agent finds the email, reads the invoices, checks the sender and account details, makes sure they have not already been paid, prepares a batch, and sends it to my bank. I get a message telling me the payments are waiting. I open Internetbanking and sign once.

I expected the difficult question to be how much of this I could trust to an agent. Building it gave me almost the opposite answer. On the checks that actually catch invoice fraud and duplicate payments, the agent is already more careful than I am. The weak part is not the intelligence touching the payment. It is the banking infrastructure around it.

## The most careful party in the payment

A familiar invoice is exactly the kind of document a tired person stops reading carefully. The logo looks right. The amount looks plausible. The account number is long enough that checking it feels like work. Change that account number on an otherwise convincing invoice and you have an attack designed for human attention.

My agent does not get tired of the familiar.

It extracts the payment details twice: once from the invoice's SPAYD QR code and once from the printed text. The amount and variable symbol must agree. A mismatch is a refusal, not a guess. The target account, bank code and constant symbol must match the known payee configuration exactly. A reminder document is refused because paying from it could duplicate the original invoices. For the batch to queue without asking me first, each invoice must be within limits, and every parsing and duplicate check must be clean. Anything outside those bounds comes back to me before it reaches the bank.

Before the agent submits anything, it checks an append-only ledger keyed by variable symbol and reads the previous 90 days of bank movements. That catches both invoices the agent has already handled and payments I may have made myself. It records its intent before it sends the request, so a crash cannot erase the fact that a payment may be in flight.

Then there is the dangerous moment. Fio provides no idempotency key and no documented duplicate protection. If a connection fails after the bank receives the batch but before the agent receives the response, retrying can pay the same invoice twice. So the agent never automatically retries a payment POST. An uncertain result stays uncertain and comes back to me.

Corporate finance treats payee validation and duplicate-payment defence as normal controls. Personal finance usually has a person moving four PDFs around late at night. In this arrangement, the agent is not a new risk being restrained by a vigilant human. It is the part that brought those controls into a place that never had them.

## Why I still sign

The workflow is possible because I bank with Fio. Its [customer-facing API](https://www.fio.cz/bank-services/internetbanking-api) lets an account holder create a token in Internetbanking, read account movements and submit a payment batch. It is free and does not require a developer contract or a financial-services licence.

Submitted payments do not execute immediately. They appear in Internetbanking under payments waiting for authorization, where I sign them as one batch. I have kept that step, but not because I think I can redo the agent's checks better in a few seconds on a banking screen.

I sign because the bank offers no better consent object yet.

Fio gives me a choice between a token that can queue payments for my signature and, with additional electronic-signature machinery, full automation. What I actually want sits between those two: this agent may pay this known kindergarten account, only when the QR and text agree, only within the configured invoice and batch limits, and never when duplicate status is uncertain. The agent enforces those rules in my system. The bank cannot hold that bounded mandate on my behalf, so my signature remains the bank's required bridge to the money.

The distinction matters. The tap is not an adult supervising unreliable AI. It is a coarse substitute for a permission the banking system does not know how to express.

## The one Czech door

I expected customer access to be scarce, but I hoped to find two or three Czech banks with some version of Fio's model. The search found one.

Every major Czech bank in the search publishes APIs. That sounds promising until you ask who may use them. At Česká spořitelna, ČSOB, Komerční banka, Moneta and Air Bank, payment initiation is exposed through the regulated PSD2 route. That route is built for licensed third-party providers, with the required certificates and onboarding. It is not a credential a private customer can create to operate their own account.

Raiffeisenbank is the revealing near-miss. Its [Premium API](https://www.rb.cz/podnikatele/ucty-a-platebni-styk/prime-bankovnictvi/premium-api) has almost the same shape as Fio's: the customer gets a credential, imports payments, and authorizes them in banking. But the product is offered to business and entrepreneur accounts, requires setup through a banker and a paid bulk-import entitlement. The capability exists. A private individual is simply not the customer for it.

Revolut makes the distinction even clearer. It offers a real payments API for business customers on paid plans, including approval workflows. On its own Business API page, it says: [“There's no public API for personal Revolut accounts.”](https://www.revolut.com/business/business-api/) Wise follows the same pattern: [API tokens are for business accounts](https://docs.wise.com/guides/developer/auth-and-security/personal-api-token), and EU-based businesses still cannot fund transfers through the API.

So the accurate claim is not that Czech banks cannot automate payments. It is that, among the Czech banks examined, Fio is the only one that gives a private individual a direct way to initiate them. Businesses may program their money. People may use an app.

## Open banking, but not personal agency

This is a strange outcome for Europe, which has spent years on open banking. The APIs are real. The openness is real too, if you are a regulated intermediary. For a person trying to automate their own finances, an API behind a payment-institution licence is functionally a closed door.

It is not a technical necessity. Europe has at least two other living counterexamples.

In Germany, private customers have used HBCI, now FinTS, since the 1990s. Banking software can initiate a transfer using the customer's own credentials, with a TAN confirmation. [Some banks have begun withdrawing payment support](https://faq.internal.outbankapp.com/en/kb/articles/1822direkt-fints-zalungen-zum-16092025-eingestellt), but the protocol still works at most German retail banks.

In the Netherlands, [bunq lets customers create a personal API key](https://doc.bunq.com/basics/getting-started) for their own account without becoming a licensed provider. Its API can execute a payment directly or create a draft that the customer approves in the app.

The European picture is therefore uneven, not uniformly bleak. The research found roughly three direct doors for individuals in the EU: Fio, FinTS and bunq. Business accounts open several more. Across most countries examined, retail customers still have none.

## The infrastructure is moving around the banks

The current wave of agentic-payment infrastructure is converging on consent rather than access. [Visa](https://corporate.visa.com/en/sites/visa-perspectives/newsroom/visa-intelligent-commerce-connect-ai-shopping-for-businesses.html) and [Mastercard](https://www.americanbanker.com/payments/news/visa-mastercard-expand-agentic-ai-deployments) are building agent credentials on card rails. The [Agentic Commerce Protocol](https://docs.stripe.com/agentic-commerce/acp) developed by Stripe and OpenAI uses payment tokens scoped to a particular merchant and purchase. The [x402 protocol](https://github.com/coinbase/x402) lets software pay for an online resource as part of an HTTP request.

These systems differ in almost every implementation detail, and not all of them are designed for invoice payments. What they share is a move away from unlimited access followed by hope. Permission is becoming something software can carry: scoped to a merchant, a purchase, a type of bill, an amount or a period, then revoked.

Most of this progress is happening around retail bank APIs rather than inside them. Card networks are adding agent credentials. New payment schemes are adding mandates. Crypto protocols are letting machines settle directly. Europe's next payment-services package improves the interfaces available to regulated providers, but it still does not give an individual a direct credential for their own account.

That is why I no longer think the important question is whether an AI agent can pay an invoice. It can do that today, and on the checks that catch a changed account number or a duplicate payment, it can do it more reliably than I do. The important questions now sit on the other side: what authority it may hold, how that consent is expressed, who carries responsibility, and which legal and compliance framework applies when software acts.

I started with four kindergarten invoices I kept forgetting. The build showed me something larger than a useful automation. The capability has arrived before the permission system around it.

Hello Purple is starting at that gap. We are not interested in treating agentic finance as a distant prediction or a finished product category. We want to build what is possible now, show where it works and where the infrastructure stops it, and keep mapping the boundary as banking access, consent and the legal frame evolve. That is how we can help people navigate this change, and how we learn which tools need to exist next.

The agent was ready. Our job now is to watch the rest of the system catch up, and help build the parts that do.

## For agents

### Facts and figures

- Bank: Fio banka (Czech Republic). Customer API base URL https://fioapi.fio.cz/v1/rest. A private account holder creates the API token in Internetbanking; no developer contract and no payment-services licence is required.
- Endpoints used: `POST /import/` submits a payment batch (token is a form field, format `xml`); `GET /periods/{token}/{from}/{to}/transactions.json` reads movements for a date range.
- Throttle: one call per token per 30 seconds, shared across reads and writes. The agent waits 35 seconds between calls.
- Response codes observed: HTTP 500 means a bad or inactive token; 409 is the 30-second throttle; 422 is a request for data older than 90 days without temporary strong authentication.
- Token validity: 180 days maximum. Fio exposes no endpoint that returns the expiry date.
- Submitted payments queue in Internetbanking under payments awaiting authorisation and execute only after the account holder signs the batch. Fio sends no notification that a batch is waiting.
- Extraction is done twice per invoice and the two must agree: the SPAYD payment string decoded from the invoice's QR code, and the printed text read with `pdftotext -layout`. The QR is vector graphics, so the page is rasterised at 300, then 600, then 900 dpi until it decodes. 1 of 41 historical invoices never decoded at any resolution, which is why the text path is mandatory.
- Duplicate defence: an append-only ledger keyed on the variable symbol, plus a read of the previous 90 days of bank movements before the first submission of a run. Intent is written to the ledger before the request is sent.
- Proven runs: two batches on 2026-08-20, eight invoices in total, all signed and reconciled against movements.
- Czech banks examined for a private customer's direct payment API: Fio is the one that offers it. Česká spořitelna, ČSOB, Komerční banka, Moneta and Air Bank expose payment initiation through the PSD2 route for licensed third parties. Raiffeisenbank's Premium API is offered to business and entrepreneur accounts. Revolut and Wise offer payment APIs to business accounts only.
- EU counterexamples for private individuals: FinTS (formerly HBCI) in Germany, bunq's personal API key in the Netherlands.

### Steps to reproduce

1. Create a Fio API token in Internetbanking with rights to read movements and submit payment orders. It is usable about five minutes after creation.
2. Read the last 90 days of movements with the `periods` endpoint and index them by variable symbol, amount and counterparty account.
3. For each invoice PDF, decode the SPAYD string from the QR code (rasterise, then decode; retry at higher dpi) and read the printed total, variable symbol and due date with `pdftotext -layout`. Refuse the invoice on any disagreement between the two.
4. Compare payee account, bank code and constant symbol against a known payee configuration. Refuse on mismatch. Refuse reminder documents, which repeat an original invoice's payment.
5. Check the variable symbol against the ledger and the movements. Refuse anything already handled or already paid by hand.
6. Write the intent to the ledger, build one payment batch in Fio's XML (element order is mandatory), submit it once with `POST /import/`. Never retry the POST; an inconclusive result stays inconclusive and is surfaced to the account holder.
7. Sign the batch in Internetbanking. Reconcile afterwards by re-reading movements: match on variable symbol, amount and account, because the batch id returned by the import is not the instruction id that appears on movements.

### Limits

- Fio's API has no idempotency key and no documented duplicate detection. The client-side ledger is the duplicate defence.
- The token is either able to queue payments for signature or, with additional electronic-signature machinery registered in person at a branch, able to execute them. There is no scoped mandate in between.
- Movements older than 90 days need temporary strong authentication.
- The `DT` field in the SPAYD string is the invoice's print date, not the due date. Due dates come from the printed text.
- Foreign-currency payments use different XML types and are outside what this workflow handles.

### Sources and links

- Fio API documentation: https://www.fio.cz/bank-services/internetbanking-api
- SPAYD (Short Payment Descriptor) specification: https://qr-platba.cz/pro-vyvojare/specifikace-formatu/
- Revolut Business API (states there is no public API for personal accounts): https://developer.revolut.com/docs/business/business-api
- Wise API documentation: https://docs.wise.com/
- FinTS: https://www.hbci-zka.de/
- bunq API: https://doc.bunq.com/
- Agentic Commerce Protocol (Stripe and OpenAI): https://www.agenticcommerce.dev/
- x402: https://www.x402.org/

### Terms

- Variable symbol (variabilní symbol): the Czech payment reference field, up to 10 digits; on an invoice it is the invoice number. The deduplication key here.
- Constant symbol (konstantní symbol): a Czech payment classification code, fixed per payee here.
- SPAYD: the Czech QR payment string format carried by "QR Platba" codes; holds account, amount, currency, symbols and a message.
- Internetbanking: Fio's web banking, where queued batches are signed.
- Fail closed: a check that cannot be evaluated refuses the payment rather than assuming a safe value.

### About this piece

Written by Jan Cervinka, CTO of Purple Group, published 2026-09-03 on Hello Purple, a technology publisher from Purple Technology. It describes a personal automation built on one bank's customer API and what the build showed about where consent for software payments lives today. Fio banka is unrelated to Purple Group. The piece describes engineering; it is not financial advice and does not invite the use of any payment or banking service.
