Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions mintlify/snippets/kyc/kyc-unregulated.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -66,7 +66,7 @@ The response always includes `kycUrl` for the hosted flow. For providers that su

<Steps>
<Step title="Create the customer">
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.
</Step>

<Step title="Verify contact channels (only where required)">
Expand Down Expand Up @@ -125,7 +125,11 @@ The shape of the flow depends on the customer type:
<Tab title="KYC (individual)">
<Steps>
<Step title="Create the customer with personal information">
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.

<Note>
`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.
</Note>

```bash
curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \
Expand Down Expand Up @@ -153,8 +157,8 @@ The shape of the flow depends on the customer type:
</Note>
</Step>

<Step title="Upload supporting documents (if requested)">
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`.
<Step title="Upload the identity document">
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" \
Expand Down Expand Up @@ -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"
Expand Down
160 changes: 107 additions & 53 deletions mintlify/snippets/sandbox-verification.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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:

<Steps>
<Step title="Create a customer with a 001 suffix">
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"
}'
```
</Step>

<Step title="Submit for verification">
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:..." }'
```
</Step>

<Step title="Supply the missing fields and document">
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"
```
</Step>

<Step title="Resubmit">
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:..." }'
```
</Step>
</Steps>

### 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 |
|--------|------------|----------|
Expand Down
Loading