Skip to main content
This guide provides comprehensive information about creating customers in the Grid API, including customer types, onboarding models, registration, and management.

Onboarding model

There are two platform models for regulated and unregulated platforms.
  • Regulated institutions: Use your existing compliance processes. Create individual and business customers directly via POST /customers. The information you supply is used for beneficiary/counterparty compliance screening.
  • Unregulated institutions: Grid performs KYC/KYB. Generate a hosted KYC/KYB link, redirect your customer to complete verification in their locale, receive a KYC result webhook. While KYC is pending, allow customers to finish account setup but block funding and money movement.

Customer Types

The Grid API supports both individual and business customers. While the API schema itself makes most Personally Identifiable Information (PII) optional at initial creation, specific fields may become mandatory based on the currencies the customer will transact with. Your platform’s configuration (retrieved via GET /config) includes a supportedCurrencies array. Each currency object within this array has a providerRequiredCustomerFields list. If a customer is intended to use a specific currency, any fields listed for that currency must be provided when creating or updating the customer. The base required information for all customers is only:
  • Platform customer ID (your internal identifier)
  • Customer type (INDIVIDUAL or BUSINESS)
If using sending and receiving to just-in-time UMA addresses, you’ll also need to specify the bank account information

Individual customers

In some cases, only the above fields are required at customer creation. Beyond those base requirements, additional fields commonly associated with individual customers include:
  • Full name
  • Date of birth (YYYY-MM-DD format)
  • Physical address (including country, state, city, postalCode)
Note: Check the providerRequiredCustomerFields for each relevant currency in your platform’s configuration to determine which of these fields are strictly mandatory at creation/update time for that customer to transact in those currencies.

Business customers

Beyond the base requirements, additional fields commonly associated with business customers include:
  • Business information:
    • Legal name (this is often required, check providerRequiredCustomerFields)
    • Registration number (optional, unless specified by providerRequiredCustomerFields)
    • Tax ID (optional, unless specified by providerRequiredCustomerFields)
  • Physical address (including country, state, city, postalCode)
Note: Check the providerRequiredCustomerFields for each relevant currency in your platform’s configuration to determine which of these fields are strictly mandatory at creation/update time for that customer to transact in those currencies. When creating or updating customers, the customerType field must be specified as either INDIVIDUAL or BUSINESS.
There can be multiple customers with the same platformCustomerId but different UMA addresses. This is useful if you want to track multiple UMA addresses and/or bank accounts for the same customer in your platform.

Customer Creation Process

Creating a new individual customer (regulated institutions)

To register a new customer directly, use the POST /customers endpoint (regulated institutions):
curl -sS -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \
  -u "$GRID_CLIENT_ID:$GRID_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "platformCustomerId": "9f84e0c2a72c4fa",
    "customerType": "INDIVIDUAL",
    "fullName": "Jane Doe",
  }'
The API allows creating a customer with minimal PII. However, to enable transactions for a customer in specific currencies, you must include any PII fields mandated by the providerRequiredCustomerFields for those currencies (found in your platform’s configuration via GET /config). 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 provider requirements. Example request body for an individual customer with UMA instant payments enabled (ensure all providerRequiredCustomerFields for intended currencies are included):
Typically bank account information is provided separately via internal and external account management. However, when using UMA for instant payments, since funding and withdrawals are instant, bank account information can be provided at time of customer creation.
{
  "umaAddress": "$john.sender@mycompany.com",
  "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"
  },
  "bankAccountInfo": {
    "accountType": "CLABE",
    "clabeNumber": "123456789012345678",
    "bankName": "Banco de México"
  }
}
UMA addresses follow the format $username@domain. For your platform:
  1. The domain part will be your configured UMA domain (set in platform configuration)
  2. The username part can be chosen by you or your customers, following these rules:
    • Must start with a $ symbol. This is to differentiate from email addresses and clearly identify an uma address.
    • The username portion is limited to a-z0-9-_.+
    • Addresses are case-insensitive, but by convention are written only with lowercase letters
    • Like email addresses, the maximum number of characters for the username portion of the address is 64 characters (including the $).
The Grid API validates these requirements and will return an error if they are not met.

Creating a new business customer (regulated institutions)

