Grid Programmatic KYC API - #726
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
|
⚡ On it — stripping the LexisNexis content from the plan (that was just answering your investigation question, not implementation scope). Also adding sandbox support to the design doc (#700) since customers need to be able to drive the KYC flow through sandbox. |
|
Got it — leaving this plan PR alone for now. Jumping over to grid-api#700 to add the sandbox section to the design doc first. Once the sandbox design is settled there, I'll come back and update this plan (both dropping the LexisNexis content per your earlier note, and incorporating sandbox into the implementation phasing). |
|
Aligned on the strategy. Reworking Phase 1 to be: full API surface (schemas + new endpoints) + full sandbox behavior, no real production wire-up yet. That lets customers integrate against sandbox immediately while we progressively fill in the real Sumsub / LexisNexis / doc pass-through behind the same API. Production wire-up becomes Phase 2+. Also dropping the LexisNexis content per your earlier note. Standby. |
|
⚡ Starting Phase 1 implementation now. Since design doc #700 has the current-state design (with sandbox first-class and OFAC treated as separate work), I'll:
|
8f5c9ef to
d64ecbf
Compare
|
First Phase 1 slice pushed (R2). In this push:
Still to come in follow-up commits on this PR:
Sparkcore backend PR will follow separately (different repo). |
✱ Stainless preview builds for gridThis PR will update the cli go kotlin openapi php python ruby typescript ✅ grid-ruby studio · code
|
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
d64ecbf to
67a3a37
Compare
67a3a37 to
0783bc0
Compare
|
R4 pushed — aligned with the 6 design changes in #700 R13. Reverted from R3:
Added:
Kept from R3:
One design nit flagged in the plan doc's Risks section: existing |
84dcfb0 to
a39f570
Compare
a39f570 to
bd115b5
Compare
bd115b5 to
65b67eb
Compare
65b67eb to
9f76353
Compare
Revision 11Addressed @pengying's two inline comments:
Also rolled into this commit (was pending in the working tree from a prior local session that lost the dedicated commit to a rebase, so I let
Rebundled |
f0a2dd8 to
1575a8b
Compare
Revision 12Flattened
Follow-on cleanup:
Rationale (matches Stripe's Downstream impact on webdev#31108 (PR B)Sparkcore-side already has flat columns on the ent ( |
Revision 13 — pathParam nesting per @akanter's landingSwitched Changes:
Composes naturally to Sparkcore-side follow-up (webdev #31107): switching the handler routes from
|
b9e4d8d to
a7aeaff
Compare
Addresses @jklein24's review questions on grid-api#726: - top-level: explicit that FieldConstraint drives both client-side pre-validation and direct form-UI rendering (HTML5 input type, inputmode, autocomplete, maxlength attributes). - format: usage guidance — prefer HTML5 input type names when the field maps to one; use semantic slugs otherwise; treat unknown values as opaque and fall back to accompanying pattern/length constraints. Example changed to `email` (HTML5 canonical). - pattern: notes that length is surfaced as separate minLength/ maxLength fields so consumers can wire native controls without regex evaluation. - minLength / maxLength: rationale for being distinct fields (native <input maxlength> wire-up) documented. No schema shape change; description-only. Co-Authored-By: jklein24 <jklein24@users.noreply.github.com>
…xIdentifier/taxIdCountryOfIssuance (@akanter direction, Stripe-style)
…d (pathParam nesting per @akanter direction) Restful pathParam nesting matches shreyav's and jklein24's inclination: - Renamed openapi/paths/customers/customers_edd.yaml → customers_{customerId}_edd.yaml - Added path-level customerId path parameter (inherited by GET/POST/PATCH) - Removed per-operation customerId query parameter - Deleted CustomerEddCreateRequest.yaml (customerId no longer in body; CustomerEdd.yaml is now the POST request body directly) - openapi/openapi.yaml: path key /customers/edd -> /customers/{customerId}/edd, grouped with other /customers/{customerId}/... subresources Composes naturally to /transactions/{id}/edd if we ever ship transaction-EDD.
…tomers/{id}/edd endpoint)
@akanter's landed direction after design discussion + 8-vendor competitive research (BaaS
precedent unanimous: Stripe/Bridge/Unit all put EDD on the customer resource).
- Delete openapi/paths/customers/customers_{customerId}_edd.yaml (was R13's endpoint file)
- Remove /customers/{customerId}/edd path key from openapi/openapi.yaml
- IndividualCustomerFields.yaml: restructure to allOf composition with CustomerEdd.yaml,
so the 11 EDD fields (SoF, SoW, PEP, income, net worth, purpose, txn volume/count, plus
3 *OtherDescription companions) become optional top-level attributes on the customer
- CustomerEdd.yaml: drop createdAt/updatedAt (no longer a resource; Customer's own
timestamps suffice); update description to reflect the new pattern
- Error400.yaml: drop /customers/{id}/edd from submit-endpoints example list
API surface != DB schema: sparkcore-side still keeps EntUmaaasCustomerEdd as a separate
1:1-nullable table to avoid NULL bloat on IndividualUserInfo; only customers who submit
EDD get a row. See webdev#31107 PR A rework for the sparkcore-side change.
a7aeaff to
af730cd
Compare
|
re github-actions[bot] breaking-change warningThose warnings are false positives from the R14 restructure — the detector doesn't unwrap What actually changed:
They're not breaking — the merged schema (allOf semantics) still has Alternative: could inline the 11 EDD field definitions directly into Rebase status: PR is now on latest main ( |
|
You need a patch on the path /customers |
|
Let me know if you meant something different — e.g., a queryParam-style |
## Summary
- Fix sandbox-verification.mdx EDD example to use correct endpoint
(`PATCH /customers/{customerId}` instead of non-existent `POST
/customers/edd`)
- Replace invalid `PERSONAL_SPEND` enum value with valid `P2P_TRANSFERS`
from PurposeOfAccount schema
- Add required `customerType: INDIVIDUAL` to PATCH request body
This sync addresses documentation drift from the Grid Programmatic KYC
API (#726) changes.
## Test plan
- [x] Verified `P2P_TRANSFERS` is a valid PurposeOfAccount enum value in
`openapi/components/schemas/customers/PurposeOfAccount.yaml`
- [x] Verified EDD fields are patched via `PATCH
/customers/{customerId}` per `CustomerEdd.yaml` description and
`IndividualCustomerUpdateRequest.yaml` schema
- [x] Ran `make lint` - no new errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

Summary
Phase 1 grid-api slice of the KYC singleton flow — OpenAPI schema additions, the new EDD endpoint, and Mintlify sandbox docs.
OpenAPI schemas
taxIdentificationadded toIndividualCustomerFields.yamlas a single optional object referencing the existingIdentificationTypeenum (SSN|ITIN|EIN|NON_US_TAX_ID).TaxIdentification.yaml(idType, identifier, countryOfIssuance).FieldConstraint.yamlundererrors/— regex / format / enum / min-max length.Error400.yaml'sdetailsdescription documents the convention: on submit-endpoint validation failures,details.constraintconforms toFieldConstraint, giving platforms a machine-readable validator hint they can use to pre-validate their onboarding form before re-submitting. Applies toPOST /customers,PATCH /customers/{id},POST /customers/edd,PATCH /customers/edd.IndividualSourceOfFundsCategory(11 individual-appropriate values),SourceOfWealthCategory,AnnualIncomeRange,NetWorthRange,PepStatus,ExpectedMonthlyTransactionCount,ExpectedMonthlyTransactionVolume.IndividualSourceOfFundsCategorysits alongside the existing (business)SourceOfFundsCategory, keeping the business flow's enum untouched.ExpectedMonthlyTransactionCount/Volumeare extracted from previously-inline definitions inBusinessInfo.yamland shared with the new EDD schema.New EDD endpoint
Flat linked-resource pattern per
openapi/README.md— customerId in the request body onPOST, as a query param onGET/PATCH.POST /customers/edd— create or replace a customer's enhanced-due-diligence fields (200, upsert semantics).GET /customers/edd?customerId={id}— retrieve (404 if none recorded).PATCH /customers/edd?customerId={id}— partial update.CustomerEddCreateRequest.yaml— POST body:customerId+ 8 optional EDD fields.CustomerEdd.yaml— response and PATCH body: 8 optional fields (sourceOfFundsCategories,sourceOfWealthCategories,purposeOfAccount,expectedMonthlyTransactionCount,expectedMonthlyTransactionVolume,annualIncomeRange,netWorthRange,pepStatus).openapi/openapi.yaml.Sandbox docs
mintlify/snippets/sandbox-verification.mdx— combined snippet covering all three verification types (business KYB, beneficial-owner KYC, individual-customer KYC).fullNamesuffix001→ PENDING,002→ REJECTED,003→ APPROVED with EDD-required flow, else APPROVED.VerificationErrorwithEDD_INFORMATION_MISSING) →POST /customers/edd→ retry verification → APPROVED.mintlify/api-reference/sandbox-testing.mdxpoints at the renamed snippet.Verification
make buildsucceeds — bundledopenapi.yamlandmintlify/openapi.yamlregenerated.make lintpasses (exit 0; 14 pre-existing warnings, no new errors introduced by this diff).Scope
grid-api (OpenAPI spec + Mintlify docs) only. Sparkcore persistence, sandbox switch wiring, and Sumsub integration ship on webdev#31010 (plan up for approval). OFAC / LexisNexis handling is a separate workstream.
Reply with a comment (e.g. LGTM) to approve — emoji reactions don't notify me here.