Building an Amex to Monzo Recon Engine with Apple Shortcuts
I recently left Stripe for a new opportunity elsewhere and had some time to kill in between jobs, so thought it would be a good time to solve a small pain point as a side project. Every time I spend on my Amex card, I wanted that same amount moved into a separate pot set aside to cover it. The main benefit of this is that it aligns with my current finance setup in Monzo. I allocate spend across a number of pots (think of them as sub-accounts) which contain funds set aside for specific things like bills, travel, groceries. With Amex spend, I have to manually match each transaction one-to-one and move that money into the Amex pot so my monthly direct debit is covered. Secondly, I’m able to budget on my Amex card like I would with actual cash. I’ve been guilty in the past of overspending on a credit card because my actual bank balance wasn’t being drained until the bill was due at the end of the month.
I thought this would be a good side project to tackle, because I’ve never worked with either the Monzo or TrueLayer API before. Secondly, it was an actual pain point, and I figured I could solve it using my own experience working with integrations that support money movement at Stripe.
How I designed the solution
I took inspiration from my research into how to automate moving Amex spend to a Monzo pot online. I came across a post on the Monzo forum where someone described using AI to help figure out the solution. I already had a skeleton design in my head of how it should come together, from my experience working on money movement integrations at Stripe, but I definitely needed the help of Claude Code to build and test this out of the gate.
For those interested in seeing how the solution works, I’ve left a link to the public GitHub repo above. I’ve also included an AGENTS.md file so you can use whatever agent you want to implement this.
To make this work, I needed:
- Both pending and completed transactions to be reconciled and moved to the Amex pot.
- Reconciliation of Amex spending into the Monzo pot to happen as often as reasonably possible, too long a gap and the budgeting aspect goes a bit out the window.
- The solution to be able to deposit and withdraw funds from the Amex pot, so in cases where the balance is higher (e.g. a refund) or lower (e.g. FX fees), those funds are moved back into my main Monzo balance.
Since Amex doesn’t offer an API like Monzo does, I had to rely on an open banking solution to obtain my Amex spend. TrueLayer polls for data, meaning I wouldn’t be getting webhook events like the Monzo API offers. So I needed to implement a cron job that runs every X amount of minutes so there was an accurate view of what was currently owed to Amex. I used Cloudflare Workers for the cron job that would poll TrueLayer for the Amex spend.
Overall, the solution worked like this:
- Spend on my Amex card
- Cron job runs to understand current spend (both pending and processed)
- Cloudflare pulls current balance from my Amex pot
- Reconciles current balance on Amex with Monzo Amex pot balance
- Money movement happens!
I used Cloudflare Workers since it offers a free account where you can run up to 100,000 requests per day across five cron jobs. Since I only needed one cron job and requests every 60 minutes, it meant I could run this project comfortably without paying for anything.

Using Apple Shortcuts for real-time money movement
There was one slight problem (or annoyance) with this first version. The cron job ran every 60 minutes, which meant I didn’t really get any real-time money movement. It’s not a dealbreaker, but I was keen to try and achieve some aspect of instant money movement between the pots if I could.
After doing some digging, it turns out that I could use Apple Shortcuts to achieve this since there’s an automation for Apple Wallet, which allows you to extract details of a transaction whenever you tap a wallet card or pass. I could then create an API call to my Cloudflare Workers project with the transaction amount and see instant money movement.
Since this is a Wallet-run shortcut, paying online with Apple Pay or Chip and PIN payments won’t work; only tap transactions do. I did consider creating a shortcut to extract the amount spent from Amex notifications, but to be honest around 99% of Amex spend is done in-person via taps, so this was good enough for me. Anything paid online or via Chip and PIN would be picked up via TrueLayer and the hourly cron job.

Seeing it work in practice
I did a couple of dry runs with no real money movement to test that the cron job worked as expected. I then did my first real live transaction to test the shortcut, which worked as expected, I received a “200” response and saw the correct amount of money move instantly to my Amex pot. I then paid for a coffee using Chip and PIN, and about 30 mins later (halfway through a cron job window) £8.70 was moved into my Amex pot, validating the workflows end to end 🎉.
Lessons learned and what to add next
I first tested this using a different Amex card I wasn’t using daily. Swapping to my main Amex card threw a 404 account_not_found error, because I hadn’t actually thought about how onboarding and off-boarding cards should work. I think when working with these types of projects using Claude Code, just following instructions blindly isn’t the end of the world if you know how you want the solution to work end to end, but it makes it super hard to debug where something has gone wrong if you haven’t got a full understanding of how every step works.
As for what’s next, I’ll need to see how this works for my own Amex direct debit, as there’s a 2–3 day lag between when it’s charged and when the bill is actually paid. That means the worker will think there’s an amount owed and reconcile that back into my Amex pot. For now I’ll deal with a shortfall in my Monzo balance for a couple of days, but to solve for this I’ll need to actually start storing the individual transactions and reconciling the total in that billing period against a paid-out direct debit from the Monzo API, so the worker knows the statement has been balanced.