Skip to main content

Direct Lender Integration — Design Spec

Status: Design-first, pre-implementation. No code or schema exists yet for this system. Source: Compiled from the #direct-lender-integration Slack channel discussion and agent memory (design artifacts shared 2026-06-30 through 2026-07-06). This document consolidates that discussion into a single reference; it does not introduce new decisions beyond what was discussed in-channel.

1. Overview

Per Kevin Hill (driving this project), the direct-lender integration is not just “add a few lenders” — it is a full new system within Funding Machine. It covers, per lender:
  • Operator registration / onboarding with the lender
  • Deal intake and document collection
  • Submission to the lender via one of three patterns (API / portal / email)
  • Status tracking through a submission pipeline
  • Audit logging
This is a distinct workflow from the existing 7 Figures Funding processing-team flow, where deals are submitted to the internal processing team rather than directly to a lender. Kevin’s explicit direction: design this well, in the open, in-channel, before implementing, while production continues to ship smaller, non-conflicting updates in parallel.

Ground rule (hard scope boundary)

Per Kevin (2026-06-30), the direct-lender system must be fully additive and must not touch:
  • The existing term-loan path (the Engine/MoneyLion integration, v2)
  • Card/credit underwriting
  • The processing-team flow, in any way
It is its own module, behind its own feature flag, and only impacts Revenue Based funding (i.e., new direct-lender products), not the existing term-loan offer wall or processing pipeline. The Engine integration (convex/termLoanSubmissions.ts) is referenced only as a code-pattern template for building a typed lender-API client — it is never modified as part of this work.

2. Governance

The repo enforces a spec-gate via VISION.md + AGENTS.md (required reading before any PR):
  • VISION.md marks lender APIs, Convex schema changes, billing, and auth as out-of-scope for autonomous changes, requiring explicit approval (named approver: Brock).
  • AGENTS.md bans adding a feature-flag gate around the existing Engine term-loan path specifically (v2 is the only path; the v1 partner-link path was removed May 2026). That ban does not extend to flags on new systems like this one.
The entire direct-lender project sits on these approval-gated surfaces (it needs a new lender API integration, new Convex tables, and touches auth/actor patterns for the GHL iframe app). Per VISION.md’s own rule, human-directed work counts as the required approval for the specific task it covers — i.e., a task explicitly requested by a person (as opposed to an autonomous agent decision) satisfies the gate for that task only. This document and this PR are human-directed (Kevin Hill) and satisfy the gate for the docs-only work done so far; it is not a blanket or standing approval for future work. Each subsequent gated change (a new lender API integration, a new Convex table, an auth change) still needs its own human-delegated task before an autonomous run may proceed — this document only records that the gate exists and how it was satisfied for the work described here. Working agreement:
  • Keep PRs small and incremental, merged continuously to main rather than one large branch.
  • Every PR that touches a gated surface (lender API code, convex/schema.ts, auth/actor plumbing) must call that out explicitly in the PR summary so reviewers can apply the extra scrutiny the spec-gate implies.

3. Architecture Plan

Agreed approach (proposed 2026-06-30): build the direct-lender system as an additive, dark-launched module, merged in small PRs rather than a long-lived feature branch.

Feature flag

  • Start with an env-level flag: NEXT_PUBLIC_DIRECT_LENDER_ENABLED.
  • Graduate to per-location rollout via locationSettings.featureFlags once ready for selective operator enablement.

