Skip to main content

Customer API

The Customer API provides endpoints for retrieving paginated lists of customers linked to stores that the authenticated user has access to.
All Customer API endpoints require authentication and a valid x-store-id header to identify the store context.

Overview

Customers can be:
  • Linked to a store (created automatically when a store is created)
  • Linked to a user account (created when a user signs up)
  • Created manually with a local name and optional default price list
  • Assigned or updated with a default price list
  • Filtered and sorted by various criteria
  • Retrieved in paginated lists
  • Bulk deleted from a store (remove multiple customer-store relations)

Endpoint Details

Base URL: /customers
Content-Type: application/json

Required Headers

Authorization: Bearer <token>
x-store-id: <store_id>
All routes require a valid x-store-id header. Users must have an active relation with the store to access its customers.

Get Customers

GET /customers Retrieve a paginated list of customers linked to a store that the authenticated user has access to. Requires Authentication: Bearer token in Authorization header

Required Headers

KeyValueRequiredDescription
x-store-idstringYesStore identifier (used by @StoreId() decorator)

Query Parameters

ParameterTypeRequiredDescriptionDefault
searchstringNoFilter customers by name (partial match)
namestringNoFilter customers by exact or partial name
isActivebooleanNoFilter by active/inactive status
pagenumberNoPage number (1-based)1
limitnumberNoNumber of items per page (1–100)10
sortBystringNoSort field (name, isActive, updatedAt, createdAt)createdAt
sortOrderstringNoSort direction (asc or desc)desc

Success Response

Status Code: 200 OK
{
  "data": [
    {
      "id": "cst_12345",
      "name": "Abdellah Chehri",
      "userId": "usr_789",
      "isActive": true,
      "createdAt": "2025-11-03T10:00:00.000Z",
      "updatedAt": "2025-11-03T10:30:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 12,
    "totalPages": 2,
    "hasNext": true,
    "hasPrev": false
  }
}

Response Fields

Customer Object

FieldTypeDescription
idstringUnique customer ID
namestringCustomer display name
localNamestring?Local name of the customer (if set)
defaultPriceListIdstring?Default price list ID (if assigned)
userIdstring?Related user ID (if created by user)
isActivebooleanActive status of customer
createdAtstringCreation timestamp (ISO 8601)
updatedAtstringLast update timestamp (ISO 8601)

Pagination Object

FieldTypeDescription
pagenumberCurrent page number
limitnumberNumber of items per page
totalnumberTotal number of records
totalPagesnumberTotal pages available
hasNextbooleanWhether a next page exists
hasPrevbooleanWhether a previous page exists

Possible Errors

CodeMessage
400Bad Request - Invalid query params or validation errors
403Forbidden - User does not have access to this store
500Internal Server Error - Failed to fetch customers

Example Requests

Get all customers with default pagination:
curl -X GET "https://jethings-backend.fly.dev/customers" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here"
Search customers by name:
curl -X GET "https://jethings-backend.fly.dev/customers?search=john&page=1&limit=10&sortBy=name&sortOrder=asc" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here"
Filter by active status:
curl -X GET "https://jethings-backend.fly.dev/customers?isActive=true&page=1&limit=20" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here"
Filter by exact name:
curl -X GET "https://jethings-backend.fly.dev/customers?name=John%20Doe" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here"

Create Customer

POST /customers Create a new customer and link them to the current store. You can optionally assign a default price list. Requires Authentication: Bearer token in Authorization header

Required Headers

KeyValueRequiredDescription
x-store-idstringYesStore identifier (used by @StoreId() decorator)

Request Body

{
  "localName": "Ali's Boutique",
  "defaultPriceListId": "pl_abc123"
}

Request Body Fields

FieldTypeRequiredDescription
localNamestringYesThe local name of the customer
defaultPriceListIdstring (UUID)NoOptional price list ID to assign

Success Response

Status Code: 200 OK
{
  "customer": {
    "id": "cst_abc123",
    "localName": "Ali's Boutique",
    "defaultPriceListId": "pl_abc123",
    "isActive": true,
    "createdAt": "2025-11-03T10:00:00.000Z",
    "updatedAt": "2025-11-03T10:00:00.000Z"
  },
  "customerStore": {
    "id": "csr_987",
    "customerId": "cst_abc123",
    "storeId": "str_12345",
    "createdAt": "2025-11-03T10:00:00.000Z"
  }
}

Response Fields

Customer Object

FieldTypeDescription
idstringUnique customer ID
localNamestringLocal name of the customer
defaultPriceListIdstring?Default price list ID (if assigned)
isActivebooleanActive status of customer
createdAtstringCreation timestamp (ISO 8601)
updatedAtstringLast update timestamp (ISO 8601)

CustomerStore Object

FieldTypeDescription
idstringUnique customer-store relation ID
customerIdstringCustomer ID
storeIdstringStore ID
createdAtstringCreation timestamp (ISO 8601)

Possible Errors

CodeMessage
400Bad Request - Invalid request data or validation errors
403Forbidden - User does not have access to this store
404Not Found - Price list not found (if defaultPriceListId provided)
500Internal Server Error - Failed to create customer

Example Request

curl -X POST "https://jethings-backend.fly.dev/customers" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here" \
  -d '{
    "localName": "Ali'\''s Boutique",
    "defaultPriceListId": "pl_abc123"
  }'
