Customers
Customer objects represent the end users who purchase products and services through your platform.
A customer record is the foundation of the EPD ecosystem. Before processing a payment or creating a subscription, you need a customer. Each customer can have:
- Multiple payment methods (cards stored via EPD Gateway vault)
- Active subscriptions for recurring billing
- A history of orders and transactions
- Custom metadata for your internal tracking
Tip: Store customer IDs in your database to avoid creating duplicate records. Use the
phoneparameters to look up existing customers.
/customers Create a customer
Creates a new customer record with contact information and optional payment details.
Before You Start
Create a customer before processing their first payment or starting a subscription. The customer record links together their payment methods, orders, and subscription history.
Uniqueness Constraints
Both email and phone must be unique per merchant. Attempting to create a duplicate returns a 409 Conflict error. To find an existing customer, use GET /v1/customers?email=john@example.com.
EPD Gateway Vault Integration
If you've already vaulted the customer's card through EPD Gateway, pass the epd_gateway_customer_vault_id to automatically link their payment method. See the Card Vaulting Guide for the full Collect.js → EPD Gateway → EPD Commerce flow.
Sandbox Testing
In sandbox mode, pass a test card token (e.g. card_visa, card_visa_declined) as the epd_gateway_customer_vault_id to create a customer with a simulated payment method — no card vaulting required. See the Testing Guide for all available tokens.
Header parameters
string"2026-02-11"string (uuid)"550e8400-e29b-41d4-a716-446655440000"Request body required
string (email)"john@example.com"string"John"string"Doe"string"+14155551234"string"Acme Corp"ShippingAddressMetadatastring"12345678"Code samples
curl -X POST https://api.epd.com/v1/customers \
-H "Authorization: Bearer epd_test_sk_xxxx" \
-H "Content-Type: application/json" \
-H "EPD-Version: 2026-02-11" \
-d '{
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"phone": "+14155551234",
"company": "Acme Corp"
}' const response = await fetch('https://api.epd.com/v1/customers', {
method: 'POST',
headers: {
'Authorization': 'Bearer epd_test_sk_xxxx',
'Content-Type': 'application/json',
'EPD-Version': '2026-02-11',
},
body: JSON.stringify({
email: 'john@example.com',
first_name: 'John',
last_name: 'Doe',
phone: '+14155551234',
company: 'Acme Corp',
}),
});
const customer = await response.json();
console.log(customer.id); // 550e8400-e29b-41d4-a716-446655440000 import requests
response = requests.post(
'https://api.epd.com/v1/customers',
headers={
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
},
json={
'email': 'john@example.com',
'first_name': 'John',
'last_name': 'Doe',
'phone': '+14155551234',
'company': 'Acme Corp',
}
)
customer = response.json()
print(customer['id']) # 550e8400-e29b-41d4-a716-446655440000 $ch = curl_init('https://api.epd.com/v1/customers');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer epd_test_sk_xxxx',
'Content-Type: application/json',
'EPD-Version: 2026-02-11',
],
CURLOPT_POSTFIELDS => json_encode([
'email' => 'john@example.com',
'first_name' => 'John',
'last_name' => 'Doe',
'phone' => '+14155551234',
]),
]);
$response = json_decode(curl_exec($ch), true);
echo $response['id']; // 550e8400-e29b-41d4-a716-446655440000 Responses
string"550e8400-e29b-41d4-a716-446655440000"string (email)"john@example.com"string"John"string"Doe"string"+14155551234"string"Acme Corp"objectstring (uuid)"6ba7b818-9dad-11d1-80b4-00c04fd430c8"string"John Doe"string"123 Main St"string"Suite 100"string"San Francisco"string"CA"string"94105"string"US"string"+14155551234"Metadatastring"6ba7b815-9dad-11d1-80b4-00c04fd430c8"array[PaymentMethod]string (date-time)"2024-01-15T10:30:00.000Z"string (date-time)"2024-01-15T10:30:00.000Z"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/customers List all customers
Returns a paginated list of customers sorted by creation date (newest first). Supports filtering, full-text search, date ranges, resource expansion, and sparse fieldsets.
Pagination
Uses cursor-based pagination for consistent results. Use starting_after with the last customer's ID to get the next page.
GET /v1/customers?limit=20
GET /v1/customers?limit=20&starting_after=550e8400-e29b-41d4-a716-446655440000
Filtering & Search
| Parameter | Description | Example |
|---|---|---|
email |
Exact email match | ?email=john@example.com |
q |
Full-text search (name, email, company) | ?q=acme |
created_at[gte] |
Created on or after date | ?created_at[gte]=2024-01-01 |
deleted |
Include soft-deleted customers | ?deleted=true |
Query parameters
integer10string"550e8400-e29b-41d4-a716-446655440000"string"550e8400-e29b-41d4-a716-446655440001"string"created_at[desc]"string"john@example.com"string"acme"array[string]["vip"]booleanfalsefalsestring"payment_methods"string"2024-01-01"string"2024-02-01"string"id,email,first_name,created"Header parameters
string"2026-02-11"Code samples
# List first 20 customers
curl https://api.epd.com/v1/customers?limit=20 \
-H "Authorization: Bearer epd_test_sk_xxxx" \
-H "EPD-Version: 2026-02-11"
# Search by email
curl "https://api.epd.com/v1/customers?email=john@example.com" \
-H "Authorization: Bearer epd_test_sk_xxxx"
# Full-text search with date filter
curl "https://api.epd.com/v1/customers?q=acme&created_at[gte]=2024-01-01" \
-H "Authorization: Bearer epd_test_sk_xxxx" // List customers with pagination
const params = new URLSearchParams({
limit: '20',
expand: 'payment_methods',
});
const response = await fetch(
`https://api.epd.com/v1/customers?${params}`,
{
headers: {
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
},
}
);
const { data, has_more, cursors } = await response.json();
// Get next page
if (has_more) {
const nextPage = await fetch(
`https://api.epd.com/v1/customers?limit=20&starting_after=${cursors.next}`,
{ headers: { 'Authorization': 'Bearer epd_test_sk_xxxx' } }
);
} import requests
# List customers with filters
response = requests.get(
'https://api.epd.com/v1/customers',
headers={
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
},
params={
'limit': 20,
'expand': 'payment_methods',
'created_at[gte]': '2024-01-01',
}
)
result = response.json()
customers = result['data']
# Iterate through all pages
while result['has_more']:
response = requests.get(
'https://api.epd.com/v1/customers',
headers={'Authorization': 'Bearer epd_test_sk_xxxx'},
params={
'limit': 20,
'starting_after': result['cursors']['next'],
}
)
result = response.json()
customers.extend(result['data']) Responses
array[Customer]any"/v1/customers"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/customers/{id} Retrieve a customer
Retrieves the details of an existing customer by ID. Use expand to include related resources like payment methods or subscriptions in a single request.
Path parameters
string"550e8400-e29b-41d4-a716-446655440000"Query parameters
stringHeader parameters
string"2026-02-11"Code samples
# Basic retrieval
curl https://api.epd.com/v1/customers/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer epd_test_sk_xxxx"
# With expanded payment methods
curl "https://api.epd.com/v1/customers/550e8400-e29b-41d4-a716-446655440000?expand=payment_methods" \
-H "Authorization: Bearer epd_test_sk_xxxx" const response = await fetch(
'https://api.epd.com/v1/customers/550e8400-e29b-41d4-a716-446655440000?expand=payment_methods',
{
headers: { 'Authorization': 'Bearer epd_test_sk_xxxx' },
}
);
const customer = await response.json();
console.log(customer.email);
console.log(customer.payment_methods); // expanded Responses
string"550e8400-e29b-41d4-a716-446655440000"string (email)"john@example.com"string"John"string"Doe"string"+14155551234"string"Acme Corp"objectstring (uuid)"6ba7b818-9dad-11d1-80b4-00c04fd430c8"string"John Doe"string"123 Main St"string"Suite 100"string"San Francisco"string"CA"string"94105"string"US"string"+14155551234"Metadatastring"6ba7b815-9dad-11d1-80b4-00c04fd430c8"array[PaymentMethod]string (date-time)"2024-01-15T10:30:00.000Z"string (date-time)"2024-01-15T10:30:00.000Z"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/customers/{id} Update a customer
Updates the specified customer by setting the values of the parameters passed. Any parameters not provided remain unchanged.
Uniqueness constraints still apply — if you change the email or phone to a value already used by another customer, a 409 Conflict is returned.
Note: Deleted customers cannot be updated. Attempting to update a deleted customer returns a
400error.
Path parameters
string"550e8400-e29b-41d4-a716-446655440000"Header parameters
string"2026-02-11"string (uuid)"550e8400-e29b-41d4-a716-446655440000"Request body required
string (email)"newemail@example.com"string"Jane"string"Smith"string"+14155559876"string"Acme Corp"ShippingAddressMetadatastring"87654321"Code samples
curl -X PATCH https://api.epd.com/v1/customers/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer epd_test_sk_xxxx" \
-H "Content-Type: application/json" \
-H "X-EPD-Idempotency-Key: $(uuidgen)" \
-d '{
"email": "newemail@example.com",
"metadata": { "tier": "enterprise" }
}' const response = await fetch('https://api.epd.com/v1/customers/550e8400-e29b-41d4-a716-446655440000', {
method: 'PATCH',
headers: {
'Authorization': 'Bearer epd_test_sk_xxxx',
'Content-Type': 'application/json',
'X-EPD-Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
email: 'newemail@example.com',
metadata: { tier: 'enterprise' },
}),
});
const customer = await response.json(); Responses
string"550e8400-e29b-41d4-a716-446655440000"string (email)"john@example.com"string"John"string"Doe"string"+14155551234"string"Acme Corp"objectstring (uuid)"6ba7b818-9dad-11d1-80b4-00c04fd430c8"string"John Doe"string"123 Main St"string"Suite 100"string"San Francisco"string"CA"string"94105"string"US"string"+14155551234"Metadatastring"6ba7b815-9dad-11d1-80b4-00c04fd430c8"array[PaymentMethod]string (date-time)"2024-01-15T10:30:00.000Z"string (date-time)"2024-01-15T10:30:00.000Z"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/customers/{id} Delete a customer
Permanently deletes a customer. If the customer has order history, they are soft-deleted instead.
| Condition | Behavior |
|---|---|
| Has active/paused subscriptions | Blocked (400 error) |
| Has order history | Soft delete (deleted: true) |
| No order history | Hard delete (permanent) |
| Already deleted | Returns success (idempotent) |
Path parameters
string"550e8400-e29b-41d4-a716-446655440000"Header parameters
string"2026-02-11"string (uuid)"550e8400-e29b-41d4-a716-446655440000"Responses
string"550e8400-e29b-41d4-a716-446655440000"truestring"Customer successfully deleted."objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]