curl -sS -X POST "https://api.lightspark.com/grid/2025-10-13/customers" \
  -u "$GRID_CLIENT_ID:$GRID_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "umaAddress": "$acme.corp@mycompany.com",
    "platformCustomerId": "b87d2e4a9c13f5b",
    "customerType": "BUSINESS",
    "businessInfo": {
      "legalName": "Acme Corporation",
      "registrationNumber": "789012345",
      "taxId": "123-45-6789"
    },
    "address": {
      "line1": "456 Oak Avenue",
      "line2": "Floor 12",
      "city": "New York",
      "state": "NY",
      "postalCode": "10001",
      "country": "US"
    },
    "bankAccountInfo": {
      "accountType": "US_ACCOUNT",
      "accountNumber": "123456789",
      "routingNumber": "987654321",
      "accountCategory": "CHECKING",
      "bankName": "Chase Bank"
    }
  }'

Onboarding customers (unregulated institutions)

Unregulated institutions should initiate a hosted KYC/KYB flow. Generate a link and redirect the customer to complete verification. While KYC is pending, allow account setup but block funding and money movement.
  1. Request a hosted KYC link for a customer using your platformCustomerId (optional redirectUri to return the user to your app when finished):
curl -sS -G "https://api.lightspark.com/grid/2025-10-13/customers/kyc-link" \
  -u "$GRID_CLIENT_ID:$GRID_API_SECRET" \
  --data-urlencode "platformCustomerId=9f84e0c2a72c4fa" \
  --data-urlencode "redirectUri=https://app.example.com/onboarding/completed"
Response:
{
  "kycUrl": "https://kyc.grid.example/onboard/abc123",
  "platformCustomerId": "9f84e0c2a72c4fa",
  "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001"
}
  1. Redirect the customer to kycUrl to complete KYC/KYB in their locale.
  2. After the user is redirected back to your app, they can continue with account setup until KYC review is complete.
  3. Handle the KYC status webhook. Grid notifies you when a decision is reached; update your records and unlock funding on APPROVED.

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.
For regulated platforms, customers are created with APPROVED KYC status by default.
Webhook Payload (sent to your endpoint):
{
  "webhookId": "Webhook:019542f5-b3e7-1d02-0000-000000000020",
  "type": "KYC_STATUS",
  "timestamp": "2023-07-21T17:32:28Z",
  "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
  "kycStatus": "APPROVED",
  "platformCustomerId": "1234567"
}
Webhook Headers:
  • Content-Type: application/json
  • X-Webhook-Signature: sha256=abc123...
customerId
string
required
System-generated unique identifier of the customer whose KYC status has changed.
kycStatus
string
required
Final KYC verification status. Webhooks are only sent for final states:
  • APPROVED: Customer verification completed successfully
  • REJECTED: Customer verification was rejected
  • EXPIRED: KYC verification has expired and needs renewal
  • CANCELED: Verification process was canceled
  • MANUALLY_APPROVED: Customer was manually approved by platform
  • MANUALLY_REJECTED: Customer was manually rejected by platform
Intermediate states like PENDING_REVIEW do not trigger webhook notifications. Only final resolution states will send webhook notifications.
// Example webhook handler for KYC status updates
// Note: Only final states trigger webhook notifications
app.post('/webhooks/kyc-status', (req, res) => {
  const { customerId, kycStatus } = req.body;
  
  switch (kycStatus) {
    case 'APPROVED':
      // Activate customer account
      await activateCustomer(customerId);
      await sendWelcomeEmail(customerId);
      break;
      
    case 'REJECTED':
      // Notify support and customer
      await notifySupport(customerId, 'KYC_REJECTED');
      await sendRejectionEmail(customerId);
      break;
      
    case 'MANUALLY_APPROVED':
      // Handle manual approval
      await activateCustomer(customerId);
      await sendWelcomeEmail(customerId);
      break;
      
    case 'MANUALLY_REJECTED':
      // Handle manual rejection
      await notifySupport(customerId, 'KYC_MANUALLY_REJECTED');
      await sendRejectionEmail(customerId);
      break;
      
    case 'EXPIRED':
      // Handle expired KYC
      await notifyCustomerForReKyc(customerId);
      break;
      
    case 'CANCELED':
      // Handle canceled verification
      await logKycCancelation(customerId);
      break;
      
    default:
      // Log unexpected statuses
      console.log(`Unexpected KYC status ${kycStatus} for customer ${customerId}`);
  }
  
  res.status(200).send('OK');
});