Create customer without price list:
curl -X POST "https://jethings-backend.fly.dev/customers" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here" \
  -d '{
    "localName": "New Customer"
  }'

Set Customer Price List

PUT /customers/:customerId/price-list Assign or update the default price list of a customer. Optionally update the customer’s name at the same time. Requires Authentication: Bearer token in Authorization header

Required Headers

KeyValueRequiredDescription
x-store-idstringYesStore identifier (used by @StoreId() decorator)

Path Parameters

ParameterTypeRequiredDescription
customerIdstringYesThe ID of the customer

Request Body

{
  "priceListId": "pl_789xyz",
  "name": "Updated Customer Name"
}

Request Body Fields

FieldTypeRequiredDescription
priceListIdstring (UUID)YesThe price list ID to assign to this customer
namestringNoOptional name to update for the customer

Success Response

Status Code: 200 OK
{
  "success": true,
  "message": "Customer price list has been updated",
  "customer": {
    "id": "cst_abc123",
    "localName": "Ali's Boutique",
    "defaultPriceListId": "pl_789xyz",
    "isActive": true,
    "updatedAt": "2025-11-03T11:00:00.000Z"
  }
}

Response Fields

FieldTypeDescription
successbooleanOperation success status
messagestringSuccess message
customerobjectUpdated customer object
customer.idstringUnique customer ID
customer.localNamestringLocal name of the customer
customer.defaultPriceListIdstring?Default price list ID (if assigned)
customer.isActivebooleanActive status of customer
customer.updatedAtstringLast update timestamp (ISO 8601)

Possible Errors

CodeMessage
400Bad Request - Invalid request data or validation errors
403Forbidden - User does not have access to this store
404Not Found - Customer or price list not found
500Internal Server Error - Failed to update customer price list

Example Requests

Set price list only:
curl -X PUT "https://jethings-backend.fly.dev/customers/cst_abc123/price-list" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here" \
  -d '{
    "priceListId": "pl_789xyz"
  }'
Set price list with customer name update:
curl -X PUT "https://jethings-backend.fly.dev/customers/cst_abc123/price-list" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here" \
  -d '{
    "priceListId": "pl_789xyz",
    "name": "Updated Customer Name"
  }'

Remove Customer Price List

DELETE /customers/:customerId/price-list Remove the default price list from a customer. Requires Authentication: Bearer token in Authorization header

Required Headers

KeyValueRequiredDescription
x-store-idstringYesStore identifier (used by @StoreId() decorator)

Path Parameters

ParameterTypeRequiredDescription
customerIdstringYesThe ID of the customer

Success Response

Status Code: 200 OK
{
  "success": true,
  "message": "Customer price list has been removed",
  "customer": {
    "id": "cst_abc123",
    "localName": "Ali's Boutique",
    "defaultPriceListId": null,
    "isActive": true,
    "updatedAt": "2025-11-03T11:15:00.000Z"
  }
}

Response Fields

FieldTypeDescription
successbooleanOperation success status
messagestringSuccess message
customerobjectUpdated customer object
customer.idstringUnique customer ID
customer.localNamestringLocal name of the customer
customer.defaultPriceListIdnullPrice list removed (set to null)
customer.isActivebooleanActive status of customer
customer.updatedAtstringLast update timestamp (ISO 8601)

Possible Errors

CodeMessage
403Forbidden - User does not have access to this store
404Not Found - Customer not found
500Internal Server Error - Failed to remove customer price list

Example Request

curl -X DELETE "https://jethings-backend.fly.dev/customers/cst_abc123/price-list" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here"

Bulk Delete Customers

