Inspiration
Most fintech for underserved communities starts from the idea that people struggle with money because they don't understand it. The research says something else: scarcity uses up mental bandwidth. When you live paycheck to paycheck, every decision costs more attention. Another budgeting app with pie charts of money you don't have doesn't help. It's one more source of stress.
And the help that does exist is hard to use. Utility assistance, rent relief, hardship deferrals and local grants are real, but they're scattered across hundreds of county, state and nonprofit websites. Each one has its own form, and people need help most exactly when they have the least time and energy to look for it.
We wanted to build a guardrail rather than a dashboard: something that does the math, finds the help and writes the paperwork. That's Equa. Have a problem? Use Equa.
What it does
Equa connects to your bank account and turns raw transactions into one number and a few clear next steps. It never shows charts of money you don't have.
- Safe to Spend: One ring tells you how much you can actually spend: your checking balance minus every bill and loan payment due in the next month. The ring turns green, amber or red with a plain-language cue ("Nice! Your bills are covered" or "Things are tight, so spend carefully"). Tap it to see the math, then expand the list to see every bill due this cycle.
- Money check-up: Equa grades your last 8 weeks against the 50/30/20 rule (needs, wants and savings) and the 28/36 rule (housing and debt) as simple pass/fail rings, without a spreadsheet.
- Relief programs near you: Equa finds real local, state and federal assistance programs for your ZIP code. Gemini then picks the ones you most likely qualify for and explains why in one line. It can only choose from programs that are actually in our database, so it can't make up a grant.
- Application progress cards: Each match becomes a card with a checked "Apply" link and progress tracking, so nothing slips through the cracks.
- "Have Equa fill it out": On an application form, one tap has Equa read your profile and bank data and fill in every field. The answers type themselves in live, including a short, honest explanation of why you need help. Equa never makes up an answer: anything it doesn't know stays blank and it tells you. You review it and press Submit.
- High-APR debt: Equa finds your most expensive loan and shows what it costs you each month in interest. In one click, Gemini writes a rate-reduction or deferment request to your lender.
- My Toyota: Built for the Toyota Financial Services prompt. For your auto loan, Equa drafts a temporary hardship deferral request and suggests moving your due date to payday. If your car payment is too large a share of your income, it suggests SmartPath. Every card links to TFS's real deferral, due-date and support pages.
- Plan: An ordered to-do list built from your real numbers: free up cash first, then lower what your debt costs, then apply for the rest of your matches.
- Equa chat: A warm, no-judgment assistant that answers using your actual bills, loans and check-up results, not generic advice.
How we built it
Frontend: Next.js (App Router), TypeScript, Tailwind CSS, shadcn/ui and GSAP, designed mobile first. Server actions call a typed client generated from the backend's OpenAPI schema. A file watcher regenerates the client whenever a backend route changes, so the frontend and backend never drift apart.
Backend: Python 3.14 + FastAPI, async SQLAlchemy on Postgres, Alembic migrations, and fastapi-users for auth. 105 backend tests run against a real Postgres test database.
Capital One Nessie API (our bank): "Connect to bank" creates a Nessie customer and checking account, then seeds about 60 days of realistic history:
- paychecks
- rent
- utilities, phone and internet
- a Toyota auto loan
- everyday purchases at H-E-B, Shell, Target and more
Each account gets a different profile: weekly or biweekly pay, its own landlord and providers, different loan sizes, spending habits and starting balance. That way every demo account tells a different story. Safe to Spend, the check-up, APR impact, autofill and chat all read live from Nessie, and every call retries on timeouts, 429s and 5xx errors.
Program discovery pipeline: A background worker builds our database of relief programs:
- It loads federal programs from GSA's public Assistance Listings and maps ZIP codes to cities, counties and states using Census geography data.
- It uses SerpApi to search for local programs, then fetches the pages with an SSRF-safe, rate-limited fetcher.
- Gemini extracts structured program records from each page (eligibility, benefit and apply link). These are validated, deduplicated and saved to the database.
- The job queue uses claims, heartbeats, retries and a SerpApi budget guard, so it can run unattended.
Google Gemini (our AI layer):
- Program matching uses a forced function call that can only return program IDs that exist in our database. We drop any unknown ID it returns.
- Lender and deferral letters and form autofill use JSON mode with an "unknown means null" rule, so Equa leaves a field blank rather than guessing.
- Chat is grounded in the user's real financial data.
Snowflake (analytics warehouse): A scheduled, one-way sync copies Postgres into Snowflake using key-pair auth, staged loads and deduplicating MERGEs, and alerts when data goes stale. Views on top report utility burden and program coverage in aggregate. No individual user's financial data ever leaves Postgres.
Deploy: The FastAPI backend, discovery worker and Postgres run in Docker on a Vultr VM behind Caddy (automatic HTTPS at api.equalityfin.tech). The frontend is on Vercel at equalityfin.tech.
Tooling: Claude Code helped us move fast during the 24-hour sprint.
Challenges we ran into
- Stopping the AI from making things up. An LLM will happily invent a grant that doesn't exist, which is the worst possible outcome for someone in crisis. We forced program matching through a tool call limited to known program IDs, dropped anything else, checked every apply link, and made every drafting prompt use "if you don't know it, leave it blank."
- Nessie loans have no interest rate field. We estimate each loan's APR from its credit score and loan type, using published averages. The lender letters never state that guess as fact: they leave a placeholder for the user to fill in their real APR from their statement.
- A browser agent was too slow and fragile for a live demo. Our first idea for autofill was a full browser agent (Browser Use + Chromium) that would "see" the form. With an hour left, it conflicted with our FastAPI dependencies and needed a 170 MB browser in our Docker image. We switched to a single Gemini call that returns every answer as JSON, which the UI types in live. It's faster, more reliable and easier to explain.
- Gemini spent too long thinking. The autofill call kept hitting our 30-second timeout because the model's thinking tokens took longer than the response. Setting a low thinking level for this structured task brought it down to about 7 seconds.
- Every demo account looked the same. All test users originally got the same rent, bills and loan. We rebuilt the seeder so each Nessie customer gets a unique but believable financial profile.
- Getting the toolchain working. Python 3.14 and new Node versions broke several dependencies until we upgraded them. Vercel rejected Node 26, so we pinned Node 24 everywhere.
- Scraping the web responsibly. We needed SSRF protection, per-domain rate limits and a search-API budget, with failed jobs retrying rather than silently disappearing.
- Tone. AI often sounds clinical, or even judgmental, about money. We rewrote prompts and UI copy until Equa sounded like a friend who's good with money, not a bank.
Accomplishments that we're proud of
- A complete loop: connect a bank → see what's safe to spend → get matched to real programs → have Equa write the letter or fill in the application → track it to done.
- A real discovery pipeline that finds actual local, state and federal programs by ZIP code, not a hard-coded list of five grants.
- AI you can trust: constrained tool calls, validated output, no invented facts, and the human always makes the final decision.
- Several sponsor technologies working as one product: Capital One Nessie, Snowflake, Google Gemini and the Toyota Financial Services prompt each do a real job in the app.
- A UI that respects limited bandwidth: one number, a few next steps, plain language, and mobile first.
What we learned
- Guardrails matter more than prompts. Making LLM output safe for people in financial distress took constrained tool calls, schema validation and explicit "unknown means null" rules, not just better wording.
- Keep the warehouse away from the app. A one-way sync means Snowflake analytics can never slow down or break the product.
- The research translates into product rules. Scarcity research told us what to cut: no charts of money users don't have, no jargon, and never more than one thing to do next.
- A clear demo beats an impressive architecture. Cutting the browser agent for a simpler approach that shows the same idea was one of our best calls.
What's next for Equa - Equality Finances
- Real bank connections through Plaid instead of Nessie's mock data.
- Autofill for real applications: map real program forms (LIHEAP, rental assistance and utility hardship funds) and bring back the browser agent for portals that don't have an API.
- Submission and renewal tracking: reminders when benefits need recertifying, and status updates pulled back into the progress cards.
- Predicting missed bills: use pay timing and spending patterns to warn users before a bill bounces, and point them to help while there's still time.
- A hardship platform for lenders and utilities: generalize the My Toyota flow so any lender or utility can offer deferrals and payment plans before a customer defaults, not after.
- Accessibility and language: a Spanish version first, plus voice input for users who find forms hardest.
Built With
- fastapi
- python
- shadcn
- tailwindcss
- typescript
- vercel
- vultur
Log in or sign up for Devpost to join the conversation.