Customer management

Retrieving customer information

You can retrieve customer information using either the Grid-assigned customer ID or your platform’s customer ID:
curl -sS -X GET "https://api.lightspark.com/grid/2025-10-13/customers/{customerId}" \
  -u "$GRID_CLIENT_ID:$GRID_API_SECRET"
or list customers with a filter:
curl -sS -G "https://api.lightspark.com/grid/2025-10-13/customers" \
  -u "$GRID_CLIENT_ID:$GRID_API_SECRET" \
  --data-urlencode "umaAddress={umaAddress}" \
  --data-urlencode "platformCustomerId={platformCustomerId}" \
  --data-urlencode "customerType={customerType}" \
  --data-urlencode "createdAfter={createdAfter}" \
  --data-urlencode "createdBefore={createdBefore}" \
  --data-urlencode "cursor={cursor}" \
  --data-urlencode "limit={limit}"
Note that this example shows all available filters. You can use any combination of them.

Updating customer information

Use PATCH to update customer information:
curl -sS -X PATCH "https://api.lightspark.com/grid/2025-10-13/customers/{customerId}" \
  -u "$GRID_CLIENT_ID:$GRID_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "bankAccountInfo": {
      "accountType": "US_ACCOUNT",
      "accountNumber": "123456789",
      "routingNumber": "987654321",
      "bankName": "Chase Bank"
    }
  }'
Common use cases for platformAccountId:
  • Tracking multiple bank accounts and UMA addresses for the same customer
  • Linking accounts to internal accounting systems
  • Maintaining consistency between the Grid API and your platform’s account records
  • Facilitating account reconciliation and reporting

Data validation

The Grid API performs validation on all customer data. Common validation rules include:
  • All required fields must be present based on customer type
  • Date of birth must be in YYYY-MM-DD format and represent a valid date
  • Names must not contain special characters
  • Bank account information must follow country-specific formats
  • Addresses must include all required fields including country code
If validation fails, the API will return a 400 Bad Request response with detailed error information.

Bulk customer import operations

For scenarios where you need to add many customers to the system at once, the API provides a CSV file upload endpoint.

CSV file upload

For large-scale customer imports, you can upload a CSV file containing customer information:
curl -sS -X POST "https://api.lightspark.com/grid/2025-10-13/customers/bulk/csv" \
  -u "$GRID_CLIENT_ID:$GRID_API_SECRET" \
  -F "file=@customers.csv"
The CSV file should follow a specific format with required and optional columns based on customer type. Here’s an example:
umaAddress,platformCustomerId,customerType,fullName,birthDate,addressLine1,city,state,postalCode,country,accountType,accountNumber,bankName,platformAccountId,businessLegalName,routingNumber,accountCategory
$john.doe@uma.domain.com,cust_user123,INDIVIDUAL,John Doe,1990-01-15,123 Main St,San Francisco,CA,94105,US,US_ACCOUNT,123456789,Chase Bank,chase_primary_1234,,222888888,SAVINGS
$acme@uma.domain.com,cust_biz456,BUSINESS,,,400 Commerce Way,Austin,TX,78701,US,US_ACCOUNT,987654321,Bank of America,boa_business_5678,Acme Corp,121212121,CHECKING
CSV Upload Best Practices
  1. Use a spreadsheet application to prepare your CSV file
  2. Validate data before upload (e.g., date formats, required fields)
  3. Include a header row with column names
  4. Use UTF-8 encoding for special characters
  5. Keep file size under 100MB for optimal processing
You can track the job status through:
  1. Webhook notifications (if configured)
  2. Status polling endpoint:
curl -sS -X GET "https://api.lightspark.com/grid/2025-10-13/customers/bulk/jobs/{jobId}" \
  -u "$GRID_CLIENT_ID:$GRID_API_SECRET"
Example job status response:
{
  "jobId": "job_123456789",
  "status": "PROCESSING",
  "progress": {
    "total": 5000,
    "processed": 2500,
    "successful": 2499,
    "failed": 1
  },
  "errors": [
    {
      "platformCustomerId": "cust_biz456",
      "error": {
        "code": "validation_error",
        "message": "Invalid bank account number"
      }
    }
  ]
}
I