openapi: 3.1.0
info:
title: Grid Agent Management Customers API
description: 'API for managing global payments on the open Money Grid. Built by Lightspark. See the full documentation at https://docs.lightspark.com/.
'
version: '2025-10-13'
contact:
name: Lightspark Support
email: support@lightspark.com
license:
name: Proprietary
url: https://lightspark.com/terms
servers:
- url: https://api.lightspark.com/grid/2025-10-13
description: Production server
security:
- BasicAuth: []
- AgentAuth: []
tags:
- name: Customers
description: Customer management endpoints for creating and updating customer information
paths:
/customers:
post:
summary: Add a new customer
description: Register a new customer in the system with an account identifier and bank account information
operationId: createCustomer
tags:
- Customers
security:
- BasicAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerCreateRequestOneOf'
examples:
individualCustomer:
summary: Create an individual customer
value:
customerType: INDIVIDUAL
platformCustomerId: ind-9f84e0c2
region: US
currencies:
- USD
- USDC
fullName: Jane Smith
birthDate: '1990-01-15'
nationality: US
email: jane.smith@example.com
phoneNumber: '+14155551234'
individualCustomerInferred:
summary: Create an individual customer with inferred currencies
value:
customerType: INDIVIDUAL
platformCustomerId: ind-7b3f1a9d
region: MX
fullName: Carlos García
birthDate: '1988-05-22'
nationality: MX
phoneNumber: '+525512345678'
businessCustomer:
summary: Create a business customer
value:
customerType: BUSINESS
platformCustomerId: biz-acme-001
region: US
currencies:
- USD
- USDC
email: finance@acme.com
phoneNumber: '+14155559876'
businessInfo:
legalName: Acme Corporation
doingBusinessAs: Acme
country: US
registrationNumber: '5523041'
incorporatedOn: '2018-03-14'
entityType: LLC
taxId: 47-1234567
countriesOfOperation:
- US
businessType: INFORMATION
purposeOfAccount: CONTRACTOR_PAYOUTS
sourceOfFunds: Funds derived from customer payments for software services
expectedMonthlyTransactionCount: COUNT_100_TO_500
expectedMonthlyTransactionVolume: VOLUME_100K_TO_1M
expectedRecipientJurisdictions:
- US
- MX
address:
line1: 123 Market Street
line2: Suite 400
city: San Francisco
state: CA
postalCode: '94105'
country: US
responses:
'201':
description: Customer created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerOneOf'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error400'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error401'
'405':
description: Method not allowed. Returned (as JSON, not HTML) when the request uses an HTTP method that is not supported on this path.
content:
application/json:
schema:
$ref: '#/components/schemas/Error405'
'409':
description: Conflict. `UMA_ADDRESS_EXISTS` when the requested UMA address is already taken; `CONFLICT` when `platformCustomerId` collides with an existing active customer on the same platform.
content:
application/json:
schema:
$ref: '#/components/schemas/Error409'
'500':
description: Internal service error
content:
application/json:
schema:
$ref: '#/components/schemas/Error500'
'501':
description: Not implemented
content:
application/json:
schema:
$ref: '#/components/schemas/Error501'
get:
summary: List customers
description: 'Retrieve a list of customers with optional filtering parameters. Returns all customers that match
the specified filters. If no filters are provided, returns all customers (paginated).
'
operationId: listCustomers
tags:
- Customers
security:
- BasicAuth: []
parameters:
- name: platformCustomerId
in: query
description: Filter by platform-specific customer identifier
required: false
schema:
type: string
- name: customerType
in: query
description: Filter by customer type
required: false
schema:
$ref: '#/components/schemas/CustomerType'
- name: createdAfter
in: query
description: Filter customers created after this timestamp (inclusive)
required: false
schema:
type: string
format: date-time
- name: createdBefore
in: query
description: Filter customers created before this timestamp (inclusive)
required: false
schema:
type: string
format: date-time
- name: updatedAfter
in: query
description: Filter customers updated after this timestamp (inclusive)
required: false
schema:
type: string
format: date-time
- name: updatedBefore
in: query
description: Filter customers updated before this timestamp (inclusive)
required: false
schema:
type: string
format: date-time
- name: limit
in: query
description: Maximum number of results to return (default 20, max 100)
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
- name: cursor
in: query
description: Cursor for pagination (returned from previous request)
required: false
schema:
type: string
- name: region
in: query
description: Filter by customer region (ISO 3166-1 alpha-2 country code)
required: false
schema:
type: string
- name: currency
in: query
description: Filter by currency code. Returns customers that have this currency in their enabled currencies list.
required: false
schema:
type: string
- name: umaAddress
in: query
description: Filter by uma address
required: false
schema:
type: string
- name: isIncludingDeleted
in: query
description: Whether to include deleted customers in the results. Default is false.
required: false
schema:
type: boolean
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerListResponse'
'400':
description: Bad request - Invalid parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error400'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error401'
'405':
description: Method not allowed. Returned (as JSON, not HTML) when the request uses an HTTP method that is not supported on this path.
content:
application/json:
schema:
$ref: '#/components/schemas/Error405'
'500':
description: Internal service error
content:
application/json:
schema:
$ref: '#/components/schemas/Error500'
/customers/{customerId}:
parameters:
- name: customerId
in: path
description: System-generated unique customer identifier
required: true
schema:
type: string
get:
summary: Get customer by ID
description: Retrieve a customer by their system-generated ID
operationId: getCustomerById
tags:
- Customers
security:
- BasicAuth: []
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerOneOf'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error401'
'404':
description: Customer not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error404'
'500':
description: Internal service error
content:
application/json:
schema:
$ref: '#/components/schemas/Error500'
patch:
summary: Update customer by ID
description: 'Update a customer''s metadata by their system-generated ID.
Most customer updates complete synchronously and return `200` with the updated customer. If the request changes `email` for a customer that has one or more tied Embedded Wallet internal accounts with `EMAIL_OTP` credentials, or changes `phoneNumber` for a customer that has one or more tied Embedded Wallet internal accounts with `SMS_OTP` credentials, the contact update uses the two-step signed-retry flow so the customer''s wallet session authorizes the authentication credential update. On the signed retry, Grid updates the customer contact field and every tied matching OTP credential across all tied Embedded Wallets as one logical operation. If any tied credential cannot be updated, the customer contact field is not changed.
Update `email` and `phoneNumber` in separate PATCH calls. A request that includes both fields is rejected.
For an Embedded Wallet email or SMS auth phone update:
1. Call `PATCH /customers/{customerId}` with the full update body and no signature headers. Grid returns `202` with `payloadToSign`, `requestId`, and `expiresAt`. The pending challenge binds the submitted update fields and the set of tied Embedded Wallet OTP credentials that must be updated.
2. Use the session API keypair of a verified authentication credential on one of the customer''s tied Embedded Wallets to build an API-key stamp over `payloadToSign`, then retry the same request with that full stamp as the `Grid-Wallet-Signature` header and the `requestId` echoed back as the `Request-Id` header. The retry body must carry the same update fields submitted in step 1. The signed retry returns `200` with the updated customer.
'
operationId: updateCustomerById
tags:
- Customers
security:
- BasicAuth: []
parameters:
- name: Grid-Wallet-Signature
in: header
required: false
description: Full API-key stamp built over the prior `payloadToSign` with the session API keypair of a verified authentication credential on one of the customer's tied Embedded Wallets. Required on the signed retry for Embedded Wallet email or SMS auth phone updates; ignored on the initial call and on customer updates that complete synchronously.
schema:
type: string
example: eyJwdWJsaWNLZXkiOiIwMmExYjIuLi4iLCJzY2hlbWUiOiJTSUdOQVRVUkVfU0NIRU1FX1RLX0FQSV9QMjU2Iiwic2lnbmF0dXJlIjoiMzA0NTAyMjEwMC4uLiJ9
- name: Request-Id
in: header
required: false
description: The `requestId` returned in a prior `202` response, echoed back on the signed retry so the server can correlate it with the issued challenge. Required on the signed retry for Embedded Wallet email or SMS auth phone updates; must be paired with `Grid-Wallet-Signature`.
schema:
type: string
example: Request:019542f5-b3e7-1d02-0000-000000000010
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerUpdateRequestOneOf'
examples:
individualUpdate:
summary: Update individual customer example
value:
customerType: INDIVIDUAL
fullName: John Smith
birthDate: '1985-06-15'
currencies:
- USD
- EUR
- USDC
address:
line1: 456 Market St
city: San Francisco
state: CA
postalCode: '94103'
country: US
businessUpdate:
summary: Update business customer example
value:
customerType: BUSINESS
currencies:
- USD
- USDC
businessInfo:
legalName: New Tech Solutions LLC
registrationNumber: BRN-987654321
taxId: EIN-123456789
address:
line1: 100 Technology Parkway
city: Palo Alto
state: CA
postalCode: '94304'
country: US
embeddedWalletEmailUpdate:
summary: Embedded Wallet email update request (both steps)
value:
customerType: INDIVIDUAL
email: john.smith@example.com
embeddedWalletPhoneUpdate:
summary: Embedded Wallet SMS auth phone update request (both steps)
value:
customerType: INDIVIDUAL
phoneNumber: '+14155559876'
combinedContactUpdateRejected:
summary: Combined email and phone update request (rejected)
value:
customerType: INDIVIDUAL
email: john.smith@example.com
phoneNumber: '+14155559876'
responses:
'200':
description: Customer updated successfully. For Embedded Wallet email or SMS auth phone updates, this is returned only on the signed retry after the customer contact field and all tied matching OTP credentials have been updated.
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerOneOf'
'202':
description: Challenge issued for an Embedded Wallet email or SMS auth phone update. The response contains `payloadToSign` plus a `requestId`. Build an API-key stamp over `payloadToSign` with the session API keypair from a verified authentication credential on one of the customer's tied Embedded Wallets, then retry the same request with `Grid-Wallet-Signature` and `Request-Id`.
content:
application/json:
schema:
$ref: '#/components/schemas/SignedRequestChallenge'
examples:
embeddedWalletEmailUpdate:
summary: Embedded Wallet customer email update challenge
value:
payloadToSign: '{"organizationId":"org_2m9F...","parameters":{"userEmail":"john.smith@example.com","userId":"user_2m9F..."},"timestampMs":"1775681700000","type":"ACTIVITY_TYPE_UPDATE_USER_EMAIL"}'
requestId: Request:019542f5-b3e7-1d02-0000-000000000010
expiresAt: '2026-04-08T15:35:00Z'
embeddedWalletPhoneUpdate:
summary: Embedded Wallet customer SMS auth phone update challenge
value:
payloadToSign: '{"organizationId":"org_2m9F...","parameters":{"userId":"user_2m9F...","userPhoneNumber":"+14155559876"},"timestampMs":"1775681700000","type":"ACTIVITY_TYPE_UPDATE_USER_PHONE_NUMBER"}'
requestId: Request:019542f5-b3e7-1d02-0000-000000000011
expiresAt: '2026-04-08T15:35:00Z'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error400'
'401':
description: Unauthorized. Also returned for Embedded Wallet email or SMS auth phone update retries when the provided `Grid-Wallet-Signature` is missing, malformed, or does not match the pending customer update challenge, when the `Request-Id` does not match an unexpired pending challenge, or when the retry body does not match the update fields bound into `payloadToSign` on the initial call.
content:
application/json:
schema:
$ref: '#/components/schemas/Error401'
'404':
description: Customer not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error404'
'409':
description: Conflict. Returned when the supplied email address is already associated with an `EMAIL_OTP` credential, or the supplied phone number is already associated with an `SMS_OTP` credential, on this or another internal account, or when the tied Embedded Wallet OTP credential set changed between the initial `202` challenge and the signed retry.
content:
application/json:
schema:
$ref: '#/components/schemas/Error409'
'424':
description: Failed dependency. Returned when Grid cannot update one or more tied Embedded Wallet OTP credentials. The customer contact field is not changed unless all tied credentials are updated successfully.
content:
application/json:
schema:
$ref: '#/components/schemas/Error424'
'500':
description: Internal service error
content:
application/json:
schema:
$ref: '#/components/schemas/Error500'
delete:
summary: Delete customer by ID
description: Delete a customer by their system-generated ID
operationId: deleteCustomerById
tags:
- Customers
security:
- BasicAuth: []
responses:
'200':
description: Customer deleted successfully
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerOneOf'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error401'
'404':
description: Customer not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error404'
'410':
description: Customer deleted already
content:
application/json:
schema:
$ref: '#/components/schemas/Error410'
'500':
description: Internal service error
content:
application/json:
schema:
$ref: '#/components/schemas/Error500'
/customers/bulk/csv:
post:
summary: Upload customers via CSV file
description: 'Upload a CSV file containing customer information for bulk creation. The CSV file should follow
a specific format with required and optional columns based on customer type.
### CSV Format
The CSV file should have the following columns:
Required columns for all customers:
- umaAddress: The customer''s UMA address (e.g., $john.doe@uma.domain.com)
- platformCustomerId: Your platform''s unique identifier for the customer
- customerType: Either "INDIVIDUAL" or "BUSINESS"
Required columns for individual customers:
- fullName: Individual''s full name
- birthDate: Date of birth in YYYY-MM-DD format
- addressLine1: Street address line 1
- city: City
- state: State/Province/Region
- postalCode: Postal/ZIP code
- country: Country code (ISO 3166-1 alpha-2)
Required columns for business customers:
- businessLegalName: Legal name of the business
- addressLine1: Street address line 1
- city: City
- state: State/Province/Region
- postalCode: Postal/ZIP code
- country: Country code (ISO 3166-1 alpha-2)
Optional columns for all customers:
- addressLine2: Street address line 2
- platformAccountId: Your platform''s identifier for the bank account
- description: Optional description for the customer
Optional columns for individual customers:
- email: Customer''s email address
Optional columns for business customers:
- businessRegistrationNumber: Business registration number
- businessTaxId: Tax identification number
### Example CSV
```csv
umaAddress,platformCustomerId,customerType,fullName,birthDate,addressLine1,city,state,postalCode,country,platformAccountId,businessLegalName
john.doe@uma.domain.com,customer123,INDIVIDUAL,John Doe,1990-01-15,123 Main St,San Francisco,CA,94105,US
acme@uma.domain.com,biz456,BUSINESS,,,400 Commerce Way,Austin,TX,78701,US
```
The upload process is asynchronous and will return a job ID that can be used to track progress.
You can monitor the job status using the `/customers/bulk/jobs/{jobId}` endpoint.
'
operationId: uploadCustomersCsv
tags:
- Customers
security:
- BasicAuth: []
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required:
- file
properties:
file:
type: string
format: binary
description: CSV file containing customer information
responses:
'202':
description: CSV upload accepted for processing
content:
application/json:
schema:
$ref: '#/components/schemas/BulkCustomerImportJobAccepted'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error401'
'500':
description: Internal service error
content:
application/json:
schema:
$ref: '#/components/schemas/Error500'
/customers/bulk/jobs/{jobId}:
get:
summary: Get bulk import job status
description: 'Retrieve the current status and results of a bulk customer import job. This endpoint can be used
to track the progress of both CSV uploads.
The response includes:
- Overall job status
- Progress statistics
- Detailed error information for failed entries
- Completion timestamp when finished
'
operationId: getBulkCustomerImportJob
tags:
- Customers
security:
- BasicAuth: []
parameters:
- name: jobId
in: path
description: ID of the bulk import job to retrieve
required: true
schema:
type: string
responses:
'200':
description: Job status retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/BulkCustomerImportJob'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error401'
'404':
description: Job not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error404'
'500':
description: Internal service error
content:
application/json:
schema:
$ref: '#/components/schemas/Error500'
components:
schemas:
BeneficialOwnerPersonalInfo:
type: object
required:
- firstName
- lastName
- birthDate
- nationality
- address
- idType
- identifier
properties:
firstName:
type: string
description: First name of the individual
example: Jane
middleName:
type: string
description: Middle name of the individual
example: Marie
lastName:
type: string
description: Last name of the individual
example: Smith
birthDate:
type: string
format: date
description: Date of birth in ISO 8601 format (YYYY-MM-DD)
example: '1978-06-15'
nationality:
type: string
description: Country of nationality (ISO 3166-1 alpha-2)
example: US
email:
type: string
format: email
description: Email address of the individual
example: jane.smith@acmecorp.com
phoneNumber:
type: string
description: Phone number in E.164 format
example: '+14155550192'
pattern: ^\+[1-9]\d{1,14}$
address:
$ref: '#/components/schemas/Address'
idType:
$ref: '#/components/schemas/IdentificationType'
identifier:
type: string
description: The identification number or value
example: 123-45-6789
countryOfIssuance:
type: string
description: Country that issued the identification (ISO 3166-1 alpha-2)
example: US
Error424:
type: object
required:
- message
- status
- code
properties:
status:
type: integer
enum:
- 424
description: HTTP status code
code:
type: string
description: '| Error Code | Description |
|------------|-------------|
| PAYREQ_REQUEST_FAILED | Payment request failed |
| COUNTERPARTY_PUBKEY_FETCH_ERROR | Error fetching counterparty public key |
| NO_COMPATIBLE_UMA_VERSION | No compatible UMA version |
| LNURLP_REQUEST_FAILED | LNURLP request failed |
| EMAIL_OTP_CREDENTIAL_SYNC_FAILED | Failed to update one or more tied EMAIL_OTP credentials |
'
enum:
- PAYREQ_REQUEST_FAILED
- COUNTERPARTY_PUBKEY_FETCH_ERROR
- NO_COMPATIBLE_UMA_VERSION
- LNURLP_REQUEST_FAILED
- EMAIL_OTP_CREDENTIAL_SYNC_FAILED
message:
type: string
description: Error message
details:
type: object
description: Additional error details
additionalProperties: true
IndividualCustomerFields:
type: object
required:
- customerType
properties:
customerType:
type: string
enum:
- INDIVIDUAL
kycStatus:
$ref: '#/components/schemas/KycStatus'
fullName:
type: string
description: Individual's full name
example: John Michael Doe
birthDate:
type: string
format: date
description: Date of birth in ISO 8601 format (YYYY-MM-DD)
example: '1990-01-15'
nationality:
type: string
description: Country code (ISO 3166-1 alpha-2)
example: US
address:
$ref: '#/components/schemas/Address'
Address:
type: object
required:
- line1
- postalCode
- country
properties:
line1:
type: string
description: Street address line 1
example: 123 Main Street
line2:
type: string
description: Street address line 2
example: Apt 4B
city:
type: string
description: City
example: San Francisco
state:
type: string
description: State/Province/Region
example: CA
postalCode:
type: string
description: Postal/ZIP code
example: '94105'
country:
type: string
description: Country code (ISO 3166-1 alpha-2)
example: US
BeneficialOwner:
type: object
required:
- id
- customerId
- roles
- ownershipPercentage
- personalInfo
- kycStatus
- createdAt
properties:
id:
type: string
description: Unique identifier for this beneficial owner
example: BeneficialOwner:019542f5-b3e7-1d02-0000-000000000001
customerId:
type: string
description: The ID of the business customer this beneficial owner is associated with
example: Customer:019542f5-b3e7-1d02-0000-000000000001
roles:
type: array
items:
$ref: '#/components/schemas/BeneficialOwnerRole'
description: Roles of this person within the business
example:
- UBO
- DIRECTOR
ownershipPercentage:
type: integer
description: Percentage of ownership in the business (0-100)
minimum: 0
maximum: 100
example: 51
personalInfo:
$ref: '#/components/schemas/BeneficialOwnerPersonalInfo'
kycStatus:
$ref: '#/components/schemas/KycStatus'
createdAt:
type: string
format: date-time
description: When this beneficial owner was created
example: '2025-10-03T12:00:00Z'
updatedAt:
type: string
format: date-time
description: When this beneficial owner was last updated
example: '2025-10-03T12:00:00Z'
BusinessCustomerCreateRequest:
title: Business Customer Create Request
allOf:
- $ref: '#/components/schemas/CustomerCreateRequest'
- $ref: '#/components/schemas/BusinessCustomerFields'
- type: object
properties:
businessInfo:
$ref: '#/components/schemas/BusinessInfo'
BulkCustomerImportJobAccepted:
type: object
required:
- jobId
- status
properties:
jobId:
type: string
description: Unique identifier for the bulk import job
example: Job:019542f5-b3e7-1d02-0000-000000000006
status:
type: string
enum:
- PENDING
- PROCESSING
CustomerListResponse:
type: object
required:
- data
- hasMore
properties:
data:
type: array
description: List of customers matching the filter criteria
items:
$ref: '#/components/schemas/CustomerOneOf'
hasMore:
type: boolean
description: Indicates if more results are available beyond this page
nextCursor:
type: string
description: Cursor to retrieve the next page of results (only present if hasMore is true)
totalCount:
type: integer
description: Total number of customers matching the criteria (excluding pagination)
Error404:
type: object
required:
- message
- status
- code
properties:
status:
type: integer
# --- truncated at 32 KB (75 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/lightspark/refs/heads/main/openapi/lightspark-customers-api-openapi.yml