> ## Documentation Index
> Fetch the complete documentation index at: https://ramps-docs-sync-20260716.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuring Customers

> Complete guide to creating and managing customers for Bitcoin rewards

This guide covers everything you need to know about creating and managing customers in the Grid API for Bitcoin rewards distribution.

## Overview

Customers are the *payers* of your Bitcoin rewards. They can be individuals or businesses. Each customer in the Grid system has:

* **System-generated ID**: Unique identifier assigned by Grid (e.g., `Customer:019542f5-b3e7-1d02-0000-000000000001`)
* **Customer Type**: Either `INDIVIDUAL` or `BUSINESS`
* **KYC Status**: Indicates if the customer has been verified and approved.
* **Internal Accounts**: Automatically created for each supported currency upon customer creation
* **Platform Customer ID**: Optional field to link to your own user/customer ID

<Note>
  The `platformCustomerId` field is optional but recommended. Use your existing user IDs to maintain a simple mapping between your system and Grid.
</Note>

## Customer Onboarding

<AccordionGroup>
  <Accordion title="Regulated Platforms" icon="">
    <Check>
      **Regulated platforms** have lighter KYC requirements since they handle compliance verification internally.
    </Check>

    The KYC/KYB flow allows you to onboard customers through direct API calls.

    Regulated financial institutions can:

    * **Direct API Onboarding**: Create customers directly via API calls with minimal verification
    * **Internal KYC/KYB**: Handle identity verification through your own compliance systems
    * **Reduced Documentation**: Only provide essential customer information required by your payment counterparty or service provider.
    * **Faster Onboarding**: Streamlined process for known, verified customers

    #### Creating Customers via Direct API

    For regulated platforms, you can create customers directly through the API without requiring external KYC verification:

    To register a new customer in the system, use the `POST /customers` endpoint:

    ```bash theme={null}
    curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \
      -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
      -H "Content-Type: application/json" \
      -d '{
        "platformCustomerId": "customer_12345",
        "customerType": "INDIVIDUAL",
        "fullName": "Jane Doe",
        "birthDate": "1992-03-25",
        "nationality": "US",
        "address": {
          "line1": "123 Pine Street",
          "city": "Seattle",
          "state": "WA",
          "postalCode": "98101",
          "country": "US"
        }
      }'
    ```

    The examples below show a more comprehensive set of data. Not all fields are strictly required by the API for customer creation itself, but become necessary based on currency and UMA provider requirements if using UMA.

    <Tabs>
      <Tab title="Individual customer">
        ```json theme={null}
        {
          "platformCustomerId": "9f84e0c2a72c4fa",
          "customerType": "INDIVIDUAL",
          "fullName": "John Sender",
          "birthDate": "1985-06-15",
          "address": {
            "line1": "Paseo de la Reforma 222",
            "line2": "Piso 15",
            "city": "Ciudad de México",
            "state": "Ciudad de México",
            "postalCode": "06600",
            "country": "MX"
          }
        }
        ```
      </Tab>

      <Tab title="Business Customer">
        ```json theme={null}
        {
          "platformCustomerId": "b87d2e4a9c13f5b",
          "customerType": "BUSINESS",
          "businessInfo": {
            "legalName": "Acme Corporation",
            "registrationNumber": "789012345",
            "taxId": "123-45-6789",
            "incorporatedOn": "2018-03-14"
          },
          "address": {
            "line1": "456 Oak Avenue",
            "line2": "Floor 12",
            "city": "New York",
            "state": "NY",
            "postalCode": "10001",
            "country": "US"
          }
        }
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Unregulated Platforms" icon="">
    <Note>
      **Unregulated platforms** rely on Grid to run KYC for individuals and KYB for businesses. You can onboard customers either through the **hosted KYC/KYB link flow** below, or by **submitting customer data directly through the API**. Both paths produce the same `kycStatus` transitions and emit the same `CUSTOMER.KYC_APPROVED` / `CUSTOMER.KYC_REJECTED` / `CUSTOMER.KYC_PENDING` (and `CUSTOMER.KYB_*` equivalents) webhooks.
    </Note>

    Either path works for unregulated platforms:

    * **Hosted flow**: Redirect customers to a Grid-hosted link (or embed the provider SDK) for identity verification. Best when you want Grid to handle the entire collection UX.
    * **Direct API onboarding**: Collect customer information in your own UI and submit it via the API. For `INDIVIDUAL` customers (KYC), personal information goes through `POST /customers`. For `BUSINESS` customers (KYB), you also register beneficial owners via `POST /beneficial-owners`. Submit for review with `POST /verifications`.

    ### Hosted KYC Link Flow

    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.

    #### 1. Create the customer

    Create the customer with `POST /customers`, supplying at least `customerType` and any fields you already have. See [Configuring Customers](/payouts-and-b2b/onboarding/configuring-customers) for the full list of optional pre-fill fields.

    ```bash theme={null}
    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",
        "platformCustomerId": "9f84e0c2a72c4fa",
        "region": "US",
        "currencies": ["USD", "USDC"],
        "email": "jane.doe@example.com",
        "fullName": "Jane Doe"
      }'
    ```

    Persist the returned `id` (the Grid customer ID) — you'll need it for the next step.

    #### 2. Generate a KYC link

    ```bash theme={null}
    curl -X POST "https://api.lightspark.com/grid/2025-10-13/customers/Customer:019542f5-b3e7-1d02-0000-000000000001/kyc-link" \
      -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "redirectUri": "https://yourapp.com/onboarding-complete"
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "kycUrl": "https://kyc.lightspark.com/onboard/abc123def456",
      "expiresAt": "2027-01-15T14:32:00Z",
      "provider": "SUMSUB",
      "token": "_act-sbx-jwt-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    }
    ```

    <Tip>
      The response always includes `kycUrl` for the hosted flow. For providers that support direct SDK integration (currently SUMSUB), a `token` is also returned — you can pass this to the provider's web SDK to embed verification in your own UI instead of redirecting. Both paths update the customer's `kycStatus` identically.
    </Tip>

    #### Complete KYC Process

    <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.
      </Step>

      <Step title="Verify contact channels (only where required)">
        Some regions (for example, the EU) require the customer's email and/or phone to be verified before KYC can begin. When this applies, the customer carries a `contactVerification` object listing **only the channels that are required** — for example `{ "email": "PENDING", "phone": "PENDING" }`, or just `{ "email": "PENDING" }` if a provider requires email alone. When the object is absent, no contact verification is required and you can skip this step.

        For each channel that's present, drive a send-then-confirm pair (the provider delivers a one-time code by email/SMS):

        * `POST /customers/{customerId}/verify-email`, then `POST /customers/{customerId}/verify-email/confirm` with `{ "code": "..." }`
        * `POST /customers/{customerId}/verify-phone`, then `POST /customers/{customerId}/verify-phone/confirm` with `{ "code": "..." }`

        Re-POST the send endpoint to resend a code. Each channel moves `PENDING` → `VERIFIED`. (`verify-email`/`verify-phone` return `409` for a channel the provider doesn't require.)

        <Note>
          Generating the KYC link before every present channel is `VERIFIED` returns `409`.
        </Note>
      </Step>

      <Step title="Generate the KYC link">
        Call `POST /customers/{customerId}/kyc-link`. Each call returns a fresh single-use `kycUrl` and `expiresAt`; previously-issued links remain single-use but aren't invalidated.

        <Note>
          The `redirectUri` you pass is embedded in the generated `kycUrl` and is used to automatically return the customer to your application after they complete verification.
        </Note>
      </Step>

      <Step title="Send the customer through verification">
        Redirect the customer to `kycUrl`, or — if you want to embed the flow directly — initialize the provider's SDK with the returned `token`.

        <Warning>
          The hosted URL is single-use and expires at `expiresAt`. If a customer needs to retry, call the endpoint again to generate a new link.
        </Warning>
      </Step>

      <Step title="Track the decision">
        Reaching your `redirectUri` only means the customer **finished the hosted flow** — not that they were approved. Wait for the final decision in one of two ways:

        * **Webhook (recommended):** Subscribe to `CUSTOMER.KYC_APPROVED` / `CUSTOMER.KYC_REJECTED` (and `CUSTOMER.KYB_APPROVED` / `CUSTOMER.KYB_REJECTED` for business customers) to be notified when the customer reaches a terminal status. `CUSTOMER.KYC_PENDING` (and the `KYB_PENDING` sibling) also fires when the customer is submitted for review — subscribe to it as well if you want to surface an "under review" state to the customer.
        * **Polling:** Call `GET /customers/{customerId}` and inspect `kycStatus`.
      </Step>

      <Step title="Handle completion">
        On `APPROVED`, the customer is ready to transact — proceed with account setup and unlock funding. On `REJECTED`, surface the appropriate next step (for example, regenerate the link or request manual review).
      </Step>
    </Steps>

    ### Direct API Onboarding

    Prefer to collect identity information in your own UI and submit it to Grid yourself? Use the API directly instead of redirecting to a hosted link. The customer's `kycStatus` transitions the same way and you receive the same `CUSTOMER.KYC_APPROVED` / `CUSTOMER.KYC_REJECTED` / `CUSTOMER.KYC_PENDING` (and `CUSTOMER.KYB_*` equivalents) webhooks.

    The shape of the flow depends on the customer type:

    * **KYC (`INDIVIDUAL` customers)** — supply the customer's personal information through the customer endpoint. No beneficial owners are involved.
    * **KYB (`BUSINESS` customers)** — create the business customer, then register its beneficial owners, directors, and officers individually.

    <Tabs>
      <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`.

            ```bash theme={null}
            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",
                "platformCustomerId": "9f84e0c2a72c4fa",
                "fullName": "Jane Doe",
                "birthDate": "1985-06-15",
                "nationality": "US",
                "email": "jane.doe@example.com",
                "address": {
                  "line1": "123 Pine Street",
                  "city": "Seattle",
                  "state": "WA",
                  "postalCode": "98101",
                  "country": "US"
                }
              }'
            ```

            <Note>
              Where the customer's provider requires it (for example, EU customers), the customer carries a `contactVerification` object and their email and phone must be `VERIFIED` before you submit for verification. Drive each channel with the send-then-confirm pairs (`verify-email` / `verify-email/confirm` and `verify-phone` / `verify-phone/confirm`) described in the Hosted flow's "Verify email and phone" step. When `contactVerification` is absent, no contact verification is required.
            </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`.

            ```bash theme={null}
            curl -X POST "https://api.lightspark.com/grid/2025-10-13/documents" \
              -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
              -F "documentHolder=Customer:019542f5-b3e7-1d02-0000-000000000001" \
              -F "documentType=PASSPORT" \
              -F "documentNumber=A12345678" \
              -F "issuingAuthority=U.S. Department of State" \
              -F "country=US" \
              -F "file=@./passport.jpg"
            ```
          </Step>

          <Step title="Submit for verification">
            Call `POST /verifications` to submit the customer for review. The response includes a `verificationStatus`. If anything is missing, `verificationStatus` is `RESOLVE_ERRORS` and the `errors` array describes exactly what to collect before retrying.

            ```bash theme={null}
            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:019542f5-b3e7-1d02-0000-000000000001"
              }'
            ```

            **Submitted successfully:**

            ```json theme={null}
            {
              "id": "Verification:019542f5-b3e7-1d02-0000-000000000002",
              "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
              "verificationStatus": "IN_PROGRESS",
              "errors": [],
              "createdAt": "2025-10-03T12:00:00Z"
            }
            ```

            **Blocked by missing data:**

            ```json theme={null}
            {
              "id": "Verification:019542f5-b3e7-1d02-0000-000000000001",
              "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
              "verificationStatus": "RESOLVE_ERRORS",
              "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"
                }
              ],
              "createdAt": "2025-10-03T12:00:00Z"
            }
            ```
          </Step>

          <Step title="Track the decision">
            Track terminal `kycStatus` transitions via the `CUSTOMER.KYC_APPROVED` / `CUSTOMER.KYC_REJECTED` webhook (recommended) or by polling `GET /customers/{customerId}`. `CUSTOMER.KYC_PENDING` also fires when the customer is submitted for review — subscribe to it if you want to surface an "under review" state. On `APPROVED`, unlock funding and money movement.
          </Step>
        </Steps>
      </Tab>

      <Tab title="KYB (business)">
        When Grid runs KYB for a business customer, the following information and documents are collected before onboarding completes. Use this list to plan what to gather from the business — provide it via `POST /customers`, `POST /beneficial-owners`, and `POST /documents` (or through the hosted flow).

        #### Business identifying information

        * Entity full legal name
        * Doing Business As (DBA) name, if applicable
        * Physical address — the principal place of business, local office, or other physical location of the entity opening the account
        * Countries of operation
        * Identification number — U.S. taxpayer identification number, or, for a foreign business without one, alternative government-issued documentation certifying the existence of the business

        #### Ownership and control structure

        Collected for:

        * **One control person** — a single individual with significant responsibility to control, manage, or direct the legal entity, **and**
        * **All beneficial owners** — every individual who owns 25% or more of the legal entity, directly or indirectly.

        For every such individual, provide:

        * Full name
        * Date of birth
        * Address
        * Identification number, by residency:
          * **U.S. persons** — Social Security Number (SSN) or Individual Taxpayer Identification Number (ITIN)
          * **Non-U.S. persons** — one or more of: ITIN, passport number with country of issuance, alien identification card number, or another government-issued document evidencing nationality or residence and bearing a photograph or similar safeguard

        #### Required documents

        * Company formation and existence documents. For example:
          * Certificate of incorporation
          * Articles of association
        * Proof of ownership and control structure. For example:
          * Corporate organization and ownership chart
          * Shareholder agreements
          * Operating agreements
          * Register of members
          * Certification of controlling person and beneficial owners
        * Proof of address, dated within the last 3 months. For example:
          * Utility bill
          * Bank statement
          * Lease agreement
          * Official correspondence
        * Tax ID or equivalent identifying-number documents
        * For non-U.S. beneficial owners — passport plus one additional government-issued ID. For example:
          * National ID

        <Steps>
          <Step title="Create the business customer">
            Call `POST /customers` with `customerType: BUSINESS` and the business information (legal name, registration number, tax ID, registered address).

            ```bash theme={null}
            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": "BUSINESS",
                "platformCustomerId": "b87d2e4a9c13f5b",
                "businessInfo": {
                  "legalName": "Acme Corporation",
                  "registrationNumber": "789012345",
                  "taxId": "123-45-6789",
                  "incorporatedOn": "2018-03-14"
                },
                "address": {
                  "line1": "456 Oak Avenue",
                  "city": "New York",
                  "state": "NY",
                  "postalCode": "10001",
                  "country": "US"
                }
              }'
            ```
          </Step>

          <Step title="Register beneficial owners">
            Register each beneficial owner, director, or officer with `POST /beneficial-owners`. Each one is verified individually with their own personal information.

            ```bash theme={null}
            curl -X POST "https://api.lightspark.com/grid/2025-10-13/beneficial-owners" \
              -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
              -H "Content-Type: application/json" \
              -d '{
                "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
                "roles": ["DIRECTOR"],
                "ownershipPercentage": 40,
                "personalInfo": {
                  "firstName": "Jane",
                  "lastName": "Doe",
                  "birthDate": "1985-06-15",
                  "nationality": "US",
                  "address": {
                    "line1": "123 Pine Street",
                    "city": "Seattle",
                    "state": "WA",
                    "postalCode": "98101",
                    "country": "US"
                  },
                  "idType": "SSN",
                  "identifier": "123-45-6789"
                }
              }'
            ```
          </Step>

          <Step title="Upload supporting documents">
            Upload business documents (registration, articles of incorporation) and any documents required for individual beneficial owners with `POST /documents`. Reference the company by `customerId` and each owner by `beneficialOwnerId`.

            ```bash theme={null}
            curl -X POST "https://api.lightspark.com/grid/2025-10-13/documents" \
              -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
              -F "documentHolder=BeneficialOwner:019542f5-b3e7-1d02-0000-00000000abcd" \
              -F "documentType=PASSPORT" \
              -F "documentNumber=B98765432" \
              -F "issuingAuthority=U.S. Department of State" \
              -F "country=US" \
              -F "file=@./owner-passport.jpg"
            ```
          </Step>

          <Step title="Submit for verification">
            Call `POST /verifications` to submit the business for review. The response includes a `verificationStatus`. If beneficial owners, fields, or documents are missing, `verificationStatus` is `RESOLVE_ERRORS` and the `errors` array tells you exactly what to collect — note that `resourceId` may point at either the customer or a specific beneficial owner.

            ```bash theme={null}
            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:019542f5-b3e7-1d02-0000-000000000001"
              }'
            ```

            **Blocked by missing data:**

            ```json theme={null}
            {
              "id": "Verification:019542f5-b3e7-1d02-0000-000000000001",
              "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
              "verificationStatus": "RESOLVE_ERRORS",
              "errors": [
                {
                  "resourceId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
                  "type": "MISSING_FIELD",
                  "field": "customer.address.line1",
                  "reason": "Business address line 1 is required"
                },
                {
                  "resourceId": "BeneficialOwner:019542f5-b3e7-1d02-0000-000000000002",
                  "type": "MISSING_FIELD",
                  "field": "personalInfo.birthDate",
                  "reason": "Date of birth is required for beneficial owners"
                }
              ],
              "createdAt": "2025-10-03T12:00:00Z"
            }
            ```

            **Submitted successfully:**

            ```json theme={null}
            {
              "id": "Verification:019542f5-b3e7-1d02-0000-000000000002",
              "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
              "verificationStatus": "IN_PROGRESS",
              "errors": [],
              "createdAt": "2025-10-03T12:00:00Z"
            }
            ```
          </Step>

          <Step title="Track the decision">
            Track terminal `kycStatus` transitions via the `CUSTOMER.KYB_APPROVED` / `CUSTOMER.KYB_REJECTED` webhook (recommended) or by polling `GET /customers/{customerId}`. `CUSTOMER.KYB_PENDING` also fires when the business is submitted for review — subscribe to it if you want to surface an "under review" state. On `APPROVED`, unlock funding and money movement.
          </Step>
        </Steps>
      </Tab>
    </Tabs>
  </Accordion>
</AccordionGroup>

<Info>
  When a customer is created successfully, internal accounts are automatically created for each currency configured on your platform. These accounts can be used as sources or destinations for transfers.
</Info>

### Handling KYC/KYB Webhooks

After a customer completes the KYC/KYB verification process, you'll receive webhook notifications about their KYC status. These notifications are sent to your configured webhook endpoint.

<Note>
  For regulated platforms, customers are created with `APPROVED` KYC status by default.
</Note>

**Webhook Payload (sent to your endpoint):**

```json theme={null}
{
  "id": "Webhook:019542f5-b3e7-1d02-0000-000000000020",
  "type": "CUSTOMER.KYC_APPROVED",
  "timestamp": "2025-07-21T17:32:28Z",
  "data": {
    "id": "Customer:019542f5-b3e7-1d02-0000-000000000001",
    "platformCustomerId": "9f84e0c2a72c4fa",
    "customerType": "INDIVIDUAL",
    "umaAddress": "$john.doe@uma.domain.com",
    "kycStatus": "APPROVED",
    "fullName": "John Michael Doe",
    "birthDate": "1990-01-15",
    "nationality": "US",
    "address": {
      "line1": "123 Main Street",
      "line2": "Apt 4B",
      "city": "San Francisco",
      "state": "CA",
      "postalCode": "94105",
      "country": "US"
    },
    "createdAt": "2025-07-21T17:32:28Z",
    "updatedAt": "2025-07-21T17:32:28Z",
    "isDeleted": false
  }
}
```

**Webhook Headers:**

* `Content-Type: application/json`
* `X-Grid-Signature: {"v": "1", "s": "base64_signature..."}`

<ResponseField name="id" type="string" required>
  Unique identifier for this webhook delivery. Use this for idempotency to prevent processing duplicate webhooks.
</ResponseField>

<ResponseField name="type" type="string" required>
  Status-specific event type. KYC/KYB webhooks use `CUSTOMER.*` types:

  * `CUSTOMER.KYC_APPROVED`: Individual customer verification completed successfully
  * `CUSTOMER.KYC_REJECTED`: Individual customer verification was rejected
  * `CUSTOMER.KYC_PENDING`: Individual customer is awaiting review
  * `CUSTOMER.KYB_APPROVED` / `CUSTOMER.KYB_REJECTED` / `CUSTOMER.KYB_PENDING`: business equivalents (only fires for `customerType: BUSINESS`)
</ResponseField>

<ResponseField name="data" type="object" required>
  The full customer resource object, same as the corresponding `GET /customers/{id}` endpoint would return. Includes all customer fields such as `id`, `kycStatus`, `fullName`, `birthDate`, `nationality`, `address`, etc.
</ResponseField>

<Note>
  `CUSTOMER.KYC_PENDING` (or `CUSTOMER.KYB_PENDING`) fires when a customer enters `kycStatus: PENDING` (for example, after they are submitted for review). Final outcomes use `CUSTOMER.KYC_APPROVED` / `CUSTOMER.KYC_REJECTED` (and the `CUSTOMER.KYB_*` siblings for business customers).
</Note>

<Accordion title="Webhook Implementation Example">
  ```javascript theme={null}
  // Example webhook handler for KYC status updates.
  // CUSTOMER.KYC_APPROVED and CUSTOMER.KYC_REJECTED are terminal decisions;
  // CUSTOMER.KYC_PENDING is an intermediate signal that the customer has been
  // submitted for review (useful for surfacing "we're still reviewing" UI).
  app.post('/webhooks/kyc-status', async (req, res) => {
    const { type, data } = req.body;

    switch (type) {
      case 'CUSTOMER.KYC_APPROVED':
        // Activate customer account
        await activateCustomer(data.id);
        await sendWelcomeEmail(data.id);
        break;

      case 'CUSTOMER.KYC_REJECTED':
        // Notify support and customer
        await notifySupport(data.id, 'KYC_REJECTED');
        await sendRejectionEmail(data.id);
        break;

      case 'CUSTOMER.KYC_PENDING':
        // Intermediate: customer submitted for review, no decision yet
        await markCustomerUnderReview(data.id);
        break;

      case 'CUSTOMER.KYB_APPROVED':
        // Business customer decision: activate
        await activateCustomer(data.id);
        await sendWelcomeEmail(data.id);
        break;

      case 'CUSTOMER.KYB_REJECTED':
        // Business customer decision: notify
        await notifySupport(data.id, 'KYB_REJECTED');
        await sendRejectionEmail(data.id);
        break;

      case 'CUSTOMER.KYB_PENDING':
        // Intermediate: business customer submitted for review
        await markCustomerUnderReview(data.id);
        break;

      default:
        // Log unexpected types
        console.log(`Unexpected webhook type ${type} for customer ${data.id}`);
    }

    res.status(200).send('OK');
  });
  ```
</Accordion>

## Listing Customers

Retrieve a paginated list of customers with optional filtering:

```bash theme={null}
curl -X GET "https://api.lightspark.com/grid/2025-10-13/customers?limit=20&customerType=INDIVIDUAL" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET"
```

### Query Parameters

<ParamField query="platformCustomerId" type="string">
  Filter by your platform's customer identifier
</ParamField>

<ParamField query="customerType" type="string">
  Filter by customer type (`INDIVIDUAL` or `BUSINESS`)
</ParamField>

<ParamField query="createdAfter" type="string">
  Filter customers created after this timestamp (ISO 8601)
</ParamField>

<ParamField query="createdBefore" type="string">
  Filter customers created before this timestamp (ISO 8601)
</ParamField>

<ParamField query="updatedAfter" type="string">
  Filter customers updated after this timestamp (ISO 8601)
</ParamField>

<ParamField query="updatedBefore" type="string">
  Filter customers updated before this timestamp (ISO 8601)
</ParamField>

<ParamField query="region" type="string">
  Filter by customer region (ISO 3166-1 alpha-2 country code)
</ParamField>

<ParamField query="currency" type="string">
  Filter by currency code. Returns customers that have this currency in their enabled currencies list.
</ParamField>

<ParamField query="umaAddress" type="string">
  Filter by UMA address
</ParamField>

<ParamField query="isIncludingDeleted" type="boolean">
  Whether to include deleted customers in results (default: false)
</ParamField>

<ParamField query="limit" type="integer">
  Maximum number of results per page (default: 20, max: 100)
</ParamField>

<ParamField query="cursor" type="string">
  Pagination cursor from previous response
</ParamField>

### Response

```json theme={null}
{
  "data": [
    {
      "id": "Customer:019542f5-b3e7-1d02-0000-000000000001",
      "platformCustomerId": "user_12345",
      "customerType": "INDIVIDUAL",
      "kycStatus": "APPROVED",
      "fullName": "Jane Doe",
      "birthDate": "1992-03-25",
      "address": {
        "line1": "123 Pine Street",
        "line2": "Unit 501",
        "city": "Seattle",
        "state": "WA",
        "postalCode": "98101",
        "country": "US"
      },
      "createdAt": "2025-10-03T12:00:00Z",
      "updatedAt": "2025-10-03T12:00:00Z",
      "isDeleted": false
    }
  ],
  "hasMore": true,
  "nextCursor": "MjAyNS0xMC0wM1QxMjowMDowMFo=",
  "totalCount": 152
}
```

<Tip>
  To find a specific customer by your platform ID, use: `GET /customers?platformCustomerId=user_12345`
</Tip>

## Retrieving a Single Customer

Get detailed information about a specific customer:

```bash theme={null}
curl -X GET "https://api.lightspark.com/grid/2025-10-13/customers/{customerId}" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET"
```

## Deleting Customers

Delete a customer by their system-generated ID:

```bash theme={null}
curl -X DELETE "https://api.lightspark.com/grid/2025-10-13/customers/{customerId}" \
  -H "Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET"
```

<Warning>
  Deleting a customer is permanent and will prevent them from receiving future payments. Their transaction history will be preserved but the customer record will be marked as deleted.
</Warning>

## Related Resources

* [API Reference: Customers](/api-reference/customers/add-a-new-customer) - Complete customer API documentation
* [Quick Start Guide](/rewards/quickstart) - End-to-end Bitcoin rewards walkthrough
* [Handling Webhooks](/rewards/platform-tools/webhooks) - Implement webhook handling for real-time notifications
