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..4e1827fe 100644 --- a/mintlify/snippets/sandbox-verification.mdx +++ b/mintlify/snippets/sandbox-verification.mdx @@ -2,67 +2,121 @@ 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`: - -| 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 | - -EDD flow example: - -```bash -# Create a customer whose fullName ends in "003" to trigger the EDD path -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", - "birthDate": "1990-01-15", - "nationality": "US", - "address": { "line1": "123 Main St", "city": "Seattle", "state": "WA", "postalCode": "98101", "country": "US" } - }' - -# First verification attempt: returns MISSING_FIELD errors on edd.* fields -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 -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" - }' - -# Retry verification — now approves -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:..." }' +The **last 3 characters** of the `fullName` on `POST /customers` (with `customerType: INDIVIDUAL`) determine the customer's `kycStatus` **immediately at creation**: + +| 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 | + +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: + + + + 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) -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 | |--------|------------|----------|