Customers

Customers API

Manage customer profiles, multiple addresses, and marketing preferences. Customers are required for creating orders.

Endpoints

MethodEndpointDescription
GET/customersList all customers
POST/customersCreate a customer
GET/customers/:idGet a customer
PUT/customers/:idUpdate a customer
DELETE/customers/:idDelete a customer

All endpoints are prefixed with /stores/{storeId}.

The Customer Object

{
  "id": "cust_abc123",
  "storeId": "store_xyz789",
  "email": "john.doe@example.com",
  "name": "John Doe",
  "phone": "+1-555-123-4567",
  "marketingOptIn": true,
  "defaultAddressId": "addr_001",
  "addresses": [
    {
      "id": "addr_001",
      "firstName": "John",
      "lastName": "Doe",
      "company": null,
      "address1": "123 Main Street",
      "address2": "Apt 4B",
      "city": "New York",
      "region": "NY",
      "postalCode": "10001",
      "country": "US",
      "phone": "+1-555-123-4567",
      "isDefault": true,
      "createdAt": "2024-01-10T08:00:00.000Z",
      "updatedAt": "2024-01-10T08:00:00.000Z"
    }
  ],
  "createdAt": "2024-01-10T08:00:00.000Z",
  "updatedAt": "2024-01-15T10:30:00.000Z"
}

Customer Fields

FieldTypeDescription
idstringUnique identifier (UUID)
emailstringEmail address (unique per store, required)
namestring?Full name
phonestring?Phone number
marketingOptInbooleanMarketing email consent
defaultAddressIdstring?ID of default shipping address
addressesAddress[]Array of saved addresses

Address Fields

FieldTypeDescription
address1stringStreet address (required)
address2string?Apt, suite, unit, etc.
citystringCity (required)
regionstring?State/province/region
postalCodestringPostal/ZIP code (required)
countrystringCountry code or name (required)
firstNamestring?Recipient first name
lastNamestring?Recipient last name
companystring?Company name
phonestring?Phone for delivery
isDefaultbooleanIs this the default address

List Customers

GET /stores/{storeId}/customers

Query Parameters

ParameterTypeDescription
limitintegerResults per page (1-200, default: 50)
offsetintegerNumber of items to skip
emailstringFind by exact email
searchstringSearch in email, name, phone

Example

curl "https://api.barecommercecore.com/stores/{storeId}/customers?search=john" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"

Create Customer

POST /stores/{storeId}/customers

Required Fields

  • email — Valid email address (unique per store)

Example

curl -X POST "https://api.barecommercecore.com/stores/{storeId}/customers" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane.smith@example.com",
    "name": "Jane Smith",
    "phone": "+1-555-987-6543",
    "marketingOptIn": true,
    "addresses": [
      {
        "firstName": "Jane",
        "lastName": "Smith",
        "address1": "789 Oak Avenue",
        "city": "Los Angeles",
        "region": "CA",
        "postalCode": "90001",
        "country": "US",
        "isDefault": true
      }
    ]
  }'

Get Customer

GET /stores/{storeId}/customers/{customerId}

Returns the customer with all their addresses.

Update Customer

PUT /stores/{storeId}/customers/{customerId}

Only include fields you want to change.

Example: Update Profile

curl -X PUT "https://api.barecommercecore.com/stores/{storeId}/customers/cust_abc123" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "John D. Smith", "marketingOptIn": false }'

Address Updates (Replace-All Semantics)

⚠️ When you include addresses in an update, it replaces the entire address list. Include all addresses you want to keep.

  • Include id for existing addresses you want to keep/modify
  • Addresses without id are created as new
  • Existing addresses not in your request are deleted
// Fetch current customer
const customer = await getCustomer(customerId);
 
// Modify and add addresses
const addresses = customer.addresses.map(addr => {
  if (addr.id === 'addr_001') {
    return { ...addr, address1: '999 New Street' };
  }
  return addr;
});
 
// Add new address (no id)
addresses.push({
  firstName: 'John',
  address1: '100 Work Plaza',
  city: 'New York',
  region: 'NY',
  postalCode: '10003',
  country: 'US',
});
 
// Send complete array
await updateCustomer(customerId, { addresses });

Delete Customer

DELETE /stores/{storeId}/customers/{customerId}

Returns 204 No Content on success.

⚠️ Cannot delete customers with orders. This preserves order history integrity.

Common Patterns

Find or Create Customer (Checkout)

async function findOrCreateCustomer(email, name, phone) {
  const { items } = await fetch(
    `/stores/{storeId}/customers?email=${encodeURIComponent(email)}`,
    { headers: { 'Authorization': 'Bearer ' + apiKey } }
  ).then(r => r.json());
 
  if (items.length > 0) {
    return items[0];
  }
 
  return fetch('/stores/{storeId}/customers', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + apiKey,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ email, name, phone }),
  }).then(r => r.json());
}

Set Default Address

await fetch(`/stores/{storeId}/customers/${customerId}`, {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer sk_live_YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    defaultAddressId: 'addr_002',
  }),
});

Error Responses

409 Duplicate Email

{
  "error": {
    "code": "CONFLICT",
    "message": "Customer with this email already exists"
  }
}

409 Has Orders

{
  "error": {
    "code": "CONFLICT",
    "message": "Cannot delete customer with existing orders"
  }
}

Webhooks

  • customer.created — New customer registered
  • customer.updated — Profile or addresses modified
  • customer.deleted — Customer deleted

Related Guides

  • Orders — Create orders for customers