Skip to content

plan-kyc-api-design#700

Draft
akanter wants to merge 1 commit into
mainfrom
07-18-kyc-api-design
Draft

plan-kyc-api-design#700
akanter wants to merge 1 commit into
mainfrom
07-18-kyc-api-design

Conversation

@akanter

@akanter akanter commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Design proposal for the API-based KYC flow — an additive extension of the existing KYB verification surface. Full doc: docs/plans/2026-07-18-kyc-api-design.md in this PR's diff.

The direct-API KYC flow already technically works today (POST /customers INDIVIDUAL → POST /documentsPOST /verifications returns structured errors[]). This document proposes the additions to make that flow production-ready for interactive in-app onboarding. Bulk migration is documented in Appendix A for continuity but is explicit future work — not on this workstream.

Reading guide

The doc is structured to be read top-to-bottom for the singleton flow (Phase 1). Bulk migration is at the end (Appendix A), skippable.

  1. Context — where we are today.
  2. Design goals — the axes we're optimizing.
  3. Open questions for Phase 1 — decisions needing input, each with a proposed default.
  4. What exists today — API surface + backend behavior + existing sandbox pattern.
  5. Proposed changes — §1 taxIdentification, §1a EDD endpoint, §2 400-level validation, §3 Document upload strategy, §4 Sandbox mode.
  6. Walkthrough — interactive singleton flow example.
  7. Implementation phasing — Phase 1 (API + sandbox) → Phase 2 (production wire-up).
  8. Appendix A — Bulk migration (deferred).

Open questions calling for input

Three decisions the doc surfaces near the top (each with a proposed default so silence = proceed):

  1. /customers/edd vs /customers/endorsements (Bridge-style)? Jeremy raised this via Aaron. Bridge uses endorsement-per-rail (base/sepa/spei/pix/faster_payments/cop) with independent lifecycles; Stripe uses a single per-customer requirements bag. Current doc uses /customers/edd (single bag). Default: keep for Phase 1, pivot before the second compliance regime lands.
  2. PurposeOfAccount — need an individual variant? Existing enum values are business-flow oriented. Default: add IndividualPurposeOfAccount, matching the pattern applied to IndividualSourceOfFundsCategory.
  3. EDD backend storage — JSON blob vs dedicated ent? Default: dedicated EntUmaaasCustomerEdd ent.

Approach

Keep KYC on the same Verification lifecycle as KYB. All extensions are additive — no breaking changes to Customer, Verification, or VerificationError. Universal wire format for addresses; per-jurisdiction / per-currency requirements are documented in Mintlify and surfaced reactively via POST /verifications errors (no runtime discovery endpoint). Sandbox is first-class — platforms drive the full KYC lifecycle (create → verify → APPROVED / REJECTED / PENDING / EDD-required) via deterministic fullName-suffix magic values that mirror the existing KYB and BO KYC patterns.

Implementation strategy: ship the API surface + sandbox behavior first (customers can integrate immediately); production wire-up follows behind the same API.

Proposed changes (Phase 1)

  • §1 taxIdentification on IndividualCustomerFields — single optional object of {idType, identifier, countryOfIssuance}, using existing IdentificationType enum.
  • §1a EDD endpoint — new POST/GET/PATCH /customers/edd (customerId in body on POST, query param on GET/PATCH), matching the flat-linked-resource pattern from openapi/README.md. Schema: 8 primary EDD fields + 3 conditional *OtherDescription freeform fields.
  • §2 Machine-readable 400 validation — new FieldConstraint.yaml under errors/, documents the Error400.details.constraint shape (regex / format / enum / min-max length). Applies to POST /customers, PATCH /customers/{id}, POST /customers/edd, PATCH /customers/edd.
  • §3 Document upload strategy — Patterns A (no docs) + B (sequential create-then-upload). Both are single-customer. Bulk-oriented document patterns (C, D) live in Appendix A.
  • §4 Sandbox — individual-KYC magic-value triggers on fullName suffix: 001 PENDING, 002 REJECTED, 003 EDD-required, else APPROVED. Documented alongside the existing business KYB and BO KYC sandbox in mintlify/snippets/sandbox-verification.mdx.

Not in this workstream

