Inspiration
A real invoice can still send money to the wrong account. An attacker only needs to convince someone that a vendor has changed banks.
For a small accounts-payable team, checking that request often means making another phone call while a payment deadline approaches. We wanted to make verification a required step in the payment process, even when someone trusts the email or enters the new bank details manually.
What it does
Landed holds payments to a new bank account until that account is verified for the specific vendor.
It sends a small, randomized test deposit and asks the vendor to confirm the amount through a trusted channel: their phone number established at onboarding or their authenticated vendor portal. Replying to the bank-change email does not count as verification.
The payment function checks the destination before sending money. If it is unverified, disputed, or an outdated account version, payment is refused.
After payment, Landed tracks confirmation that the money arrived. If confirmation fails, it prepares a recovery package with a bank-call script, reporting drafts, an evidence checklist, and the case timeline. A person still approves payments and handles the response.
How we built it
We built the frontend with Next.js and React, and used Convex for the database, server functions, scheduled tasks, and real-time updates.
Claude reads bank-change requests from emails and attachments and helps draft recovery paperwork. It cannot verify an account or send a payment. Those actions are controlled by server-side rules.
We added versioned bank accounts, encrypted account data, and an audit trail so each decision can be traced to the account, vendor, and evidence involved. We used Vitest for automated tests and a Python evaluation harness to run complete scenarios.
The prototype uses simulated settlement timing and vendor responses. We also tested transfers against Capital One’s Nessie mock bank. The phone-call integration is implemented, but we have not placed a live call.
Challenges we ran into
The hardest part was making verification specific enough. A correct answer should only verify the exact vendor, account version, and case it belongs to. It should not carry over to a later bank change.
We also had to separate receiving information from trusting it. An email can open a case, but it cannot confirm its own bank details. A convincing document or confident AI response cannot replace that check.
Testing the full workflow was another challenge. Settlement windows, unanswered calls, retries, and missed confirmation deadlines take time. We built a demo clock so we could exercise those paths without waiting days.
Accomplishments we’re proud of
The clearest demonstration is also the simplest: turn the AI off, manually enter an unverified destination, and click Pay. The server still refuses.
Our updated project passes 110 automated tests and 40 scripted runs across 28 scenarios, including cases with the extractor disabled. Those runs produced zero false releases. These are results from controlled tests, not a claim that we have solved real-world payment fraud.
We also completed both sides of the workflow: legitimate changes can proceed through verification and payment, while suspected fraud leads to a reviewable response package.
What we learned
The most important control belongs where money moves. Detecting a suspicious request helps, but a warning is not enough if someone can still pay the unverified account.
We also learned to test what happens when the AI misses something. The payment rules need to hold when extraction fails, when a person makes a mistake, and when the request looks legitimate.
What’s next for Landed
Our next steps are to test the voice integration with an approved test number, connect a payment provider beyond the mock bank, and integrate the hold into an existing accounts-payable workflow.
We also want to put Landed in front of AP teams and learn where it adds useful protection and where it creates unnecessary work.
Built With
- anthropic-claude
- capital-one-nessie
- convex
- next.js
- python
- react
- shadcn/ui
- tailwind-css
- typescript
Log in or sign up for Devpost to join the conversation.