Module boundary (proposed)

  • UI: app/(main)/direct-lenders/* for operators, app/admin/internal/direct-lenders/* for staff. (See Section 6 for the later placement revision toward a top-level “Lender” tab.)
  • Convex: new top-level files directLenders.ts, lenderRegistrations.ts, lenderSubmissions.ts, plus supporting helpers in convex/lib/.
  • Follows existing conventions: flat per-domain files in convex/, pure helpers in convex/lib/, multi-tenant scoping by GHL locationId (not orgId), indexes named by_<field> / by_<a>_<b>, new schema fields always optional for back-compat.

Three integration patterns

Each lender is assigned one submission pattern before it is built: Note: the newer design spec (Section 4) separates a distinct connection method axis (how an operator’s affiliate account gets linked — api / credentials / referral_link / iso_account) from this submission axis (how a deal gets sent — api / portal / email). Both axes should be tracked; they are not the same thing.

4. Data Model

No first-class lenders table exists in the codebase today. “Lender” currently only appears as: free-text metadata on fundingPlans (lenderName, lenderContact, etc.); static code config in lib/config/bureau-pools.ts / convex/lib/lenderMatching.ts (bureau pools, blacklists); and the Engine/MoneyLion term-loan integration in convex/termLoanSubmissions.ts.

Proposed new Convex tables (all scoped by locationId)

lenders — catalog of lenders and their products/requirements:
  • slug, name, website, monogram, brandColor
  • products[] (term_loan | line_of_credit | mca | revenue_based | working_capital | equipment; plus sba as needed)
  • connectionMethod (api | credentials | referral_link | iso_account)
  • fundingRangeMin / fundingRangeMax / fundingRangeLabel
  • speedLabel, minFico, minTimeInBusinessMonths, minRevenueAmount + minRevenuePeriod, requiredMonthlyVolume
  • restrictedStates[], restrictedIndustries[]
  • about, offers[{label, value}], underwriting[{label, value}], requiredDocs[]
  • isoSteps[{order, title, desc}], submitSteps[{order, title, desc}], submitMethodLabel
  • isoContact{name, role, email, phone}
  • (V1 addition, per Robert M’s operator-flow notes) per-lender email template stored on the catalog record: subject + body + merge fields + attachment rules, rendered with deal merge fields.
lenderRegistrations (a.k.a. lenderConnections — see naming note below) — per-operator enrollment per lender:
  • One record per operator × lender, scoped by locationId
  • status (empty | pending | connected | error | ineligible)
  • defaultProduct, environment (live | sandbox)
  • credentials{clientId?, apiSecretRef?, isoAccountNumber?, referralUrl?} — secrets stored via reference, never plaintext
  • lastSyncedAt, lastSyncStatus, connectedByUserId, connectedAt
  • eligibility{eligible, reasonCode?, reasonText?}
lenderSubmissions — a deal sent to a lender (the pipeline item):
  • connectionId, lenderId, clientId, product, amount
  • stage / status (submitted | in_review | approved | declined | funded)
  • submittedAt, updatedAt, externalRef, externalStatusRaw
  • offer snapshot {indicativeAmount, estApr, decisionEta}
  • documentsSnapshot (V1: snapshot of which client documents were attached to the submission)
lenderSubmissionEvents — audit log of everything that happens to a submission (status changes, sends, replies).

Naming reconciliation

The original architecture memo (2026-06-30) proposed lenders / lenderRegistrations / lenderSubmissions / lenderSubmissionEvents. The newer, build-ready Claude Design spec (“Direct Lenders”, also 2026-06-30) independently arrived at largely the same shape but calls the per-operator enrollment table lenderConnections. These are treated as the same tablelenderRegistrationslenderConnections — with the design spec’s field-level detail (above) taken as the more complete version. The design’s pipeline stages (submitted → in_review → approved → declined → funded) map directly onto lenderSubmissions.status.

5. Eligibility Engine

The design spec introduces an eligibility engine with two levels of gating:
  1. Operator-level eligibility — determined by the operator’s state license and monthly funded volume against a given lender’s thresholds (e.g., “not available to ISOs in UT”, “requires 50k/mo,operatorisat50k/mo, operator is at 34k”). This produces the connected / ineligible states on lenderRegistrations.
  2. Client-level eligibility — the direct-lender product block only appears on a given client’s funding plan when that client matches the lender’s criteria (revenue, time-in-business, FICO).
Placement relative to existing curation: the codebase already has a curation seam at convex/lib/loanOfferCuration.ts (applyCuration() is currently an identity pass-through, with reserved config for lenderAllowList / lenderBlockList / minRecommendationScore), intended for future direct-lender curation to plug into. Default decision (per Kevin, 2026-06-30): direct-lender eligibility lives in its own module with no shared code with loanOfferCuration.ts, unless Kevin explicitly says to reuse that seam. This keeps the hard scope boundary (Section 1) intact.

6. Screens / UX

Placement decision

There were two placement proposals across the design iterations:
  • Earlier reference prototype (“Lender Integrations”, 9 seeded lenders): a top-level sidebar nav item.
  • Newer build-ready spec (“Direct Lenders”, 7 frames): Settings → Direct Lenders, no new top-nav tab; action surfaces (connecting, submitting) live inline in the client’s funding plan, next to the existing “Submit to 7 Figures Funding” button.
  • Robert M’s 2026-07-01 V1 operator-flow notes moved this again: per-lender onboarding lives under a top-level “Lender” parent tab — resolving the placement question back toward the original top-level-nav approach rather than Settings.
The funding-plan touchpoint (a direct-lender product block rendered parallel to “Submit to 7 Figures Funding,” shown only when the client qualifies) is the one placement point that stayed constant across all iterations and is the main integration point into the existing fundingPlans UI. See Section 9 (open questions) for the still-unconfirmed piece of this.

Connection lifecycle states

lenderRegistrations/lenderConnections render through five states: empty, pending, connected, error, ineligible. Design also calls for masked API keys, a reconnect action, a rotate-key action, and a sync-status indicator.

Screens identified in the design spec

  1. Direct Lenders directory, grouped Connected / Eligible / Ineligible (card layout recommended; compact-table variant considered as an alternative).
  2. Connect-a-lender modal — 2-step, fields adapt to the lender’s connectionMethod.
  3. Connected lender detail — connection-health strip + pipeline summary (5 status counts) + leads table (Kanban-style variant considered).
  4. Funding-plan direct-lender product block — the actual submission decision point in the client’s funding plan.
  5. Optional lender reference detail (carried over from the earlier “Lender Integrations” prototype: about / offers / underwriting / required docs / ISO sign-up steps / submit steps / ISO contact / submission method, plus a manual “I’m an approved ISO” toggle).
  6. Connection-state component matrix (states from above rendered as reusable UI states).

V1 operator onboarding + email-submission flow

Robert M’s 2026-07-01 notes define the concrete V1 UX (Claude-recommended defaults, pending Robert’s confirmation at time of writing):
  • Onboarding-complete identifier: the per-operator lenderRegistrations record’s status flipping to connected. One record per operator × lender, scoped by locationId. That single status flip is what surfaces the lender in the Funding tab for that operator.
  • Submission method for V1: email template, across the board — API and portal-button lenders come later. This narrows the api/portal/email submission axis to email-first for V1.
  • Email template source: recommended as per-lender catalog data on the lenders record (subject + body + merge fields + attachment rules), rendered with deal merge fields, reasoning that each lender’s required format/fields differ and the document selector needs to attach to it; may still send through GHL’s own sending infrastructure. (Open — Robert to confirm vs. using GHL’s built-in templates directly.)
  • A “review email template” action lets the operator preview the rendered template before sending.
  • Receipt confirmation: a manual toggle on the submission for V1 (operator flips it after the lender replies) — no auto-detection in V1.
  • Pre-submit checklist + document selector: a checklist reads the lender’s requiredDocs[]; a document selector pulls from the client’s existing document section and attaches selected docs to the email; the selection is snapshotted to lenderSubmissions.documentsSnapshot.
  • “Email sent” record: timestamp (submittedAt) plus a lenderSubmissionEvents entry. This becomes the anchor record that all further lender communication hangs off of.
  • Manual status slot: a single editable lenderSubmissions.status field (submitted/in_review/approved/declined/funded), manually updated for V1.
  • Funded-total rollup: a section at the bottom of the Direct Lender view summing funded submissions per lender, matching how other products display “amount successfully funded.”
As of the notes, this is still spec only — no code written; schema/API changes remain behind the governance spec-gate (Section 2).

7. Product Taxonomy

Leo Kanell posted a three-tier funding-workflow taxonomy (2026-07-02) that groups the products the direct-lender project must support: This is a product-grouping layer sitting above individual lenders — each lender still resolves to one of the three integration patterns (Section 3), but deals/products are organized under these three workflow tiers. This layer is relevant to how the data model and eligibility engine (Sections 4–5) should categorize offerings. BLOC/SBA split (open, in progress): BLOC and SBA were originally grouped under one underwriting profile “for now” (Kevin, 2026-07-02). On 2026-07-02, Nate asked to split BLOC from SBA and track them as separate products going forward. The existing 20–30%-of-annual-gross figure above is SBA’s number — no separate BLOC preapproval range or underwriting criteria has been provided yet post-split (see Section 9).

Routing rule

Leo Kanell also posted a revenue-based routing rule (2026-07-02) for Alternative and Traditional Funding deals (MCA, BLOC, SBA):
  • Business generating less than $75k/month in revenue → route to Lexington Capital
  • Business generating more than $75k/month in revenue → route to Sandbar Fund
This routing logic belongs in the eligibility/routing layer described in Section 5. The exact-$75k boundary case (equality) is not defined in the source discussion (see Section 9).

8. Lenders Identified So Far

Open lender-sourcing need (Ty Talbot, 2026-07-06): the roster still needs 1–2 higher-risk MCA lenders and 1–2 direct/legit lenders. Ty asked Robert M for recommendations on 2026-07-06; no answer had been captured as of this writing. For all of the above, integration pattern (api/portal/email) and connection method (api/credentials/referral_link/iso_account) should be captured per-lender as details arrive, per the existing convention of tracking this in per-lender memory/records rather than assuming a default.

9. Open Questions

These are explicitly unresolved in the source discussion and are not resolved by this document:
  1. BLOC preapproval criteria. Now that BLOC is split from SBA (Section 7), what preapproval range and underwriting criteria should BLOC use? The existing 20–30%-of-annual-gross-revenue figure belongs to SBA, not BLOC. No BLOC-specific number has been provided.
  2. Funding-plan placement acceptability. Is rendering a direct-lender product block inside the existing fundingPlans UI (parallel to “Submit to 7 Figures Funding”) acceptable under the hard scope boundary in Section 1 (no touching the processing-team flow), or must the direct-lender system stay entirely out of the funding-plan screen? Asked of Kevin Hill 2026-06-30; unresolved.
  3. Screen placement, final call. Three different placements were proposed across design iterations (top-level sidebar nav → Settings-only, no new tab → top-level “Lender” parent tab). The most recent (Robert M, 2026-07-01) leans top-level “Lender” tab, but this has not been confirmed as final.
  4. Email template source. Should per-lender email templates be custom catalog data on the lenders record, or should V1 use GHL’s built-in template system? Recommended default is per-lender catalog data; Robert M has not yet confirmed.
  5. Admin UI for adding lenders. Kevin Hill asked (2026-07-06) whether there should be an internal admin-view way to add new lenders, and whether that flow should vary depending on the lender’s integration type (api/portal/email). Not yet answered.
  6. **Exact-75kboundary.Therevenueroutingrule(Section7)specifies"lessthan75k boundary.** The revenue-routing rule (Section 7) specifies "less than 75k/mo → Lexington Capital” and “more than 75k/moSandbarFund"butdoesnotdefinewhichlenderhandlesabusinessatexactly75k/mo → Sandbar Fund" but does not define which lender handles a business at exactly 75k/mo.
  7. Approval-gate mechanics. Beyond the general VISION.md rule that human-directed work satisfies the spec-gate (Section 2), Kevin Hill was asked (2026-06-30) how he specifically wants the approval gate handled procedurally before implementation begins (e.g., per-PR sign-off vs. a one-time design approval covering the whole project). No answer captured as of this writing.
  8. 1–2 higher-risk MCA lenders and 1–2 direct/legit lenders still need to be sourced (Section 8) — Ty Talbot asked Robert M for recommendations 2026-07-06; no answer captured yet.
  9. Curation-seam integration. Should the direct-lender eligibility engine (Section 5) integrate with / respect the existing loanOfferCuration.ts curation seam (which already reserves lenderAllowList, lenderBlockList, and minRecommendationScore for lender curation), or run as a fully independent rule path? Flagged by review — a lender blocked by curation could otherwise remain eligible in the new module if the two paths diverge.

Appendix: Source Material

This document was compiled from the following channel-memory sources (2026-06-30 through 2026-07-06 discussion in #direct-lender-integration): project context and driving stakeholder (Kevin Hill); the additive/dark-launch architecture plan; the two Claude Design exports (“Lender Integrations” reference prototype and “Direct Lenders” build-ready spec); Robert M’s V1 operator-flow notes; the existing lender-related code inventory; Convex conventions; Leo Kanell’s funding-workflow taxonomy and routing rules; and the VISION.md/AGENTS.md governance spec-gate.