Part 1: Building a Credit Intelligence Platform
This is the first post in my series documenting the complete build of a credit intelligence platform. Over the next 8 to 10 months, I'll be combining retrieval-augmented generation (RAG), Model Context Protocol (MCP), and multi-agent orchestration to create an AI system that can draft credit memos, analyze loan portfolios, and surface institutional knowledge — basically, a credit intelligence system!
Future posts will dive into RAG implementation, agentic workflows, and production deployment. But! None of that matters if I leak my API keys on day one.
With that, let's start at the foundation. Before we write any code and build our AWESOME credit intelligence system (because we are, in fact, awesome), I'm starting with the least sexy but most critical component… KEYS. Keeping our API keys safe, secure and private.
Why This Actually Matters
In credit risk, the focus is always on financial exposure and loss — primarily on identifying and mitigating that exposure and loss. API keys are no different: financial exposure (usage charges can rack up quickly) and operational risk (unauthorized access to your systems).
The reality of building AI applications is that you're juggling multiple API keys — Claude for reasoning, financial data APIs for real-time information, vector databases for RAG, and deployment platforms like Railway. One leaked key and you're facing unexpected bills, rate limit exhaustion, or worse. It may come natural to others, but a .env file makes me nervous.
I mean, would you leave $$ sitting on your desk? Even $5 or $10? I hope not! So why would you hardcode an API key that can get hijacked and rack up $$ usage? The answer: Maybe you would (How dare you!), but I wouldn't.
The Wrong Ways (We've All Done This — right?)
Let me show you the mistakes I could imagine making:
#🪦NEVER DO THIS - Hardcoded in script
from anthropic import Anthropic
client = Anthropic(api_key="sk-ant-api03-xxxxxxxxxxxxx")Why it's bad: Anyone who sees your code sees your key. Can't rotate keys without changing code everywhere. If you share this script with a colleague, you've just shared your API access.
#🪦NEVER DO THIS - Committed to git
#config.py
CLAUDE_API_KEY = "sk-ant-api03-xxxxxxxxxxxxx"
FINANCIAL_API_KEY = "abc123xyz"Why it's bad: BRO, Git is forever. Even if you delete this file later, it lives in your commit history indefinitely. GitHub automatically scans for API keys and will revoke them, but by then your key has been exposed.
#🪦NEVER DO THIS - In a Jupyter notebook
client = Anthropic(api_key="sk-ant-api03-xxxxxxxxxxxxx")
#Run some AWESOME analysis or something…😎Why it's bad: Notebooks are easy to accidentally share, publish, or export. I've seen people share notebooks with colleagues for "quick review" and inadvertently share API keys. It happens more than you'd think.
My Near-Miss Story
I initially started with the hardcoded approach in a jupyter notebook because it was "just a test." I told myself I'd fix it later once I got the basic API call working. Makes sense, right? But tests become prototypes, prototypes become production code, and suddenly your "temporary" insecure code is handling real credit data because, I don't know, you forgot?
What stopped me was a simple habit: running git diff before committing. That one habit caught my hardcoded key before it entered git history. But I shouldn't rely on catching mistakes — I should prevent them (and you can too!).
The Right Way: Three Approaches
Now that we know what NOT to do, let's look at a better way to handle these keys. I'm going to show you three approaches, from simplest to most robust. Where you land depends on your project stage, skillset and psychological profile.
Approach 1: Environment Variables with .env Files (Local Development)
When to use: Solo projects, local development, learning phase
This is where I started when writing the code for this series. It's simple, works immediately, and keeps keys out of my code.
Setup:
Create a .env file in your project root:
#In your .env file(🪦NEVER commit this file)
ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxxxxxx
ANTHROPIC_API_KEY=your_claude_api_key_here
FINANCIAL_DATA_API_KEY=your_financial_api_key_here
DATABASE_URL=your_database_url_hereTHEN, add .env to your .gitignore BEFORE creating the actual file:
#This is your .gitignore file
.env #Notice the .env file. Nice. 😎
.env.local
.env.*.local
# Python
__pycache__/
*.pyc
.venv/
# OS
.DS_Store
Thumbs.dbInstall python-dotenv:
pip install python-dotenvUse it in your code:
import os
from dotenv import load_dotenv
from anthropic import Anthropic
# Load environment variables from .env file
load_dotenv()
# Access API key from environment
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
# Now use the client
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=100,
messages=[{"role": "user", "content": "Hello!"}]
)
print(response.content[0].text)Pros and Cons:
😎 Simple to set up
😎 Keeps keys out of code
😎 Easy to understand
😎 Works immediately
💀 Manual setup on each machine
💀 Easy to forget .gitignore step
💀 .env file lives in project directory
My learning moment:
This approach worked great on my main MacBook Air. Then I switched to my Windows Surface via Remote Desktop and spent way too many minutes debugging why my code "suddenly stopped working." I mean, who doesn't love a good cryptogram: anthropic.APIConnectionError.
Turns out, I forgot to create the .env file on the Windows machine. The code was looking for ANTHROPIC_API_KEY in the environment, finding nothing, and failing silently-ish. Lesson learned: .env files need to be set up on every machine where you run the code. Or…
Approach 2: System Environment Variables (More Robust)
When to use: Multiple projects on the same machine, shared environments, when you're tired of creating, managing, and hiding .env file.
After the Windows desktop incident, I upgraded to system environment variables. Now my API keys are configured once per machine, available to all projects. I can build and build!
On Mac/Linux:
Add to your shell configuration file (~/.zshrc for Zsh or ~/.bash_profile for Bash):
export ANTHROPIC_API_KEY="sk-ant-api03-xxxxxxxxxxxxx"
export FINANCIAL_DATA_API_KEY="your_key_here"Reload your shell and test:
source ~/.zshrcOn Windows (PowerShell):
# Set environment variable that persists across sessions
[System.Environment]::SetEnvironmentVariable(
'ANTHROPIC_API_KEY',
'sk-ant-api03-xxxxxxxxxxxxx',
'User'
)Or use the GUI: System Properties → Advanced → Environment Variables → New User Variable
Your Python code doesn't change:
import os
from anthropic import Anthropic
# No more load_dotenv() needed - it's in the system environment. Done!
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY")) #Like I said, Done!Pros and Cons:
😎 Set once, works everywhere on that machine
😎 No .env file to manage per project
😎 More secure (not stored in project directory)
😎 Available to all terminal sessions
💀 Less portable when sharing code
💀 Requires OS-specific knowledge
💀 Can forget which machine has which keys
My experience:
After switching to system environment variables, I haven't had a single "why isn't this working?" moment due to missing keys. The trade-off: when I eventually share this code or write setup instructions, I need to clearly document: "Set ANTHROPIC_API_KEY in your environment before running." So, I'm telling you now… Set ANTHROPIC_API_KEY in your environment before running.
For this blog series, I'm sticking with system environment variables on both my Mac and Windows machines. It's one less thing to think about as we build across this project and any others.
Approach 3: Secrets Management for Production (Future-Proofing)
When to use: Deployed applications, team projects, production systems
I'm not deploying to production yet (that's Post #10-ish?), but I'm designing for it now. When I deploy this credit intelligence platform to Railway later in this series, I don't want to rewrite my key management, so you just store the key in their environment variables.
The good news: If I'm using os.environ.get() in my code, I'm already production-ready. I just need to set the environment variables in my deployment platform instead of on my local machine.
For Railway (my planned deployment platform):
# Via Railway CLI
railway variables set ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxxxxxx
# Or via Railway dashboard
# Settings → Variables → Add VariableOther options to consider:
- AWS Secrets Manager: Enterprise-grade, audit logs, automatic rotation
- Google Cloud Secret Manager: Similar to AWS, good for GCP deployments
- Azure Key Vault: Microsoft's solution
- Environment variables in platform: Heroku Config Vars, Vercel Environment Variables, etc.
My Python code stays exactly the same:
import os
from anthropic import Anthropic
# Works locally AND in production - no changes needed
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))Pros and Cons:
😎 Built for production scale
😎 Audit logs and access controls
😎 Easy key rotation without code changes
😎Team collaboration features
😎 Separation of code and secrets
💀 More complex initial setup
💀 May cost money (AWS Secrets Manager, etc.)
💀 Platform-specific learning curve
Why I'm thinking about this now:
Even though we're not ready to deploy yet - when I am ready, I don't want to refactor how I handle secrets. Writing os.environ.get() from day one means my code will work-ish when I move from local development to Railway deployment. Same code, different environment.
The key principle:
Boring, but true -> Trust, but verify. I always run git status before adding any new files to make sure my secrets aren't about to be committed.
Testing Your Setup
Here's a validation script I use to test that everything is configured correctly without exposing the actual key values:
# test_api_keys.py
"""
Validation script to verify API keys are loaded correctly.
Run this before starting development to catch configuration issues early.
"""
import os
from anthropic import Anthropic
def test_api_key():
"""Verify ANTHROPIC_API_KEY is loaded and functional."""
print("🚀 Testing API key configuration...\n")
# Check if key exists in environment
api_key = os.environ.get("ANTHROPIC_API_KEY")
if not api_key:
print("😞 ANTHROPIC_API_KEY not found in environment")
print("\n🩻 Troubleshooting:")
print("1. Check if key is set: echo $ANTHROPIC_API_KEY")
print("2. If using .env: verify .env file exists and load_dotenv() is called")
print("3. If using system variables: verify export command in ~/.zshrc")
return False
# Validate key format (without exposing the key)
if api_key.startswith("sk-ant-"):
print(f"😙 API key found (starts with 'sk-ant-', length: {len(api_key)})")
else:
print("🤔 API key format unexpected - double check it's correct")
print(f"🤔 Expected to start with 'sk-ant-', got: {api_key[:10]}...")
return False
# Test actual API connection
print("\n🚀 Testing API connection...")
try:
client = Anthropic(api_key=api_key)
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=50,
messages=[{"role": "user", "content": "Say 'API key works' if you receive this."}]
)
print("😙 API connection successful")
print(f"😙 Response received: {response.content[0].text}")
return True
except Exception as e:
print(f"💀 API call failed: {str(e)}")
print("\n🩻 Troubleshooting:")
print("1. Verify key is valid (check Anthropic console)")
print("2. Check account has available credits")
print("3. Verify network connection")
return False
if __name__ == "__main__":
success = test_api_key()
if success:
print("\n😙 All checks passed - ready to build!")
else:
print("\n💀 Configuration issues detected - fix before continuing")Expected output when everything works:
🚀 Testing API key configuration…
😙 API key found (starts with 'sk-ant-', length: 108)
🚀 Testing API connection…
😙 API connection successful
😙 Response received: API key works
😙 All checks passed - ready to build!What this script does:
- Checks if the key exists in the environment (catches missing .env or system variables. Just a general 💀.)
- Validates key format without printing the actual key (security)
- Makes a real API call to verify the key works (catches expired/invalid keys)
- Provides specific troubleshooting steps if anything fails
I run this script at the start of every development session, especially when switching machines or after setting up a new environment.
Lessons Learned & Best Practices
After setting this up across multiple machines and projects, here are my key takeaways:
1. Start Secure From Day One
"I'll fix the security later" never works. Remember Git is life, but Git is forever. It's far easier to build security from the beginning than pile it on after you've built 5,000 lines of code. The easiest path is to hardcode keys for quick testing — I resisted and you can too!
The rule: Before writing any API call, set up proper key management. It takes 10 minutes upfront and saves hours of refactoring later.
2. Use .env.example for Documentation
Even if you're working solo, create a .env.example file with placeholder values. Future you (or a collaborator) will thank you. It documents exactly what environment variables your project needs without exposing actual secrets.
3. Never Trust, Always Verify
Before adding any new file to git, run git status to verify your .gitignore is working. Before committing, run git diff to see exactly what's being committed. These two habits have saved me multiple times.
My pre-commit checklist:
git status # What's being tracked?
git diff # What are the actual changes?
git add . # Stage changes
git status # Verify nothing sensitive staged
git commit -m "…❤️…"4. Same Code, Different Environments
The pattern os.environ.get("KEY_NAME") is your friend. Write it once, and your code works locally, in CI/CD, and in production. The only thing that changes is where the environment variable is set — the code stays identical.
This is why I'm using environment variables from Post #1. When I get to Post #10 and deploy to Railway, I won't need to refactor anything — We're set!
5. Test Your Setup Immediately
Don't wait until you're three hours into coding to discover your API key isn't loading. Run a validation script first! I repeat — Run a validation script! I just gave you one. The 30 seconds it takes to verify your setup saves time debugging ominous, yet cryptic error messages (How exciting!).
What Surprised Me
I expected setting up API key management to be tedious and annoying. It wasn't. Once configured, it's completely invisible — Like a ghost who does your dishes. I never think about it anymore and my metaphorical house is clean, which means it's working for me.
The biggest surprise was how much cleaner my code became. No more API keys cluttering my scripts. No more "TODO: move this to config" comments. Just clean, portable code that works everywhere.
What I'd Do Differently
If I could start over, I'd skip the .env file approach entirely and go straight to system environment variables. The .env approach works, but having separate files per project became annoying when I started working on multiple AI projects simultaneously. System environment variables solved that problem.
For this blog series, I'm using system environment variables on both my Mac and Windows machines. When I deploy to Railway in Post #10, I'll use Railway's environment variables (Just copy + paste, I promise) — but my code won't change at all.
What's Next: Making Our First API Call
Now that I can securely access the Claude API, Post #2 will cover making the first API call. This sets us up to build a structured prompt for credit analysis.
We'll create a simple credit risk assessment that takes borrower information and returns a structured evaluation. That means, I'll cover:
- Basic message structure and parameters
- Getting consistent, structured output from Claude
- Handling responses and errors
- Cost tracking and token management
- My first real credit risk prompt
Basic, building the context and the guardrails.
Let's Build Together
With that, one last note: I'm documenting this entire journey as I learn. I'm not an AI expert — I'm a credit risk professional learning to build AI systems that solve real problems in my domain. I love me some ML, but my goal is to take it further with AI agents.
If you're following along, set up your API key management this week. Get it working, test it, commit your .gitignore to git. Then you'll be ready for Post #2 when we make our first API call.
Let's make it happen. 💰