DELETE /customers/bulk Remove multiple customers from the current store in one request. This deletes the customer-store relations for the provided IDs; it does not delete the underlying customer records globally. Requires Authentication: Bearer token in Authorization header

Required Headers

KeyValueRequiredDescription
x-store-idstringYesStore identifier (used by @StoreId() decorator)

Request Body

{
  "ids": ["cst_123", "cst_456", "cst_789"]
}

Request Body Fields

FieldTypeRequiredDescription
idsstring[] UUIDYesList of customer IDs linked to this store to remove

Success Response

Status Code: 200 OK
{
  "message": "Customers removed from store",
  "deletedCount": 3
}

Possible Errors

CodeMessage
400No customer IDs provided
403User does not have access to this store
500Internal Server Error

Example Request

curl -X DELETE "https://jethings-backend.fly.dev/customers/bulk" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-store-id: store_id_here" \
  -d '{
    "ids": ["cst_123", "cst_456"]
  }'

Data Models

CustomerResponseDto

FieldTypeDescription
idstringUnique customer ID
namestringCustomer display name
localNamestring?Local name of the customer (if set)
defaultPriceListIdstring?Default price list ID (if assigned)
userIdstring?Related user ID (if created by user)
isActivebooleanActive status of customer
createdAtDateCreation timestamp
updatedAtDateLast update timestamp

PaginationDto

FieldTypeDescription
pagenumberCurrent page number
limitnumberNumber of items per page
totalnumberTotal number of records
totalPagesnumberTotal pages available
hasNextbooleanWhether a next page exists
hasPrevbooleanWhether a previous page exists

PaginatedCustomersResponseDto

{
  data: CustomerResponseDto[];
  pagination: PaginationDto;
}

Summary

EndpointMethodDescription
/customersGETRetrieve paginated list of customers for a store
/customersPOSTCreate a new customer and link to store
/customers/:customerId/price-listPUTAssign or update customer’s default price list
/customers/:customerId/price-listDELETERemove customer’s default price list
/customers/bulkDELETEBulk remove customers from the current store

Security & Validation

  • All routes require a valid x-store-id header
  • User must have an active relation with the store to access its customers
  • Store ID validation prevents unauthorized access
  • Pagination limits are enforced (max 100 items per page)

Business Logic

Customer Creation

  • Customers can be created manually via POST /customers with a localName
  • When creating a customer, you can optionally assign a defaultPriceListId
  • Creating a customer automatically creates a CustomerStore relation linking the customer to the store
  • The price list must exist and be active if provided

Customer Price List Management

  • Customers can have a default price list assigned via PUT /customers/:customerId/price-list
  • The price list must exist and be active (verified by verifyPriceList())
  • Optionally, you can update the customer’s name when setting the price list by including the name field in the request
  • Price lists can be removed via DELETE /customers/:customerId/price-list
  • Removing a price list sets defaultPriceListId to null

Customer Retrieval

  • Returns paginated lists of customers for a specific store
  • Supports filtering by name (exact or partial match) and active status
  • Supports sorting by name, isActive, updatedAt, or createdAt
  • Default sorting is by createdAt in descending order (newest first)
  • Pagination is 1-based (first page is page 1)

Internal Methods

These methods are part of the internal business logic and are not exposed as public endpoints:
MethodPurpose
verifyPriceList()Checks if a price list exists and is active
createCustomerFromStore(storeId, storeName)Auto-creates customer entities for new stores
createCustomerFromUser(userId, firstName, lastName)Creates a customer linked to a user account
getCustomerByUserId(userId)Fetches the customer record for a specific user
getCustomerByStoreId(storeId)Returns the customer representing a store

Validation Rules

  • Page number must be >= 1
  • Limit must be between 1 and 100
  • SortBy must be one of: name, isActive, updatedAt, createdAt
  • SortOrder must be either asc or desc
  • User must have access to the specified store
  • localName is required when creating a customer
  • priceListId must be a valid UUID and reference an existing, active price list
  • Bulk delete requires at least one valid UUID in ids
  • Only customers linked to the specified store will be removed

Error Responses

Common Error Codes

CodeDescription
400Bad Request - Invalid input or validation
403Forbidden - User does not have access to this store
500Internal Server Error - Database or server error

Error Response Format

{
  "message": "Error description",
  "statusCode": 400
}

Example Error Responses

403 Forbidden:
{
  "message": "You do not have access to this store",
  "statusCode": 403
}
400 Bad Request:
{
  "message": "Invalid page number",
  "statusCode": 400
}
500 Internal Server Error:
{
  "message": "Failed to fetch customers",
  "statusCode": 500
}