Skip to main content

Customer API

The Customer API allows you to create optical customers with their personal information, prescription data, and manage customer records. This endpoint supports file uploads for prescriptions and other documents.
This endpoint uses multipart/form-data format to support file uploads. Make sure to include the proper headers when making requests.

Endpoint Details

Base URL: https://j-optic.fly.dev

Required Headers

x-store-id: <store_id>
Authorization: Bearer <token>

Create Customer

Endpoint

Endpoint: POST /customer
Content-Type: multipart/form-data

Request Structure

The request uses multipart/form-data format with:
  • jsonData: A JSON string containing the customer data
  • Files: Optional prescription documents or attachments uploaded with specific field names

Customer Data Structure

The jsonData field must contain a JSON string with the following structure:
FieldTypeRequiredDescription
customerDataobject✅ YesPersonal information of the customer
addressobjectNoCustomer address details
opticDataobjectNoOptical prescription measurements

CustomerData Object

FieldTypeRequiredDescription
firstNamestring✅ YesCustomer’s first name
lastNamestring✅ YesCustomer’s last name
emailstring✅ YesCustomer’s email address (unique)
phoneNumberstring✅ YesCustomer’s phone number
dateOfBirthstring (ISO Date)✅ YesDate of birth in ISO format
sexstring✅ YesGender: “male” or “female”

Address Object

FieldTypeRequiredDescription
streetstringNoStreet address
citystringNoCity name
zipCodestringNoPostal/ZIP code
statestringNoState or province

OpticData Object

Contains vision prescription data for different viewing distances:
FieldTypeRequiredDescription
distanceVisionobjectNoDistance vision prescription
intermediateVisionobjectNoIntermediate vision prescription
nearVisionobjectNoNear vision prescription
Each vision object contains rightEye and leftEye with:
  • sph (sphere): Spherical power
  • cyl (cylinder): Cylindrical power
  • axis: Axis measurement

Create Customer Examples

Example 1: Create Customer with Full Optical Data

curl -X POST https://j-optic.fly.dev/customer \
  -H "x-store-id: your-store-id" \
  -H "Authorization: Bearer <token>" \
  -F 'jsonData={
    "customerData": {
      "firstName": "Layla",
      "lastName": "Hassan",
      "email": "[email protected]",
      "phoneNumber": "+1-555-0199",
      "dateOfBirth": "1992-05-12T00:00:00.000Z",
      "sex": "female"
    },
    "address": {
      "street": "123 Vision Ave",
      "city": "Casablanca",
      "zipCode": "20000",
      "state": "MA"
    },
    "opticData": {
      "distanceVision": {
        "rightEye": { "sph": "-1.25", "cyl": "-0.25", "axis": "90" },
        "leftEye": { "sph": "-1.00", "cyl": "-0.25", "axis": "85" }
      },
      "intermediateVision": {
        "rightEye": { "sph": "-0.75", "cyl": "0", "axis": "0" },
        "leftEye": { "sph": "-0.75", "cyl": "0", "axis": "0" }
      },
      "nearVision": {
        "rightEye": { "sph": "-0.50", "cyl": "0", "axis": "0" },
        "leftEye": { "sph": "-0.50", "cyl": "0", "axis": "0" }
      }
    }
  }' \
  -F '[email protected]' \
  -F '[email protected]'
Success Response:
{
  "customer": {
    "id": "customer-uuid",
    "isActive": true,
    "createdAt": "2024-01-15T10:00:00.000Z",
    "updatedAt": "2024-01-15T10:00:00.000Z",
    "deletedAt": null
  },
  "localData": {
    "id": "local-data-uuid",
    "firstName": "Layla",
    "lastName": "Hassan",
    "email": "[email protected]",
    "phoneNumber": "+1-555-0199",
    "dateOfBirth": "1992-05-12T00:00:00.000Z",
    "sex": "female",
    "customerId": "customer-uuid"
  }
}

Example 2: Create Customer with Minimal Data

curl -X POST https://j-optic.fly.dev/customer \
  -H "x-store-id: your-store-id" \
  -H "Authorization: Bearer <token>" \
  -F 'jsonData={
    "customerData": {
      "firstName": "Ahmed",
      "lastName": "Benali",
      "email": "[email protected]",
      "phoneNumber": "+212-6-12345678",
      "dateOfBirth": "1985-08-20T00:00:00.000Z",
      "sex": "male"
    }
  }'

Get All Customers

Endpoint

Endpoint: GET /customer

Query Parameters

