Payments Ops Analyst
An AI assistant that explains why card approval rates changed, and shows the numbers and documents behind its answer.
The problem
Every time someone pays by card, the payment is approved or declined. Payment companies watch the share that gets approved, called the approval rate, because each wrongly declined payment is a lost sale and an unhappy customer.
When that rate drops, someone has to find out why. It might be a bank that has gone down, a slow network or a new fraud rule. Answering usually means two separate jobs: digging through reports to see what changed, then searching change logs and notes to find what caused it.
This project does both jobs. You ask a question in plain English, and an assistant built on Claude answers from the reports and the documents, then says where each fact came from.
An example
The payment data here is simulated, and it contains a few problems I planted on purpose. One of them was a fraud rule that went too far. This is what happened when I asked about that week without mentioning fraud or any type of merchant.
Here is what the assistant found:
It also listed what it couldn't confirm. For example, the data doesn't show whether the declined customers were genuine, so it wouldn't claim they were.
I then checked the answer against the source data. The figures matched, with one exception: it said declines reached "about 80 times" normal, and the actual figure is about 86. It also said it couldn't show the rise was spread across banks, when the data could have shown that. Neither mistake changed its conclusion. Read the full answer and the check.
How it works
The numbers say what happened, and the documents suggest why. The assistant is told to treat a matching document as a lead, then check that its dates and scope fit the numbers.
Where this fits in a card payment
Card payments typically run on the four-party model. The cardholder uses a card from their bank, the issuer. The merchant accepts the card through its bank, the acquirer. A card network connects the two banks, and its switch routes each authorization request to the issuer and carries the answer back.
Solid boxes are in the data and dashed boxes are not. The answer returns along the same route, usually within seconds. The money moves later, through clearing and settlement, which are also not simulated. Latency is recorded as one total for each request.
Whose view this is. The reports and documents are written from the viewpoint of an operations team at a fictional payment processor, a company that handles authorizations on behalf of many banks and merchants. That position is why it can compare patterns across 40 banks at once, and why the three planted problems sit in different places:
- Bank outage: at the issuer. The bank's system stops answering, so requests fail with code 91.
- UK slowdown: at the processor. A setting change on its link to the card network makes requests queue, so they're slow but still complete.
- Strict fraud rule: at the processor. Its own rule declines payments at every bank, which is why the rise shows up across all 40 banks and not just one.
Does it work?
The planted problems come with a separate answer key, so results can be checked. I first found all three by hand from the reports, then tested the assistant.
| Planted problem | What the data shows | The recorded cause |
|---|---|---|
| Sep 12: one bank goes down | 178 "bank unavailable" declines at that bank, against 8 to 14 on nearby days | Outage notice from the bank |
| Sep 17: UK payments slow down | Response times around 2,050 ms for two hours, against about 350 ms normally | A gateway setting changed, then rolled back |
| Sep 22 to 24: fraud rule too strict | About 665 suspected-fraud declines a day on online electronics, against about 8 | Fraud rule change log |
| Test | Result |
|---|---|
| Can the assistant find the problems from the reports? | Yes, all 3, and the figures it gave matched the data. |
| Can it connect a problem to its cause in the documents? | Yes, for the fraud rule, in the example above. The other two haven't had the same full test yet. |
| Does the search find the right document? | For 6 of 6 test questions, the expected document was in the top 3 results. For each planted problem, the right document ranked first or second. |
| Can it write a daily report? | Yes. All 10 figures in its sample note matched, and it noticed on its own that the problem had skewed its comparison. |
| Do the data quality checks work? | In a test file of 17 rows, all 10 planted bad rows were removed, along with 2 duplicates, and the 5 good rows were kept. |
What this doesn't prove
- The test is easier than real life. I wrote the data, the documents and the test questions, so I knew the answers. Real change logs are messier and less complete.
- The sample is small. These are a handful of questions, not a full evaluation. A more formal one is the next step.
- Search results can be close. In one test, the right document won by 0.620 to 0.617, and a good result doesn't always put the most useful section first.
- The payment flow is simplified. The data covers the cardholder, merchant, issuer and disputes. It leaves out the acquirer, the network as a separate step, and clearing and settlement. The decline codes follow general ISO 8583 style, while each real network and processor has its own list, so the code numbers here won't match any one network exactly.
- There's no live demo. It runs on my own Databricks and Claude accounts. You can read the sample answers, or run the code and its tests yourself.
What I learned
- Averages hide problems. The bank outage didn't show in daily totals by region. It only appeared after filtering to one decline reason and ranking by bank and day.
- Correct counts can hide wrong content. The first document table had exactly the right 52 rows, yet every row held a whole document instead of one section. Reading the actual text caught it, and the pipeline now fails if that happens again.
- An AI's answer still needs checking. The assistant was mostly right and honest about its limits, and it still got one figure slightly wrong.
What this project shows
This is hands-on project experience with simulated data, not production use.
| Area | What was done |
|---|---|
| Data engineering | Delivered a layered Spark pipeline from raw files to reporting tables, deployed from code, with data quality rules proven on planted bad rows. |
| Payments operations | Worked with authorizations, response codes, issuers, merchant categories, latency and chargebacks, placed within the four-party model. Traced an issuer outage, a latency spike and a fraud rule problem to their causes. |
| Product ownership | Wrote a product requirements doc with users, success metrics, risks and a pricing hypothesis. Ran the work as epics, user stories with acceptance criteria and short sprints in Jira, closing each story with a note of the evidence. |
| Applied AI | Gave an AI assistant safe, read-only access to data and documents, added document search (RAG), and tested its answers against known results. |
| Quality and judgment | Checked results against source data, reported the misses as well as the passes, and stated what the evidence can't prove. |
Technical details
| Part | Built with |
|---|---|
| Data pipeline | PySpark and Spark Declarative Pipelines (Lakeflow) on Databricks Free Edition, serverless, deployed with a Databricks bundle into Unity Catalog. Bronze, silver and gold layers, with Auto Loader ingestion and data quality expectations. |
| Document search (RAG) | Markdown split at headings into a table, a Databricks Vector Search Delta Sync index, and databricks-gte-large-en embeddings. |
| Assistant | A Python server using the Model Context Protocol (MCP), used from Claude Code. The report tools run on in-memory DuckDB with file and network access off, and the SQL tool accepts only a single SELECT. |
| Testing | 17 pytest tests that run without Databricks, including a fake document search, plus a separate script that checks the live search. |
Every result above has its evidence listed in the project summary.
Who built it, and how
This is a personal project, not employer or production work. Claude Code wrote the Python under my direction. I set the requirements and product decisions, reviewed what it wrote, ran the deployments and tests, and typed the Databricks notebook queries myself.