Customers
A customer is the entity that purchases goods or services from a merchant. A customer may be a person or an organization. Every customer has a unique id referenced from other resources as customerId.
A customer is the main resource for most integrations — payment instruments, subscriptions, transactions, and invoices all hang off a customer.
Default payment instrument
A customer may have a default payment instrument. The default is used:
- To automatically pay subscription renewals.
- For transaction requests where no specific
paymentInstrumentIdortokenis provided inpaymentInstruction.
A customer can hold multiple payment instruments. Only one is the default at any time. Setting a new default does not deactivate the previous one — it stays attached and chargeable by its ID.
For how payment instruments are created and how their state changes, see Payment instruments and Payment instrument lifecycle.
Relation to other resources
| Resource | Relation |
|---|---|
| Payment instruments | A customer owns zero or more instruments. One can be default. |
| Subscriptions | A subscription always points at one customerId and one paymentInstrumentId. |
| Transactions | Every transaction references a customerId. |
| Invoices | Invoices are addressed to a customerId. |
Customer API
The Public API exposes five operations on the customer resource: POST to create, GET to retrieve one or list many, PATCH to update partial fields, and PUT to upsert.
Create a customer
curl -X POST \
"https://staging-api.payments.ai/v1/public-api/organizations/${ORGANIZATION_ID}/customers" \
-H 'Content-Type: application/json' \
-H "Authorization: ApiKey ${API_KEY}" \
-d '{
"firstName": "Jane",
"lastName": "Doe",
"email": "[email protected]",
"phoneNumber": "5550100",
"isEnhancedDueDiligenceRequired": false,
"primaryAddress": {
"customerAddress": {
"address1": "123 Main St",
"address2": "Apt 4B",
"country": "US",
"city": "Springfield",
"region": "IL",
"zip": "62701"
}
}
}'
All fields are optional.
| Field | Notes |
|---|---|
firstName | Max 45 characters. |
lastName | Max 45 characters. |
organization | Max 255 characters. The customer's employer or organization name (free-form). Not the same as the organizationId URL parameter. |
email | Standard email format. |
phoneNumber | Max 10 characters. The phone number only — does not include a country/area code. |
isEnhancedDueDiligenceRequired | Boolean, default false. Marks the customer as requiring Enhanced Due Diligence (EDD) for KYC/AML processing. See KYC overview. |
primaryAddress | Object with a single nested customerAddress field. See below. |
primaryAddress.customerAddress
| Field | Notes |
|---|---|
address1 | Max 60 characters. Street line 1. |
address2 | Max 60 characters. Street line 2 (apartment, suite, etc.). |
country | Max 2 characters. ISO 3166-1 alpha-2 country code (US, DE, etc.). |
city | Max 45 characters. |
region | Max 45 characters. State or province. |
zip | Max 10 characters. Postal/ZIP code. |
Returns 201 Created with the created Customer object. Store its id — every later operation against this customer references it.
Address field names differ across endpoints and operations. Create uses
primaryAddress.customerAddress.{address1, ...}. Update (PATCH) uses a flataddress.{address1, ...}. Upsert (PUT) uses a flatprimaryAddress.{address1, ...}. The tokenization production endpoint usesbillingAddress.{address, ...}withpostalCodeinstead ofzip. Map your billing form to the correct field names per endpoint — they are not interchangeable.
Retrieve a customer
curl -X GET \
"https://staging-api.payments.ai/v1/public-api/organizations/${ORGANIZATION_ID}/customers/${CUSTOMER_ID}?showTestData=false" \
-H "Authorization: ApiKey ${API_KEY}"
| Query parameter | Notes |
|---|---|
showTestData | Boolean. Includes test data in the response when true. |
Response shape:
{
"type": "object",
"data": {
"firstName": "Jane",
"lastName": "Doe",
"organization": "Acme Inc.",
"phoneNumber": "5550100",
"isEnhancedDueDiligenceRequired": false,
"primaryAddress": {
"customerAddress": {
"address1": "123 Main St",
"address2": "Apt 4B",
"country": "US",
"city": "Springfield",
"region": "IL",
"zip": "62701"
}
}
}
}
List customers
curl -X GET \
"https://staging-api.payments.ai/v1/public-api/organizations/${ORGANIZATION_ID}/customers?limit=20&offset=0" \
-H "Authorization: ApiKey ${API_KEY}"
| Query parameter | Type | Notes |
|---|---|---|
limit | integer 0–100, default 20 | Pagination page size. |
offset | integer ≥0 | Pagination offset. |
search | string | Free-text search (for example, by email). |
showTestData | boolean | Includes test data in the response when true. |
sortBy | enum | One of createdAt, email, name, country, lifetimeRevenue, lastPaymentTime. |
sortDirection | enum | asc or desc. |
revenueMin / revenueMax | number | Filter by lifetime revenue range (numeric monetary value). |
createdFrom / createdTo | date-time | Filter by creation date range. |
lastPaymentFrom / lastPaymentTo | date-time | Filter by last payment date range. |
countries | array of strings | ISO country codes (for example, countries=US). |
primaryPaymentInstrumentMethods | array of PaymentMethodEnum | Filter by the customer's primary payment instrument method (payment-card, ach, paypal, etc.). |
isVip | boolean | Filter to VIP customers only. |
Response shape:
{
"type": "list",
"totalCount": 100,
"paginationMeta": {
"limit": 10,
"offset": 10
},
"data": [
{ "firstName": "Jane", "lastName": "Doe", "...": "..." }
]
}
Update a customer (PATCH)
Partial update — pass only the fields you want to change. All fields are optional.
curl -X PATCH \
"https://staging-api.payments.ai/v1/public-api/organizations/${ORGANIZATION_ID}/customers/${CUSTOMER_ID}" \
-H 'Content-Type: application/json' \
-H "Authorization: ApiKey ${API_KEY}" \
-d '{
"email": "[email protected]",
"phoneNumber": "5550199",
"tags": ["vip"],
"address": {
"country": "US",
"address1": "456 Oak Ave",
"city": "Chicago",
"region": "IL",
"zip": "60601"
},
"primaryPaymentInstrument": {
"method": "payment-card",
"id": "92dcc8b0-0872-4858-9f01-d6ecc724b4a9"
}
}'
| Field | Notes |
|---|---|
firstName | Max 45 characters. |
lastName | Max 45 characters. |
email | Standard email format. |
phoneNumber | Max 10 characters. |
organization | Max 255 characters. |
tags | Array of CustomerTag enum values: discounted, vip. |
address | Object with flat structure: country, address1, address2, city, region, zip. Note: PATCH uses address at the top level, not the nested primaryAddress.customerAddress shape used by Create. |
primaryPaymentInstrument | Object with method (PaymentMethodEnum) and id (UUID of the payment instrument). Sets which payment instrument is the customer's default. |
Upsert a customer (PUT)
Create the customer at the given customerId if it does not exist, or replace the full resource if it does. Use PATCH for partial updates; use PUT only when you want to overwrite the full object.
curl -X PUT \
"https://staging-api.payments.ai/v1/public-api/organizations/${ORGANIZATION_ID}/customers/${CUSTOMER_ID}" \
-H 'Content-Type: application/json' \
-H "Authorization: ApiKey ${API_KEY}" \
-d '{
"firstName": "Jane",
"lastName": "Doe",
"email": "[email protected]",
"phoneNumber": "5550199",
"organization": "Acme Inc.",
"isEnhancedDueDiligenceRequired": false,
"primaryAddress": {
"address1": "456 Oak Ave",
"address2": "",
"country": "US",
"city": "Chicago",
"region": "IL",
"zip": "60601",
"dateOfBirth": "1990-04-12T00:00:00Z",
"jobTitle": "Engineer"
}
}'
Body fields are the same as Create, with two differences:
primaryAddressis flat (nocustomerAddresswrapper).primaryAddressaccepts two extra fields available only on PUT — they are not accepted by Create (POST) or Update (PATCH), and are not returned by Retrieve (GET):
| Field | Notes |
|---|---|
dateOfBirth | ISO 8601 date-time. The customer's date of birth. |
jobTitle | String. The customer's job title. |
Returns 201 Created.
Custom fields on customers
You can attach merchant-specific structured data to a customer using custom fields. Define the schema once with POST /custom-fields (resource: customers), then populate per-customer values via the customer endpoint. See Custom fields.