ParameterTypeRequiredDefaultDescription
searchstringNo-Search by first name, last name, or username
namestringNo-Filter by specific name (first or last)
isActivebooleanNo-Filter by active status
pagenumberNo1Page number for pagination
limitnumberNo10Number of records per page
sortBystringNocreatedAtSort field: “name”, “status”, “createdAt”, “updatedAt”
sortOrderstringNodescSort order: “asc” or “desc”

Get Customers Examples

Example 1: Get All Customers (Default Pagination)

curl -X GET "https://j-optic.fly.dev/customer" \
  -H "x-store-id: your-store-id" \
  -H "Authorization: Bearer <token>"

Example 2: Search Customers with Filters

curl -X GET "https://j-optic.fly.dev/customer?search=Hassan&isActive=true&page=1&limit=20&sortBy=name&sortOrder=asc" \
  -H "x-store-id: your-store-id" \
  -H "Authorization: Bearer <token>"
Success Response:
{
  "data": [
    {
      "id": "customer-uuid",
      "name": "Layla Hassan",
      "userName": "[email protected]",
      "groups": [
        {
          "id": "group-uuid",
          "name": "VIP Customers"
        }
      ],
      "isLocal": true,
      "status": "active",
      "createdAt": "2024-01-15T10:00:00.000Z",
      "updatedAt": "2024-01-15T10:00:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 45,
    "totalPages": 3
  }
}

Example 3: Get Active Customers Only

curl -X GET "https://j-optic.fly.dev/customer?isActive=true&sortBy=createdAt&sortOrder=desc" \
  -H "x-store-id: your-store-id" \
  -H "Authorization: Bearer <token>"

Response Structures

Create Customer Response

{
  "customer": {
    "id": "customer-uuid",
    "isActive": true,
    "createdAt": "2024-01-15T10:00:00.000Z",
    "updatedAt": "2024-01-15T10:00:00.000Z",
    "deletedAt": null
  },
  "localData": {
    "id": "local-data-uuid",
    "firstName": "string",
    "lastName": "string",
    "email": "string",
    "phoneNumber": "string",
    "dateOfBirth": "ISO date string",
    "sex": "male | female",
    "customerId": "customer-uuid"
  }
}

Get Customers Response

{
  "data": [
    {
      "id": "customer-uuid",
      "name": "Full Name",
      "userName": "[email protected]",
      "groups": [
        {
          "id": "group-uuid",
          "name": "Group Name"
        }
      ],
      "isLocal": true,
      "status": "active | unactive",
      "createdAt": "ISO date string",
      "updatedAt": "ISO date string"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 100,
    "totalPages": 10
  }
}

Error Responses

400 Bad Request

{
  "statusCode": 400,
  "message": "Invalid input data or missing required fields",
  "error": "Bad Request"
}

403 Forbidden

{
  "statusCode": 403,
  "message": "You do not have access to this store",
  "error": "Forbidden"
}

409 Conflict

{
  "statusCode": 409,
  "message": "Customer with this email already exists",
  "error": "Conflict"
}

500 Internal Server Error

{
  "statusCode": 500,
  "message": "Failed to create customer",
  "error": "Internal Server Error"
}

Important Notes

Store Access Requirements

  • Requires user to be an owner of the store
  • Validates userStoreRelation for active owner relationship
  • Missing ownership raises ForbiddenException
  • Requires user to have access to the store
  • Can be owner or have assigned role/permissions
  • Store access is validated via userStoreRelation

Email Handling

  • Email addresses are trimmed and stored as provided
  • Email must be unique per store
  • Duplicate emails result in ConflictException (409)

File Uploads

Supported Files

Upload prescription documents, ID cards, or related files
Grouped by fieldname

Optional Upload

Files are optional for customer creation
Basic customer data sufficient

Customer Status

  • Customers are created with isActive: true by default
  • Status can be filtered in GET requests using isActive parameter
  • Deleted customers have deletedAt timestamp (soft delete)

Name Display Logic

The customer name follows this fallback order:
  1. firstName + lastName from local data
  2. userName from user table
  3. Placeholder value if neither available

Pagination

{
  page: 1,
  limit: 10,
  sortBy: "createdAt",
  sortOrder: "desc"
}
Returns 10 most recent customers by default

Summary

1

Authenticate

Obtain JWT token and ensure store access
2

Prepare Customer Data

Structure JSON with required customer information
3

Create Customer

POST request with multipart form data
4

Retrieve Customers

GET request with optional filters and pagination
5

Handle Response

Process customer data and pagination metadata
This API provides comprehensive customer management for optical stores, including prescription data storage, file uploads, and flexible querying with pagination and filtering capabilities.