A mid-market credit analyst spends 4-6 hours on a memo. I wired up Claude + a sanctions-list API + a PDF template. It runs in 38 seconds. Here is what worked and what I broke.
|
THE STACK • Claude 3.5 Sonnet • Python • OpenSanctions API • WeasyPrint • n8n |
The Problem Was Hiding in the Calendar
Here's what I just tried: I shadowed a credit analyst at a mid-market lender for a day. Not because I work in finance — I don't — but because a friend kept complaining that her team was drowning in paperwork while actually smart underwriting decisions were getting rushed. By noon she had completed exactly one credit memo. It was a 14-page PDF. It took her since 8 AM.
The memo structure was almost entirely templated. Company background, ownership tree, sanctions check, financial ratio table, risk narrative, recommendation. Same sections, every single deal. The only part that genuinely required her judgment was the risk narrative — maybe 20% of the total document. The other 80% was retrieval and formatting.
So I went home and built a replacement for the 80%.
The Stack
• Claude 3.5 Sonnet — drafts the risk narrative and synthesizes financials into prose
• Python — orchestration, data wrangling, API calls (120 lines, no frameworks)
• OpenSanctions API — real-time sanctions and PEP screening against 240+ global lists
• WeasyPrint — renders Jinja2 HTML templates to bank-grade PDF output
• n8n — webhook trigger so the analyst just drops a JSON payload and the memo arrives in her inbox
How the 120 Lines Actually Work
The input is a JSON blob: company name, EIN, 3 years of financials, loan amount requested, purpose. The script hits OpenSanctions first — if anything flags, the whole pipeline stops and sends an alert. No memo gets generated on a flagged entity, full stop. That was a conscious design choice, not an afterthought.
Then the financials go through a ratio calculation function (leverage, DSCR, current ratio, quick ratio — the standard five). Those ratios, plus the company description pulled from a SEC EDGAR lookup, get packed into a Claude prompt. I gave Claude a system prompt built from three anonymized memos my friend provided as style guides. The output is the risk narrative section — typically 350-500 words — with a preliminary recommendation.
WeasyPrint takes a Jinja2 HTML template, injects all the sections, and renders a PDF that matches the bank's existing memo format. The n8n webhook wires it all together: analyst posts to the endpoint, gets an email with the PDF attached in under a minute.
Where It Almost Went Wrong
The sanctions check nearly became a liability instead of a feature. OpenSanctions uses fuzzy name matching, which means "Global Trade Partners LLC" flagged against a similarly named entity on an OFAC list. I had not built a confidence-threshold filter. The first test run would have blocked a legitimate borrower.
Fix: I added a minimum match-score threshold (0.92) and a human-review queue for anything between 0.85 and 0.92. Anything below 0.85 passes automatically. Anything above 0.92 blocks. The middle band gets a Slack message to the compliance officer. That three-tier approach is now the thing I'm most proud of in the whole build.
The other near-miss: Claude occasionally hallucinated a ratio if a financial field was missing from the input. I added input validation that rejects any payload with fewer than 8 of the 12 expected financial fields, with a clear error message telling the analyst exactly which fields are missing. Took 20 minutes to add and saved what would have been an embarrassing production bug.
The Metric That Mattered
After two weeks of real use with three analysts, average memo completion time dropped from 4.2 hours to 34 minutes. The analysts still review every output — they're not rubber-stamping it — but the review is now the job, not the data entry. That's the shift. One analyst told me the tool gave her back roughly half her week. The other said she used the extra time to actually call borrower references, which she'd been skipping because there was never time.
Cost to run: roughly $0.12 per memo in API fees (Claude + OpenSanctions). Previous all-in analyst time cost per memo, at a blended $85/hr rate: about $357. The math is not subtle.
Try This
1. Collect 3-5 existing memos from your team and strip out identifying info. These become your Claude style-guide examples in the system prompt — don't skip this step, the output quality difference is dramatic.
2. Set up OpenSanctions with a free API key at opensanctions.org and test your fuzzy-match threshold before you write a single line of orchestration code. Know your false-positive rate before you build around it.
3. Build the PDF template first in plain HTML/CSS, then wire WeasyPrint to it. Getting the formatting right is the fiddliest part — front-load it so you're not debugging layout at midnight.
4. Add input validation before the LLM call, not after. Every missing or malformed field that reaches Claude is a hallucination waiting to happen.
5. Wrap it in an n8n webhook and give analysts a dead-simple interface — a JSON form or even a Google Form that outputs JSON. The last-mile UX determines whether anyone actually uses it.
DIAGRAM_HINT: architecture diagram showing data flow from analyst JSON input → OpenSanctions sanctions check → SEC EDGAR lookup → Claude 3.5 Sonnet risk narrative → Jinja2/WeasyPrint PDF renderer → n8n email delivery

Figure 1. architecture diagram showing data flow from analyst JSON input → OpenSanctions sanctions check → SEC EDGAR lookup → Claude 3.5 Sonnet risk narrative → Jinja2/WeasyPrint PDF renderer → n8n email del…


Comments (0)
Join the conversation!