Bulk migration + Grid-side document caching (Appendix A). OFAC / LexisNexis handling is a separate work item.

Reply with a comment (e.g. LGTM) to approve the design direction — emoji reactions don't notify me here.

@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
grid-flow-builder Ignored Ignored Preview Jul 24, 2026 5:05am
grid-wallet-demo Ignored Ignored Preview Jul 24, 2026 5:05am

Request Review

akanter commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
@akanter akanter added the bolt label Jul 20, 2026 — with Graphite App
@ls-bolt

ls-bolt Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

📌 Bolt Status

2026-07-20 23:55:16 UTC — ⚡ Agent staking-corona-2(#2) started
2026-07-21 01:20:29 UTC — ⚡ Agent staking-corona-3(#3) started
2026-07-21 15:13:01 UTC — ⚡ Agent staking-corona-4(#4) started
2026-07-21 17:45:35 UTC — ⚡ Agent staking-corona-5(#5) started
2026-07-22 19:11:18 UTC — ⚡ Agent staking-corona-6(#6) started
2026-07-24 04:53:47 UTC — ⚡ Agent staking-corona-7(#7) started


Feedback

@ls-bolt

ls-bolt Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

⚡ On it — working through all 14 threads. Firing off research on the industry-standard questions (HNWI fields, CSV array conventions, Sumsub requirements API + doc limits, Stripe's eventually_due in practice), and updating the doc in parallel for the ones with clear direction (drop localizedAddress, rename to /verification/requirements, move inline verify to POST /customers with a flag, clarify identification[] is ID numbers only). I'll push updates and reply on each thread.

@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from f40742a to 579a58f Compare July 21, 2026 00:07
@ls-bolt

ls-bolt Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Revision 2

Addressed all 14 threads. Replies inline; here's the diff at a glance:

Applied Aaron's direct guidance:

  • Renamed /kyc/requirements/verification/requirements (single leftover ref cleaned up too)
  • Moved atomic-verify from an inline POST /verifications variant to a submitForVerification: true flag on POST /customers and PATCH /customers/{id} — response wraps { customer, verification }
  • Kept a single POST /verifications endpoint (dropped the POST /kyc alias open question)
  • Clarified that identification[] is ID numbers only (SSN, ITIN, passport number, national-ID number); docs still go through POST /documents. Renamed the doc-backed enum values to _NUMBER suffixes to make the split obvious
  • Deferred localizedAddress for JP/CN/KR — won't add to the wire format until we're onboarding a platform that needs it
  • Kept 1000 as a placeholder cap on POST /customers/bulk

Applied research findings:

  • EVENTUALLY_DUE dropped — Stripe's eventually_due is a forecasting bucket, not a per-req "actionable why" signal. Without a "blocks feature X at volume Y" mapping to bind it to, adding the enum would over-promise
  • Added §1a Enhanced Due Diligence extraspepStatus, sourceOfWealth (distinct from source-of-funds — wealth is stock, funds is flow), annualIncomeRange / netWorthRange, taxResidencies[] (FATCA + CRS in one shape), employmentStatus, additionalNationalities[], aliases[], intermediaryStatus. All optional. Sourced from Sumsub questionnaire, Bridge individuals, Stripe v2 Person
  • §3 now says /verification/requirements is a thin proxy over Sumsub's requiredIdDocs rather than a Grid-maintained matrix. New open question about live-hit vs. TTL cache
  • §6 CSV rewrite — no vendor uses _1/_2 suffix columns. Three-path recommendation: (A) existing /bulk/csv stays as-is for flat individuals, optionally with HubSpot-style semicolon-delimited scalar-array cells; (B) new JSON POST /customers/bulk for anything nested; (C) docs always pre-uploaded via POST /documents, referenced by documentId — never inline base64
  • §6 docs approach — pre-upload only, no inline base64. Sumsub/Bridge/Stripe all do upload-and-return-ID; our existing POST /documents is fine and 10 MB per file is enough

Open questions now 8, mostly re-scoped:

  1. EDD-field completeness — anything crypto-specific / pilot-customer-specific we should add day one?
  2. identification.idType enum expansion — cross-check with Sumsub's requiredIdDocs vocabulary
  3. contactVerification before KYC — product question deferred; two options laid out
  4. HubSpot-style semicolon multi-value cells for scalar EDD fields in the existing CSV, or JSON-only for EDD?
  5. Bulk cap (placeholder 1000, sort out later)
  6. Do we need POST /documents/bulk? (Leaning no — no vendor offers this)
  7. /verification/requirements — live Sumsub hit vs local TTL cache?
  8. Chicken-and-egg on documentIds at customer creation — two options laid out

Diff: +228 / −120 lines. Full doc is a single-commit revision on the branch; scan the file diff for anything I missed.

@ls-bolt

ls-bolt Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

⚡ On it — 7 new inline replies to work through. Kicking off research on the empirical questions (how the existing /customers/bulk/csv flow actually handles data + docs, storage semantics, LexisNexis pass-through, where Sumsub accepts SSN/ITIN, and how existing customer phone verification is wired). Also trimming §1a EDD extras per your "request minimum info" guidance, renaming /customers/bulk/customers/bulk/json to mirror /bulk/csv, and locking in the cached-requirements design in §3. I'll push updates and reply on each thread.

@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from 579a58f to d3c64b0 Compare July 21, 2026 15:32
@ls-bolt

ls-bolt Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Revision 3

Addressed all 7 new threads. Replies inline; here's the diff at a glance.

Applied Aaron's direct guidance:

  • Aggressively trimmed §1 — removed countryOfResidence, mailingAddress, occupation, employer, sourceOfFundsCategories, purposeOfAccount, expectedMonthlyTransaction*. Only new field on IndividualCustomerFields is identification[]. Screenshot of the Lead Bank retail-KYC requirements confirmed none of the trimmed fields are needed today.
  • Removed §1a (EDD extras) entirely — replaced with a one-paragraph deferral note. Design stays additive-only so any of those fields can slot in per-jurisdiction if an HNWI segment materializes.
  • Renamed POST /customers/bulkPOST /customers/bulk/json to mirror /customers/bulk/csv. Updated throughout.
  • §3 cache design locked in — 24 h TTL default, explicit invalidation endpoint tied to Sumsub-config-change admin workflow, feature-flag knob to bypass.
  • CSV-first, JSON only when needed — §6 now says individual customers stay in CSV even for the NRA 2-ID case (semicolon-delimited or a scalar column pair); JSON only for genuinely nested data (BOs, doc refs).

Applied backend research findings (dug into webdev/sparkcore — added a "Current-state facts" block to the recap):

  • Existing POST /customers/bulk/csv handler is a stub — raises GridException(NOT_IMPLEMENTED). So we're implementing bulk CSV as part of this design, not extending working code. This is material context for the "how does existing CSV handle X" questions.
  • PII is stored long-term in Grid's DB (not proxy-only) — EntUmaaasIndividualUserInfo (individual), EntGridBusinessInformation (business), EntUmaaasUser (status + lexisnexis_alert_id). Document metadata persists; binary bytes only go to Sumsub.
  • Both Sumsub AND LexisNexis are in use — Sumsub for KYC/KYB (applicant, docs, hosted link, verification); LexisNexis for OFAC/sanction screening only. Split is switch-specific: LSP invokes LexisNexis; Striga / Bitso / Sandbox skip.
  • POST /customers doesn't send OTPs — initializes contact-verification state to PENDING only if the switch requires it. Explicit verify-email / verify-phone endpoints drive OTPs on demand.
  • Only Striga requires contact verification pre-KYC — every other switch defaults to no requirement. Aaron's instinct on thread Fix mobile styling #11 was right.

Applied Sumsub API research (thread #10):

  • SSN/ITIN maps to Sumsub's tin field on fixedInfo, not a document type. US format ###-##-####. Non-Doc TIN check uses inputDoc.idDocType: "TAX_PAYER_NUMBER_DOC".
  • Sumsub's doc-upload idDocType uses DRIVERS, ID_CARD, RESIDENCE_PERMIT, PASSPORT (shorter names than my proposal). Open question in doc: mirror those or keep the longer names for clarity.
  • Public enum stays user-facing (SSN | ITIN | EIN | NON_US_TAX_ID + additions); internal mapping to Sumsub's tin is our concern, not the platform's.

Open questions now 5 (down from 8):

  1. identification.idType vocabulary — mirror Sumsub short names vs. longer names?
  2. NRA 2-ID rule — how to express in /verification/requirements + VerificationError?
  3. contactVerification — product call on self-attest vs. Striga's compliance requirements
  4. POST /documents bulk mode — needed or not?
  5. documentIds chicken-and-egg — pre-upload with PENDING:<platformCustomerId> holder tag vs. holderless upload

Diff: +50 / −107 lines. Doc is now 474 lines (down from 531), which is a good sign given how much research I folded in.

@ls-bolt

ls-bolt Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

⚡ On it — 5 new replies. Substantive design points I'll be addressing:

  1. Split identification[] into tax-IDs vs photo-IDs — you're right, they're different categories (tax = fixedInfo.tin in Sumsub, photo = doc upload). Restructuring §1.
  2. Restore HNWI fields as optional — the schema should carry them so platforms can pre-send; discovery endpoint / Sumsub's requiredIdDocs decides when they're actually required. Reverting my aggressive R3 trim.
  3. CSV vs JSON design question — investigating who added the CSV endpoint stub + laying out the tradeoffs of JSON-only vs keeping both.
  4. Doc upload path + TTL — investigating whether uploads stream direct to Sumsub or buffer in Grid, and whether there's a TTL on orphaned docs.
  5. Cache "sounds good" — 👍 will just acknowledge.

Firing research on #3 and #4 in parallel, doing #1, #2, #5 in the doc immediately.

@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from d3c64b0 to f8d2128 Compare July 21, 2026 16:05
@ls-bolt

ls-bolt Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Revision 4

Addressed all 5 new threads. Replies inline; here's the diff at a glance.

Applied direct guidance:

  • Split identification[]taxIdentification[] (customer) + photo-ID numbers on Document — per your point that tax IDs (SSN/ITIN/etc.) and photo IDs (passport/DL) are genuinely different categories, not interchangeable. Mirrors how Sumsub itself models the split (fixedInfo.tin vs. idDocType doc uploads). IdentificationType enum stays exactly as-is today; no photo-ID _NUMBER types added.
  • Restored EDD extras as optional (§1a) — reverted the aggressive R3 trim. sourceOfFundsCategories, sourceOfWealth, purposeOfAccount, expectedMonthlyTransaction*, annualIncomeRange, netWorthRange, pepStatus are back on IndividualCustomerFields as optional. Schema accepts them freely; /verification/requirements (backed by Sumsub's requiredIdDocs + Grid overlays) says when they're BLOCKING; POST /verifications returns MISSING_FIELD when required-and-missing. Answers your "how do we trigger HNWI?" question: Sumsub tells us per-applicant.

Applied backend research findings (added to "Current-state facts" recap):

  • POST /documents is synchronous and direct-to-Sumsub. No S3, no temp buffer, no async queue. Handler does file.read(), creates the DB row, forwards multipart to Sumsub in the same request.
  • No TTL on documents. EntGridDocument has no expires_at / status / auto-deleted_at. Retention is explicit DELETE only (soft-deletes locally + inactivates Sumsub-side image).
  • Docs require document_holder_id at creation — no orphan-doc concept today. Makes the chicken-and-egg on documentIds at customer creation (open question Fix card columns on overview #5) concrete rather than hypothetical.

Applied git-history finding:

  • CSV bulk endpoint was in the initial Grid schema commit (Jeremy Klein, 2025-10-10). Spec-only for ~9 months; never had a backend. Which makes the "just go JSON" question much more open — added as open question fix tip formatting #4 with three options (keep both / JSON-only / JSON + YAML/TOML). Leaning JSON-only unless we hear a platform-migration team specifically needs CSV as an upload format.

Open questions now 5 (unchanged count, but re-scoped by R4):

  1. NRA 2-ID rule — how to express as a compound requirement in /verification/requirements + VerificationError?
  2. contactVerification — product call on Striga self-attest vs. requiring OTP through us
  3. POST /documents/bulk — needed or not?
  4. NEW: Keep both /bulk/csv + /bulk/json, or JSON-only?
  5. documentIds chicken-and-egg — PENDING:<platformCustomerId> holder tag vs. holderless upload
  6. NEW (implied by TTL finding): Do we want an auto-GC for orphaned bulk-migration docs, or is manual DELETE sufficient?

Doc grew by +65/-19 lines net vs R3 (up to 520 lines total).

@akanter akanter left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's really clean up the doc and make it nice and easy to read with the questions clearly called out. Also, as far as implementation goes we'll definitely want to get the single customer flow working first and then we'll layer on bulk.

Probably update the PR description too

Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
@ls-bolt

ls-bolt Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

⚡ On it — reading you loud and clear. Doing a full cleanup pass on the doc:

  • Killing all revision annotations / "resolved from vN" / historical decision context
  • Dropping "sketch" framing
  • Going JSON-only (dropping CSV path per your call)
  • Restructuring around singleton-first, then bulk
  • Addressing the doc-caching design question directly — since Sumsub requires applicant_id at doc-upload time (yes, confirming — can't rebind), this is a real design constraint we need to lay out clearly
  • Skipping self-attest flag
  • Removing extraneous inline comments you flagged for deletion

Rewriting rather than surgical-editing since the meta-ask is "make it clean for Victor to review". Will push and reply on each thread.

@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from f8d2128 to 94ae43e Compare July 21, 2026 20:14
@ls-bolt

ls-bolt Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Full doc rewrite — clean review document, ready for Victor and team.

Down from 520 to 301 lines. Removed all revision annotations, historical decision context, and per-reviewer callouts. No "sketch" framing.

Structural changes:

  • Fresh outline: Context → Design goals → Design principles → What exists today → Proposed changes (§1 through §6) → Walkthroughs (singleton first, then bulk) → Design decisions still open → Implementation phasing
  • JSON-only bulk migrationPOST /customers/bulk/csv dropped from the design
  • sourceOfWealthsourceOfWealthCategories as an array (matching sourceOfFundsCategories)
  • Singleton-first implementation priority stated explicitly in the phasing section
  • §6 Document upload strategy — direct Sumsub constraint stated first ("cannot pre-upload documents before the customer exists" because Sumsub requires applicant_id at upload time and doesn't support rebinding); four patterns (A/B/C/D) laid out; Pattern D (Grid-side doc caching) called out as an open design decision needing product/compliance input, not proposed for initial implementation
  • Contact-verification / self-attest / Striga discussion dropped
  • All "Resolved from vN" lists removed; open questions is 5 items, all actually open

Substantive additions:

  • Sumsub doc-rebinding limitation stated as the core constraint shaping the upload strategy
  • Pattern D (doc caching) with concrete trade-off analysis (legal custodian, cost, TTL)
  • "Some platforms don't store their end-users' documents" acknowledged

Threads with new activity all replied to inline. Ready for Victor's review whenever you want to hand off.

Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md
@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from 94ae43e to d88cc21 Compare July 22, 2026 19:14
@ls-bolt ls-bolt Bot mentioned this pull request Jul 22, 2026
@ls-bolt

ls-bolt Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Started Phase 1 implementation on a separate stack per your ask — plan up as grid-api#726.

Focus: taxIdentification[] schema + backend, and post-KYC OFAC screening (which the investigation confirms is a genuine gap — screening runs at create-time and on a 30-day rescreen batch for LSP customers today, but not on KYC approval).

Full plan and LexisNexis findings on that PR. This design doc PR stays as-is.

@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from d88cc21 to df5f38e Compare July 22, 2026 20:39
@ls-bolt

ls-bolt Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Added sandbox to the design doc. Three additions:

  1. Design goals — new bullet making sandbox a first-class requirement.
  2. What exists today — new "Sandbox surface" subsection documenting the existing magic-value pattern (KYB via registrationNumber last-3-digits, BO KYC via lastName last-3-chars) and calling out the gap (no analogous pattern for individual-customer KYC today).
  3. New §7 Sandbox mode — full design:
    • Magic values: last 3 chars of fullName on POST /customers001 PENDING / 002 REJECTED / else APPROVED, mirroring the existing BO KYC pattern.
    • Per-piece sandbox behavior for each proposed change (§1 taxIdentification[], §1a EDD extras, §2 VerificationError, §3 /verification/requirements, §5 submitForVerification, §4 bulk).
    • Explicit "what sandbox does NOT do" list (no Sumsub, no LexisNexis, no real doc processing, but webhooks DO fire so integrators can test their handlers).
    • Documentation update note — existing sandbox-kyb-verification.mdx grows a third subsection; consider renaming to reflect expanded scope.

+44 lines net (301 → 345). Once you sign off on the sandbox design, I'll come back to the plan PR (#726) and rework Phase 1 to include the sandbox implementation alongside taxIdentification[] (and drop the LexisNexis content per your earlier note).

@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from df5f38e to 7daf744 Compare July 22, 2026 21:13
@ls-bolt

ls-bolt Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Reworked the "Implementation phasing" section for the new API + sandbox first, production wire-up progressively strategy.

New phasing:

  1. Phase 1 — API surface + sandbox behavior (ship ASAP). Singleton scope: §1 taxIdentification, §1a EDD extras, §2 VerificationError enhancements, §3 /verification/requirements, §5 submitForVerification flag, and §7 sandbox magic values. All schema-locked; sandbox switch resolves outcomes deterministically without calling Sumsub or LexisNexis. Customers integrate against sandbox immediately.

  2. Phase 2 — Production wire-up (progressive, per piece, no API changes). Fill in real vendor behavior behind the Phase 1 API. Order flexible — each item independent: Sumsub fixedInfo.tin mapping, real Sumsub applicant/doc submission, /verification/requirements cache backed by real requiredIdDocs, VerificationError.code/.constraint wired to real Sumsub reasons.

  3. Phase 3 — Bulk. §4 POST /customers/bulk/json once singleton is validated in production.

  4. Phase 4 — Document caching / Pattern D. Only if product & compliance sign off.

Key point I made explicit in the intro to the section: the API contract is locked once Phase 1 ships, so Phase 2 production wire-up doesn't change what platforms see — their existing sandbox integrations just start working against real vendors.

+19 / -3 lines net. Doc now 361 lines total.

Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from 7daf744 to 8745715 Compare July 22, 2026 21:31
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch 2 times, most recently from c59c0e9 to 514734d Compare July 22, 2026 21:47
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from 514734d to 2fdc8b6 Compare July 22, 2026 21:59
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch 2 times, most recently from 8f7fd92 to 32b3d72 Compare July 23, 2026 01:16
@ls-bolt

ls-bolt Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Applied all 6 changes. R13 pushed (343 lines, +101/-137 net — significant simplification).

Changes:

  1. §5 submitForVerification removed entirely. New brief note replaces the section explaining why (return-type polymorphism, customers don't materially benefit, keeping endpoints separate keeps every response type predictable).

  2. §3 GET /verification/requirements removed. Replaced with a "requirements discovery via documentation, not an endpoint" section — platforms build against the documented per-jurisdiction / per-currency matrix in Mintlify docs, submit what they have, iterate on errors[] from POST /verifications. Same feedback loop as today, no new endpoint or cache to maintain.

  3. §7 Sandbox EDD trigger added. New 003 suffix on fullNamePOST /verifications returns RESOLVE_ERRORS with MISSING_FIELD errors on edd.* fields. Platform calls POST /customers/{customerId}/edd and retries. Full example flow in the section.

  4. §1a EDD fields moved to a separate resource. New POST /customers/{customerId}/edd, GET, PATCH. Response envelope wraps just the EDD fields; nothing on the base customer changes. Backend storage TBD (JSON blob on EntUmaaasIndividualUserInfo for low cost vs. dedicated EntUmaaasCustomerEdd ent for querying).

  5. §1 taxIdentification simplified from array to single object. Dropped the multi-jurisdictional-taxpayer array with a note that we can revisit if real demand shows up.

  6. §2 VerificationError.code removed — you're right, the existing VerificationErrorType enum (MISSING_FIELD, INVALID_FIELD, MISSING_IDENTITY_DOCUMENT, POOR_QUALITY_DOCUMENT, etc.) already categorizes errors so platforms can route programmatically off type. Kept constraint (regex / enum / length metadata) since that adds real value for pre-validation.

Also touched (for consistency):

  • Design goals — dropped the "pre-flight discover fields" goal, tweaked the errors-shape and sandbox goals.
  • Singleton walkthrough — removed submitForVerification and GET /verification/requirements calls; example now goes POST /customersPOST /verifications → iterate on errors.
  • Bulk walkthrough — same cleanup.
  • Implementation phasing — Phase 1 rewritten around the new scope: 4 grid-api items + 4 sparkcore backend items (down from 6+6). Phase 2 gets an EDD-required signal item alongside the existing tax-ID and constraint items.

Doc structure otherwise stable. R14 will follow on grid-api#726 with the implementation changes to match: revert submitForVerification schema + response wrapper, revert code on VerificationError, remove EDD fields from IndividualCustomerFields, change taxIdentification from array to single object, add the POST /customers/{customerId}/edd endpoint spec.

@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch 2 times, most recently from 1dc9983 to 6730a58 Compare July 23, 2026 02:16
Comment thread docs/plans/2026-07-18-kyc-api-design.md Outdated
@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from 6730a58 to d7cc081 Compare July 23, 2026 02:30
@ls-bolt

ls-bolt Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

R16 — meta-reference audit

Following up on Aaron's line-104 thread about format-level constraint guidance belonging on 400 responses (not on VerificationError) — went back and audited the whole doc for the same "reads like a revision log, not a design doc" pattern I keep slipping into.

Structural:

  • Deleted §3 (Requirements discovery — via docs, not endpoint) and §5 (Verification submission — separate call) in full. Both existed only to explain what was NOT being shipped.
  • Renumbered §4 → §3 (Bulk migration), §6 → §4 (Documentation caching), §7 → §5 (Sandbox). Updated all three cross-references.

Prose:

  • §2 header: dropped the "(not on VerificationError)" parenthetical — it now just says "Machine-readable validation on 400 responses" and the section body describes the design directly.
  • 4 other meta spots cleaned: IdentificationType stays as it is todayuses the existing enum; replacing what would have been the GET /verification/requirements endpoint (x2) → describes the docs directly; no changes to Error400.yaml / no changes to VerificationError.yaml → dropped.

Result: 337 lines (down 15). Reads without needing prior-revision context.

Also did the same audit pass on the plan doc in #726 — cleaned the one remaining meta on §2's line 14.


🤖 staking-corona(#6) | Feedback

@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch 2 times, most recently from 1042fb8 to b34e79f Compare July 23, 2026 09:09
@ls-bolt
ls-bolt Bot force-pushed the 07-18-kyc-api-design branch from b34e79f to 637cf7c Compare July 24, 2026 05:05
@ls-bolt

ls-bolt Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

R19 — applied @akanter's 07-21 review

Four asks, four responses:

1. Clean up the doc / nice and easy to read. Rewrote the structure to be singleton-first:

  • Bulk migration moved from §3 (middle of the doc) to Appendix A at the end.
  • §4 Document upload strategy simplified to Patterns A + B only (single-customer flow); bulk-related Patterns C + D relocated to Appendix A alongside the endpoint spec and walkthrough.
  • Renumbered so the main body is §1 → §1a → §2 → §3 (Document upload) → §4 (Sandbox). No mid-doc "future work" callouts breaking up the Phase 1 story.

2. Questions clearly called out. New "Open questions for Phase 1" section right after "Design goals" (line 21), with each question carrying a proposed default so silence = proceed:

  • /customers/edd vs Bridge-style /customers/endorsements (from Jeremy's raise, active in Slack).
  • PurposeOfAccount — need an IndividualPurposeOfAccount alongside the existing (business) enum?
  • EDD backend storage — JSON blob on EntUmaaasIndividualUserInfo vs dedicated EntUmaaasCustomerEdd ent?

Bulk-only open questions stay in Appendix A under "Open questions for the bulk workstream."

3. Single customer flow first, layer bulk on later. Main body (§1–§4 + Walkthrough + Implementation phasing) covers only the interactive singleton flow. Everything bulk-shaped lives in Appendix A, marked "deferred; future work." Phase 1 items in the phasing section are all singleton; Phase 2 is production wire-up of the same singleton API.

4. PR description updated. Now leads with a "Reading guide" that points readers at the sections top-down and calls out where the open questions live.

Doc line count: 345 (up 5 from R18 despite adding the Open Questions section — Appendix A + reading structure netted out).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant