From 08f46c77fc0f8f1231f96526a43d81444090d8a8 Mon Sep 17 00:00:00 2001 From: Aaron Kanter Date: Tue, 11 Aug 2026 16:16:33 +0200 Subject: [PATCH 1/2] docs(kyc): align sandbox verification and onboarding docs with implemented behavior The sandbox suffix tables described a design that never shipped. Verified against dev and prod (2026-08-11) and corrected: - Individual suffixes resolve kycStatus AT CREATION (001 PENDING / 002 REJECTED / 003 UNVERIFIED / other APPROVED); terminal suffixes make POST /verifications return 400, so only 001 and 003 are submittable. - The 003 suffix simulates a correctable provider rejection (POOR_QUALITY_DOCUMENT), not an EDD MISSING_FIELD flow; replaced the fictional edd.* example with the verified fix-and-resubmit loop. - Business customers are created UNVERIFIED and resolve on submission; 002/other skip validation entirely, 001/003 go through full KYB validation. Responses use kybStatus. - BO suffixes resolve when the owning business resolves via its suffix. - Individual verification requires an identity document (PASSPORT single image, DRIVERS_LICENSE/NATIONAL_ID front+back) and taxIdType/taxIdentifier; the docs called documents optional. - kycStatus starts UNVERIFIED (docs said PENDING). - fullName must parse into given + family name; single-word names are refused at submission. Co-Authored-By: Claude Fable 5 --- mintlify/snippets/kyc/kyc-unregulated.mdx | 20 +++-- mintlify/snippets/sandbox-verification.mdx | 85 +++++++++++++++------- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/mintlify/snippets/kyc/kyc-unregulated.mdx b/mintlify/snippets/kyc/kyc-unregulated.mdx index 27bc8a59..5fecc17a 100644 --- a/mintlify/snippets/kyc/kyc-unregulated.mdx +++ b/mintlify/snippets/kyc/kyc-unregulated.mdx @@ -13,7 +13,7 @@ Either path works for unregulated platforms: The hosted KYC flow provides a secure, hosted interface where customers can complete their identity verification and onboarding process. -The flow is two steps: create the customer with the information you have, then generate a hosted KYC link for that customer. The customer's `kycStatus` stays `PENDING` until they complete the hosted flow. +The flow is two steps: create the customer with the information you have, then generate a hosted KYC link for that customer. The customer's `kycStatus` starts at `UNVERIFIED` and moves to `PENDING` once they complete the hosted flow and review begins. #### 1. Create the customer @@ -66,7 +66,7 @@ The response always includes `kycUrl` for the hosted flow. For providers that su - Call `POST /customers` with `customerType` and any pre-fill fields you have. The returned `id` is the customer's Grid ID; their `kycStatus` is `PENDING` until verification completes. + Call `POST /customers` with `customerType` and any pre-fill fields you have. The returned `id` is the customer's Grid ID; their `kycStatus` starts at `UNVERIFIED`, becomes `PENDING` while under review, and lands on `APPROVED` or `REJECTED` when the decision is made. @@ -125,7 +125,11 @@ The shape of the flow depends on the customer type: - Call `POST /customers` with `customerType: INDIVIDUAL` and the personal information collected from the customer (legal name, date of birth, address, nationality, etc.). The returned `id` is the customer's Grid ID; `kycStatus` starts at `PENDING`. + Call `POST /customers` with `customerType: INDIVIDUAL` and the personal information collected from the customer (legal name, date of birth, address, nationality, etc.). The returned `id` is the customer's Grid ID; `kycStatus` starts at `UNVERIFIED` and moves to `PENDING` once you submit for verification. + + + `fullName` must contain both a given name and a family name (for example, `"Jane Doe"`). The name is split into first/last for the verification provider, and a single-word name is rejected at submission. + ```bash curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \ @@ -153,8 +157,8 @@ The shape of the flow depends on the customer type: - - Some jurisdictions or currencies require an ID document or proof of address. Upload them with `POST /documents` using `multipart/form-data`, referencing the customer by `customerId`. + + Individual verification requires an identity document — a `PASSPORT` (single image), or a `DRIVERS_LICENSE` / `NATIONAL_ID` (uploaded as separate `FRONT` and `BACK` images via the `side` field). Some jurisdictions or currencies also request additional documents such as proof of address. Upload each one with `POST /documents` using `multipart/form-data`; identity documents also require `documentNumber` and `issuingAuthority`. ```bash curl -X POST "https://api.lightspark.com/grid/2025-10-13/documents" \ @@ -202,9 +206,9 @@ The shape of the flow depends on the customer type: "errors": [ { "resourceId": "Customer:019542f5-b3e7-1d02-0000-000000000001", - "type": "MISSING_PROOF_OF_ADDRESS_DOCUMENT", - "acceptedDocumentTypes": ["PROOF_OF_ADDRESS"], - "reason": "Proof of address document is required" + "type": "MISSING_IDENTITY_DOCUMENT", + "acceptedDocumentTypes": ["PASSPORT", "DRIVERS_LICENSE", "NATIONAL_ID"], + "reason": "Identity document is required" } ], "createdAt": "2025-10-03T12:00:00Z" diff --git a/mintlify/snippets/sandbox-verification.mdx b/mintlify/snippets/sandbox-verification.mdx index 94eaff9a..9dd65843 100644 --- a/mintlify/snippets/sandbox-verification.mdx +++ b/mintlify/snippets/sandbox-verification.mdx @@ -2,48 +2,81 @@ In sandbox, you can trigger specific KYC/KYB verification outcomes using magic s ### Individual customer verification (KYC) -The **last 3 characters** of the `fullName` on `POST /customers` (with `customerType: INDIVIDUAL`) determine the outcome when you call `POST /verifications`: +The **last 3 characters** of the `fullName` on `POST /customers` (with `customerType: INDIVIDUAL`) determine the customer's `kycStatus` **immediately at creation**: -| Suffix | Outcome | Behavior | -|--------|---------|----------| -| **001** | `verificationStatus: IN_PROGRESS`, `kycStatus: PENDING` | KYC verification remains pending (manual review) | -| **002** | `verificationStatus: REJECTED`, `kycStatus: REJECTED` | KYC verification is rejected | -| **003** | `verificationStatus: RESOLVE_ERRORS` with `MISSING_FIELD` errors on `edd.*` fields | EDD is required — call `PATCH /customers/{customerId}` with the requested fields, then retry `POST /verifications` | -| **Any other** | `verificationStatus: IN_PROGRESS`, `kycStatus: APPROVED` | KYC verification is approved | +| Suffix | `kycStatus` at creation | Behavior on `POST /verifications` | +|--------|-------------------------|-----------------------------------| +| **001** | `PENDING` | With complete data and an identity document: `verificationStatus: PENDING_MANUAL_REVIEW` — simulates an applicant waiting on manual review | +| **002** | `REJECTED` | Returns `400` — the customer was terminally rejected at creation | +| **003** | `UNVERIFIED` | With complete data: `verificationStatus: RESOLVE_ERRORS` with a `POOR_QUALITY_DOCUMENT` error — simulates a correctable provider rejection | +| **Any other** | `APPROVED` | Returns `400` — the customer was approved at creation | -EDD flow example: +Because terminal suffixes resolve at creation, only `001` and `003` customers can be submitted for verification. Use any non-suffixed name to mint ready-to-transact approved customers, and a `001` name to exercise the full submission flow. + +Submitting for verification has the same data requirements as production: full name, birth date, nationality, `taxIdType` + `taxIdentifier`, address, and an identity document uploaded via `POST /documents`. Anything missing comes back as `verificationStatus: RESOLVE_ERRORS` with one entry per problem in `errors`: + +```json +{ + "verificationStatus": "RESOLVE_ERRORS", + "errors": [ + { + "resourceId": "Customer:019542f5-b3e7-1d02-0000-000000000001", + "type": "MISSING_FIELD", + "field": "taxIdentifier", + "reason": "Tax identifier is required" + }, + { + "resourceId": "Customer:019542f5-b3e7-1d02-0000-000000000001", + "type": "MISSING_IDENTITY_DOCUMENT", + "acceptedDocumentTypes": ["PASSPORT", "DRIVERS_LICENSE", "NATIONAL_ID"], + "reason": "Identity document is required" + } + ] +} +``` + +Fix-and-resubmit example — the standard integration loop: ```bash -# Create a customer whose fullName ends in "003" to trigger the EDD path +# 1. Create a customer whose fullName ends in "001" (stays PENDING, submission allowed) curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \ -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "customerType": "INDIVIDUAL", - "fullName": "Jane Doe 003", + "fullName": "Jane Doe 001", "birthDate": "1990-01-15", - "nationality": "US", - "address": { "line1": "123 Main St", "city": "Seattle", "state": "WA", "postalCode": "98101", "country": "US" } + "nationality": "US" }' -# First verification attempt: returns MISSING_FIELD errors on edd.* fields +# 2. First verification attempt: RESOLVE_ERRORS lists every missing field and document curl -X POST "https://api.lightspark.com/grid/2025-10-13/verifications" \ -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "customerId": "Customer:..." }' -# Supply the EDD fields via PATCH +# 3. Supply the missing fields... curl -X PATCH "https://api.lightspark.com/grid/2025-10-13/customers/Customer:..." \ -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "customerType": "INDIVIDUAL", - "sourceOfWealthCategories": ["SALARY"], - "purposeOfAccount": "P2P_TRANSFERS", - "annualIncomeRange": "RANGE_100K_250K" + "taxIdType": "SSN", + "taxIdentifier": "111-22-3333", + "address": { "line1": "123 Main St", "city": "Seattle", "state": "WA", "postalCode": "98101", "country": "US" } }' -# Retry verification — now approves +# ...and the identity document (any JPEG, PNG, or PDF works in sandbox) +curl -X POST "https://api.lightspark.com/grid/2025-10-13/documents" \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -F "documentHolder=Customer:..." \ + -F "documentType=PASSPORT" \ + -F "country=US" \ + -F "documentNumber=A12345678" \ + -F "issuingAuthority=U.S. Department of State" \ + -F "file=@./passport.jpg" + +# 4. Resubmit — now advances to PENDING_MANUAL_REVIEW curl -X POST "https://api.lightspark.com/grid/2025-10-13/verifications" \ -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ -H "Content-Type: application/json" \ @@ -52,17 +85,19 @@ curl -X POST "https://api.lightspark.com/grid/2025-10-13/verifications" \ ### Business customer verification (KYB) -The **last 3 digits** of the `registrationNumber` in `businessInfo` determine the KYB status outcome when you call `POST /verifications`: +Business customers are always created with `kybStatus: UNVERIFIED` — their suffix applies when you call `POST /verifications`, not at creation. The **last 3 characters** of the `registrationNumber` in `businessInfo` determine the outcome: -| Suffix | `kybStatus` | Behavior | -|--------|------------|----------| -| **001** | `PENDING` | KYB verification remains pending | -| **002** | `REJECTED` | KYB verification is rejected | -| **Any other** | `APPROVED` | KYB verification is approved | +| Suffix | Outcome on `POST /verifications` | +|--------|----------------------------------| +| **002** | `kybStatus: REJECTED`, `verificationStatus: REJECTED` — immediate, skips data and document validation | +| **001** / **003** | Normal validation applies: complete business information, business documents, and at least one beneficial owner are required (`RESOLVE_ERRORS` otherwise); a complete submission stays `PENDING` | +| **Any other** | `kybStatus: APPROVED`, `verificationStatus: APPROVED` — immediate, skips data and document validation | + +Once a business customer is approved or rejected, further `POST /verifications` calls return `400`. ### Beneficial owner KYC -The **last 3 characters** of the `lastName` in `personalInfo` determine the individual KYC status outcome: +When a business customer resolves terminally through its registration-number suffix, each of its beneficial owners is resolved at the same moment using the **last 3 characters** of the `lastName` in that owner's `personalInfo`: | Suffix | `kycStatus` | Behavior | |--------|------------|----------| From 8a10d22c9801c7b4096f86806786e41feceabe3c Mon Sep 17 00:00:00 2001 From: Aaron Kanter Date: Tue, 11 Aug 2026 16:41:54 +0200 Subject: [PATCH 2/2] Restructure sandbox fix-and-resubmit example into Steps components Co-Authored-By: Claude Fable 5 --- mintlify/snippets/sandbox-verification.mdx | 109 ++++++++++++--------- 1 file changed, 64 insertions(+), 45 deletions(-) diff --git a/mintlify/snippets/sandbox-verification.mdx b/mintlify/snippets/sandbox-verification.mdx index 9dd65843..4e1827fe 100644 --- a/mintlify/snippets/sandbox-verification.mdx +++ b/mintlify/snippets/sandbox-verification.mdx @@ -37,51 +37,70 @@ Submitting for verification has the same data requirements as production: full n Fix-and-resubmit example — the standard integration loop: -```bash -# 1. Create a customer whose fullName ends in "001" (stays PENDING, submission allowed) -curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H "Content-Type: application/json" \ - -d '{ - "customerType": "INDIVIDUAL", - "fullName": "Jane Doe 001", - "birthDate": "1990-01-15", - "nationality": "US" - }' - -# 2. First verification attempt: RESOLVE_ERRORS lists every missing field and document -curl -X POST "https://api.lightspark.com/grid/2025-10-13/verifications" \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H "Content-Type: application/json" \ - -d '{ "customerId": "Customer:..." }' - -# 3. Supply the missing fields... -curl -X PATCH "https://api.lightspark.com/grid/2025-10-13/customers/Customer:..." \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H "Content-Type: application/json" \ - -d '{ - "customerType": "INDIVIDUAL", - "taxIdType": "SSN", - "taxIdentifier": "111-22-3333", - "address": { "line1": "123 Main St", "city": "Seattle", "state": "WA", "postalCode": "98101", "country": "US" } - }' - -# ...and the identity document (any JPEG, PNG, or PDF works in sandbox) -curl -X POST "https://api.lightspark.com/grid/2025-10-13/documents" \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -F "documentHolder=Customer:..." \ - -F "documentType=PASSPORT" \ - -F "country=US" \ - -F "documentNumber=A12345678" \ - -F "issuingAuthority=U.S. Department of State" \ - -F "file=@./passport.jpg" - -# 4. Resubmit — now advances to PENDING_MANUAL_REVIEW -curl -X POST "https://api.lightspark.com/grid/2025-10-13/verifications" \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H "Content-Type: application/json" \ - -d '{ "customerId": "Customer:..." }' -``` + + + A `fullName` ending in `001` keeps the customer `PENDING`, so submission is allowed. Persist the returned `id` for the following steps. + + ```bash + curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H "Content-Type: application/json" \ + -d '{ + "customerType": "INDIVIDUAL", + "fullName": "Jane Doe 001", + "birthDate": "1990-01-15", + "nationality": "US" + }' + ``` + + + + The first attempt returns `verificationStatus: RESOLVE_ERRORS` with every missing field and document listed in `errors`. + + ```bash + curl -X POST "https://api.lightspark.com/grid/2025-10-13/verifications" \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H "Content-Type: application/json" \ + -d '{ "customerId": "Customer:..." }' + ``` + + + + Patch the missing fields onto the customer, then upload the identity document. Any JPEG, PNG, or PDF works in sandbox. + + ```bash + curl -X PATCH "https://api.lightspark.com/grid/2025-10-13/customers/Customer:..." \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H "Content-Type: application/json" \ + -d '{ + "customerType": "INDIVIDUAL", + "taxIdType": "SSN", + "taxIdentifier": "111-22-3333", + "address": { "line1": "123 Main St", "city": "Seattle", "state": "WA", "postalCode": "98101", "country": "US" } + }' + + curl -X POST "https://api.lightspark.com/grid/2025-10-13/documents" \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -F "documentHolder=Customer:..." \ + -F "documentType=PASSPORT" \ + -F "country=US" \ + -F "documentNumber=A12345678" \ + -F "issuingAuthority=U.S. Department of State" \ + -F "file=@./passport.jpg" + ``` + + + + The verification now advances to `verificationStatus: PENDING_MANUAL_REVIEW` and the customer's `kycStatus` is `PENDING`. + + ```bash + curl -X POST "https://api.lightspark.com/grid/2025-10-13/verifications" \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H "Content-Type: application/json" \ + -d '{ "customerId": "Customer:..." }' + ``` + + ### Business customer verification (KYB)