Add KYB business-entity fields for Lead — NAICS, structured source of funds, counterparty countries (ENG-10687)#643
Conversation
…funds, counterparty countries (ENG-10687) Adds to BusinessInfo / BusinessInfoUpdate / BusinessInfoResponse: - naicsCode (2-6 digit NAICS) - sourceOfFundsCategories (references the existing SourceOfFunds enum) + sourceOfFundsOtherDescription - purposeOfAccountOtherDescription - expectedCounterpartyCountries Adds MISSING_CONTROL_PERSON and MISSING_GOOD_STANDING_DOCUMENT verification error types. Co-Authored-By: akanter <akanter@users.noreply.github.com>
The legacy free-text sourceOfFunds property coexists on BusinessInfo; a sibling type named SourceOfFunds breaks the generated C# SDK (property / type name collision flagged by the Stainless preview build).
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
This stack of pull requests is managed by Graphite. Learn more about stacking. |
✱ Stainless preview builds for gridThis PR will update the cli csharp go kotlin openapi php python ruby typescript Edit this comment to update them. They will appear in their respective SDK's changelogs. ✅ grid-cli studio · code · diff
✅ grid-openapi studio · code · diff
✅ grid-ruby studio · code · diff
✅ grid-go studio · code · diff
✅ grid-kotlin studio · code · diff
|
|
CI triage on this claimed PR (tip is unchanged from #641, where Lint passed):
|
Greptile SummaryThis PR extends
Confidence Score: 4/5Safe to merge; all changes are additive, optional fields on existing schemas with no breaking changes. The changes are purely additive — new optional fields and two new enum values. The main things to double-check before merging are whether PERSONAL_SAVINGS belongs in a business-only enum and whether the VerificationErrorType description should be updated to cover the new person-level category. Neither would cause a runtime failure, but both affect API consumer clarity. SourceOfFundsCategory.yaml for the PERSONAL_SAVINGS semantic question; VerificationErrorType.yaml for the stale description text.
|
| Filename | Overview |
|---|---|
| openapi/components/schemas/customers/BusinessInfo.yaml | Adds naicsCode (pattern-validated), sourceOfFundsCategories (new SourceOfFundsCategory enum ref), sourceOfFundsOtherDescription, purposeOfAccountOtherDescription, and expectedCounterpartyCountries. Structurally consistent with existing fields. |
| openapi/components/schemas/customers/BusinessInfoUpdate.yaml | Same new fields added as BusinessInfo.yaml; changes are identical in structure and content, consistent with the existing update schema pattern. |
| openapi/components/schemas/customers/BusinessInfoResponse.yaml | Same new fields added as BusinessInfo.yaml; all five new fields are symmetric across create/update/response schemas as expected. |
| openapi/components/schemas/customers/SourceOfFundsCategory.yaml | New enum for structured source-of-funds; includes PERSONAL_SAVINGS which is semantically unusual for a business-entity-only schema and may warrant clarification. |
| openapi/components/schemas/verifications/VerificationErrorType.yaml | Adds MISSING_CONTROL_PERSON and MISSING_GOOD_STANDING_DOCUMENT; the description text wasn't updated to document the new MISSING_CONTROL_PERSON category type. |
Entity Relationship Diagram
%%{init: {'theme': 'neutral'}}%%
erDiagram
BusinessInfo {
string legalName
string taxId
date incorporatedOn
string naicsCode "NEW: 2-6 digit NAICS"
array sourceOfFundsCategories "NEW: SourceOfFundsCategory[]"
string sourceOfFundsOtherDescription "NEW: max 500 chars"
string purposeOfAccountOtherDescription "NEW: max 500 chars"
array expectedCounterpartyCountries "NEW: ISO 3166-1 alpha-2[]"
}
SourceOfFundsCategory {
string OPERATING_REVENUE
string INVESTMENT_INCOME
string LOANS
string VENTURE_CAPITAL
string PERSONAL_SAVINGS
string DONATIONS
string OTHER
}
VerificationErrorType {
string MISSING_CONTROL_PERSON "NEW"
string MISSING_GOOD_STANDING_DOCUMENT "NEW"
string MISSING_BENEFICIAL_OWNER
string MISSING_FIELD
}
BusinessInfo ||--o{ SourceOfFundsCategory : "sourceOfFundsCategories"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
erDiagram
BusinessInfo {
string legalName
string taxId
date incorporatedOn
string naicsCode "NEW: 2-6 digit NAICS"
array sourceOfFundsCategories "NEW: SourceOfFundsCategory[]"
string sourceOfFundsOtherDescription "NEW: max 500 chars"
string purposeOfAccountOtherDescription "NEW: max 500 chars"
array expectedCounterpartyCountries "NEW: ISO 3166-1 alpha-2[]"
}
SourceOfFundsCategory {
string OPERATING_REVENUE
string INVESTMENT_INCOME
string LOANS
string VENTURE_CAPITAL
string PERSONAL_SAVINGS
string DONATIONS
string OTHER
}
VerificationErrorType {
string MISSING_CONTROL_PERSON "NEW"
string MISSING_GOOD_STANDING_DOCUMENT "NEW"
string MISSING_BENEFICIAL_OWNER
string MISSING_FIELD
}
BusinessInfo ||--o{ SourceOfFundsCategory : "sourceOfFundsCategories"
Comments Outside Diff (1)
-
openapi/components/schemas/verifications/VerificationErrorType.yaml, line 25-31 (link)The
descriptiontext categorises error types into three buckets (MISSING_DOCUMENT, document-quality types, APPLICANT types), butMISSING_CONTROL_PERSONdoesn't fit any of them — it's a missing-person/entity error, not a missing-document or applicant error. Without a description update, API consumers have no guidance on when to expect this new value.MISSING_BENEFICIAL_OWNERhas the same gap, but this PR is the right moment to fix it.Prompt To Fix With AI
This is a comment left during a code review. Path: openapi/components/schemas/verifications/VerificationErrorType.yaml Line: 25-31 Comment: The `description` text categorises error types into three buckets (MISSING_*_DOCUMENT, document-quality types, APPLICANT_* types), but `MISSING_CONTROL_PERSON` doesn't fit any of them — it's a missing-person/entity error, not a missing-document or applicant error. Without a description update, API consumers have no guidance on when to expect this new value. `MISSING_BENEFICIAL_OWNER` has the same gap, but this PR is the right moment to fix it. How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 5 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 5
openapi/components/schemas/customers/SourceOfFundsCategory.yaml:7
**`PERSONAL_SAVINGS` in a business-entity enum**
`PERSONAL_SAVINGS` is semantically individual/consumer-oriented and stands out in a schema that applies exclusively to business entities. A client seeing this enum value on a KYB form could incorrectly report the business's source of funds as "personal savings" (e.g., a sole-proprietor confusing business and personal funds), which might create CDD quality issues. Is this intentional (e.g., founder-funded LLC scenarios), or should it be excluded from the business-entity variant in favour of a value like `EQUITY_INVESTMENT` or `OWNER_CAPITAL_CONTRIBUTION`?
### Issue 2 of 5
openapi/components/schemas/verifications/VerificationErrorType.yaml:25-31
The `description` text categorises error types into three buckets (MISSING_*_DOCUMENT, document-quality types, APPLICANT_* types), but `MISSING_CONTROL_PERSON` doesn't fit any of them — it's a missing-person/entity error, not a missing-document or applicant error. Without a description update, API consumers have no guidance on when to expect this new value. `MISSING_BENEFICIAL_OWNER` has the same gap, but this PR is the right moment to fix it.
```suggestion
description: >-
Type of verification error. The category-specific MISSING_*_DOCUMENT types
indicate which document category is needed. Document quality types
(POOR_QUALITY_DOCUMENT, SUSPECTED_FRAUD_DOCUMENT, etc.) indicate specific
issues with uploaded documents. APPLICANT_* types indicate issues with the
applicant themselves (sanctions, fraud, criminal records).
MISSING_BENEFICIAL_OWNER and MISSING_CONTROL_PERSON indicate that a required
person record has not been provided.
example: MISSING_FIELD
```
### Issue 3 of 5
openapi/components/schemas/customers/BusinessInfo.yaml:89-98
Neither `sourceOfFundsOtherDescription` nor `purposeOfAccountOtherDescription` has a `minLength: 1` guard. A client that selects `OTHER` and submits an empty string would pass schema validation while producing a meaningless CDD record. Adding `minLength: 1` to both makes the schema self-documenting about the expected contract and lets validators reject bad payloads before they reach the backend.
```suggestion
sourceOfFundsOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the source of funds when OTHER is selected
example: Proceeds from a legal settlement
purposeOfAccountOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the account purpose when OTHER is selected
example: Escrow for equipment leases
```
### Issue 4 of 5
openapi/components/schemas/customers/BusinessInfoUpdate.yaml:85-94
Same missing `minLength: 1` as in `BusinessInfo.yaml` — applies here in the update schema as well.
```suggestion
sourceOfFundsOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the source of funds when OTHER is selected
example: Proceeds from a legal settlement
purposeOfAccountOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the account purpose when OTHER is selected
example: Escrow for equipment leases
```
### Issue 5 of 5
openapi/components/schemas/customers/BusinessInfoResponse.yaml:90-99
Same missing `minLength: 1` as in `BusinessInfo.yaml` — applies here in the response schema as well.
```suggestion
sourceOfFundsOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the source of funds when OTHER is selected
example: Proceeds from a legal settlement
purposeOfAccountOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the account purpose when OTHER is selected
example: Escrow for equipment leases
```
Reviews (1): Last reviewed commit: "Rename SourceOfFunds enum schema to Sour..." | Re-trigger Greptile
| @@ -7,5 +7,5 @@ enum: | |||
| - PERSONAL_SAVINGS | |||
There was a problem hiding this comment.
PERSONAL_SAVINGS in a business-entity enum
PERSONAL_SAVINGS is semantically individual/consumer-oriented and stands out in a schema that applies exclusively to business entities. A client seeing this enum value on a KYB form could incorrectly report the business's source of funds as "personal savings" (e.g., a sole-proprietor confusing business and personal funds), which might create CDD quality issues. Is this intentional (e.g., founder-funded LLC scenarios), or should it be excluded from the business-entity variant in favour of a value like EQUITY_INVESTMENT or OWNER_CAPITAL_CONTRIBUTION?
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/customers/SourceOfFundsCategory.yaml
Line: 7
Comment:
**`PERSONAL_SAVINGS` in a business-entity enum**
`PERSONAL_SAVINGS` is semantically individual/consumer-oriented and stands out in a schema that applies exclusively to business entities. A client seeing this enum value on a KYB form could incorrectly report the business's source of funds as "personal savings" (e.g., a sole-proprietor confusing business and personal funds), which might create CDD quality issues. Is this intentional (e.g., founder-funded LLC scenarios), or should it be excluded from the business-entity variant in favour of a value like `EQUITY_INVESTMENT` or `OWNER_CAPITAL_CONTRIBUTION`?
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| sourceOfFundsOtherDescription: | ||
| type: string | ||
| maxLength: 500 | ||
| description: Description of the source of funds when OTHER is selected | ||
| example: Proceeds from a legal settlement | ||
| purposeOfAccountOtherDescription: | ||
| type: string | ||
| maxLength: 500 | ||
| description: Description of the account purpose when OTHER is selected | ||
| example: Escrow for equipment leases |
There was a problem hiding this comment.
Neither
sourceOfFundsOtherDescription nor purposeOfAccountOtherDescription has a minLength: 1 guard. A client that selects OTHER and submits an empty string would pass schema validation while producing a meaningless CDD record. Adding minLength: 1 to both makes the schema self-documenting about the expected contract and lets validators reject bad payloads before they reach the backend.
| sourceOfFundsOtherDescription: | |
| type: string | |
| maxLength: 500 | |
| description: Description of the source of funds when OTHER is selected | |
| example: Proceeds from a legal settlement | |
| purposeOfAccountOtherDescription: | |
| type: string | |
| maxLength: 500 | |
| description: Description of the account purpose when OTHER is selected | |
| example: Escrow for equipment leases | |
| sourceOfFundsOtherDescription: | |
| type: string | |
| minLength: 1 | |
| maxLength: 500 | |
| description: Description of the source of funds when OTHER is selected | |
| example: Proceeds from a legal settlement | |
| purposeOfAccountOtherDescription: | |
| type: string | |
| minLength: 1 | |
| maxLength: 500 | |
| description: Description of the account purpose when OTHER is selected | |
| example: Escrow for equipment leases |
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/customers/BusinessInfo.yaml
Line: 89-98
Comment:
Neither `sourceOfFundsOtherDescription` nor `purposeOfAccountOtherDescription` has a `minLength: 1` guard. A client that selects `OTHER` and submits an empty string would pass schema validation while producing a meaningless CDD record. Adding `minLength: 1` to both makes the schema self-documenting about the expected contract and lets validators reject bad payloads before they reach the backend.
```suggestion
sourceOfFundsOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the source of funds when OTHER is selected
example: Proceeds from a legal settlement
purposeOfAccountOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the account purpose when OTHER is selected
example: Escrow for equipment leases
```
How can I resolve this? If you propose a fix, please make it concise.| sourceOfFundsOtherDescription: | ||
| type: string | ||
| maxLength: 500 | ||
| description: Description of the source of funds when OTHER is selected | ||
| example: Proceeds from a legal settlement | ||
| purposeOfAccountOtherDescription: | ||
| type: string | ||
| maxLength: 500 | ||
| description: Description of the account purpose when OTHER is selected | ||
| example: Escrow for equipment leases |
There was a problem hiding this comment.
Same missing
minLength: 1 as in BusinessInfo.yaml — applies here in the update schema as well.
| sourceOfFundsOtherDescription: | |
| type: string | |
| maxLength: 500 | |
| description: Description of the source of funds when OTHER is selected | |
| example: Proceeds from a legal settlement | |
| purposeOfAccountOtherDescription: | |
| type: string | |
| maxLength: 500 | |
| description: Description of the account purpose when OTHER is selected | |
| example: Escrow for equipment leases | |
| sourceOfFundsOtherDescription: | |
| type: string | |
| minLength: 1 | |
| maxLength: 500 | |
| description: Description of the source of funds when OTHER is selected | |
| example: Proceeds from a legal settlement | |
| purposeOfAccountOtherDescription: | |
| type: string | |
| minLength: 1 | |
| maxLength: 500 | |
| description: Description of the account purpose when OTHER is selected | |
| example: Escrow for equipment leases |
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/customers/BusinessInfoUpdate.yaml
Line: 85-94
Comment:
Same missing `minLength: 1` as in `BusinessInfo.yaml` — applies here in the update schema as well.
```suggestion
sourceOfFundsOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the source of funds when OTHER is selected
example: Proceeds from a legal settlement
purposeOfAccountOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the account purpose when OTHER is selected
example: Escrow for equipment leases
```
How can I resolve this? If you propose a fix, please make it concise.| sourceOfFundsOtherDescription: | ||
| type: string | ||
| maxLength: 500 | ||
| description: Description of the source of funds when OTHER is selected | ||
| example: Proceeds from a legal settlement | ||
| purposeOfAccountOtherDescription: | ||
| type: string | ||
| maxLength: 500 | ||
| description: Description of the account purpose when OTHER is selected | ||
| example: Escrow for equipment leases |
There was a problem hiding this comment.
Same missing
minLength: 1 as in BusinessInfo.yaml — applies here in the response schema as well.
| sourceOfFundsOtherDescription: | |
| type: string | |
| maxLength: 500 | |
| description: Description of the source of funds when OTHER is selected | |
| example: Proceeds from a legal settlement | |
| purposeOfAccountOtherDescription: | |
| type: string | |
| maxLength: 500 | |
| description: Description of the account purpose when OTHER is selected | |
| example: Escrow for equipment leases | |
| sourceOfFundsOtherDescription: | |
| type: string | |
| minLength: 1 | |
| maxLength: 500 | |
| description: Description of the source of funds when OTHER is selected | |
| example: Proceeds from a legal settlement | |
| purposeOfAccountOtherDescription: | |
| type: string | |
| minLength: 1 | |
| maxLength: 500 | |
| description: Description of the account purpose when OTHER is selected | |
| example: Escrow for equipment leases |
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/customers/BusinessInfoResponse.yaml
Line: 90-99
Comment:
Same missing `minLength: 1` as in `BusinessInfo.yaml` — applies here in the response schema as well.
```suggestion
sourceOfFundsOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the source of funds when OTHER is selected
example: Proceeds from a legal settlement
purposeOfAccountOtherDescription:
type: string
minLength: 1
maxLength: 500
description: Description of the account purpose when OTHER is selected
example: Escrow for equipment leases
```
How can I resolve this? If you propose a fix, please make it concise.
Summary
Spec side of webdev ENG-10687 (KYB field gaps for Lead business entities). Companion to the webdev stack rooted at lightsparkdev/webdev#29776.
Adds to
BusinessInfo/BusinessInfoUpdate/BusinessInfoResponse:naicsCode— 2–6 digit NAICS code (Lead takes NAICS viabusiness_details.industry)sourceOfFundsCategories— array referencing the existing (previously unreferenced)SourceOfFundsenum, plussourceOfFundsOtherDescriptionpurposeOfAccountOtherDescription— CDD 'other' description forpurposeOfAccount: OTHERexpectedCounterpartyCountries— geographic-risk CDD field (distinct from send-sideexpectedRecipientJurisdictions)Adds
MISSING_CONTROL_PERSONandMISSING_GOOD_STANDING_DOCUMENTtoVerificationErrorType(control person and Certificate of Good Standing are Lead KYB requirements; the webdev validator will emit these for Lead-partnered platforms).make buildre-bundledopenapi.yaml+mintlify/openapi.yaml.make lint-openapiis baseline-equivalent (same single pre-existing error as main).Test plan
🤖 fierce-nexus-2(#2) | Feedback
Original PR: #641