Every new lender looked like a new project
By mid-2026 I had worked on this platform for more than two years, so I knew where brokers lost time long before this project started. Brokers use the platform to prepare a client's loan and send it to a lender. The first integration was a personal loan flow with our partner lender. Then a second lender signed on. It had no interface for brokers at all: it would only receive data through its API and manage everything on its own side.
Building a second, separate submission flow would have worked once. It would also have meant a third build for the third lender, and brokers learning a different flow for each one. The real question was what stays the same across lenders, and what has to change.
Designing the first flow from scratch
The personal loan flow went through nine iterations before it shipped. These are the turning points that later made it reusable.
A story map from pre-approval to quote, client confirmation and the broker's final check.
“Action needed” and “Earlier submissions” instead of system states, so brokers see their next step first.
Action on the left, timeline on the right, on every waiting state.
Conditions advance on their own to identity checks, and processing shows progress instead of a frozen screen.
I ran the project with the partner lender's team and its lead. Together we defined both directions of the integration: what application data goes from our platform to the lender, and what comes back, the lender's status and any action the broker needs to take. I set the phases and milestones and wrote the requirements each one shipped against.
Action left, timeline right
Loan applications spend most of their life waiting: for the client, the lender or a document. I gave every waiting state the same layout. The left side says what the broker can do now. The right side shows where the application is and what happens next.
Because the layout describes waiting in general, not one lender's steps, it carried straight over to the second lender.
I built the flow as a 15-screen clickable HTML prototype, so product, engineering and QA could agree on one version before any build.
- Pre-approval received
- Quote sent to client
- Awaiting client confirmation
- Identity check
- Submitted to lender
A second lender, and two ways to add it
For the second lender, the lender's steps became a five-step form built from existing components:
Adding a lender now means adding one option to “Select lender” and mapping its fields. Brokers don't learn a new flow.
Two statuses, not one
The decision I'd defend hardest is a data model one that shows up in the interface. An application has its own state in our product: drafted, documents in, submitted. A lender has a separate state on its side: under review, awaiting information, approved, declined.
Merging them into one status column looks simpler and breaks the moment one application goes to two lenders. So the Loans list keeps Application status and Lender status as separate columns, with a Lender column beside them.
| Client | Lender | Application status | Lender status |
|---|---|---|---|
| J. Sample | Partner lender | Submitted | Approved |
| A. Example | Second lender | Submitted | Awaiting information |
| R. Demo | Second lender | Draft | — |
Lender status uses one shared vocabulary that each lender's own states map onto:
Agree the contract before anyone designs a screen
The second lender's API was still being finalised. If engineers built the form and mapping against a guessed payload, every change on the lender's side would mean rework on ours, twice. So I broke the work into four tickets and put a gate in front of the UI.
This is the gate ticket as I wrote it, with names removed.
Context
We're connecting the Loans flow to a lender that only accepts data by API. The form, the mapping and status tracking will all be built against this payload. A change after build means rework in all three.
Acceptance criteria
- Create and submit payloads are agreed with the lender in writing, field by field, against our field dictionary.
- Every required lender field maps to data we already collect. Gaps are listed, not built, in Phase 1.
- Sample requests pass against the lender's test endpoint for create, submit and status.
- The lender's status values and their meaning are agreed and mapped to our lender status list.
- Document handling is agreed: sent as attachments, with allowed file types and sizes.
Out of scope
- New data fields in the application form
- Sending one application to several lenders
Done when
My manager signs off the contract, and the two UI stories are unblocked.
The second lender only needed some of our fields. We sent our standard payload anyway: borrower details, loan details and the adviser's contact information. The lender takes what it needs, and the next lender gets the same payload, so its integration starts from mapping, not from a new build.
The lender's first request was a short email listing the fields it wanted. I checked each one against our data model, decided what we could send and what was out of scope, and wrote it up as a field dictionary. Engineering built the API from that document, adjusting the technical structure where they needed to, but the scope and field meanings stayed the ones I had set. I had done the same for personal loans earlier: I wrote the base payload, and engineering built on it.
That dictionary became the master: every lender field, what it means, and where our data for it comes from. It turns “can we support this lender?” into a lookup instead of a meeting.
Scoping Phase 1 to about a week
The fastest way to learn whether the pattern held was to ship a thin version. Phase 1 used only data the platform already collects, added no new fields, and sent documents to the lender as attachments.
That made the first submission less complete than it could be. It also meant the work was mapping and reuse, not new design and new database fields, so it fitted in about a week instead of a quarter.
Decisions I'd defend, and what they cost
One Loans module instead of a lender-specific flow
Brokers learn one flow; a new lender is one more option.
Each lender's form has to fit a shared structure, even when its fields are unusual.
Application status and lender status as separate fields
Ready for one application going to several lenders.
One more column in the list, and more to explain at first.
Contract gate before UI work
Engineers never build against a payload that might change.
UI work waits on the lender's timeline, not ours.
A standard payload, not each lender's minimum
One payload every lender receives, so the next integration is mapping only.
More data leaves our system than one lender strictly needs, so the standard set stays limited to what lenders assess an application on.
Phase 1 with existing data only
Proves the pattern in about a week.
A thinner first submission; richer data waits for Phase 2.
Dropping my own first idea
The applications-list option mixed two meanings of status.
Sketches and a review cycle I'd already spent.
Outcome
What I'd do next
- Pass brokers' uploaded documents, such as payslips, through to the lender, so lenders get the full picture on the first submission.
- Let one application go to several lenders and compare their responses side by side, which the two-status model already supports.
- Track time from first draft to submission per lender, to see where brokers wait and why.
What I learned: the second integration is where a product decides whether it's building features or a platform. Most of the leverage came from deciding what to keep the same, not from what I added.