GET
/
wp-json
/
latepoint-api
/
v1
/
customers
/
{id}
Get Customer
curl --request GET \
  --url https://your-site.com/wp-json/latepoint-api/v1/customers/{id} \
  --header 'X-API-Key: <x-api-key>'
{
  "status": "error",
  "error": {
    "code": "customer_not_found",
    "message": "Customer with ID 45 was not found"
  }
}

Description

This endpoint returns all available information for a specific customer, including their personal data, statistics, bookings, and custom fields.

Authentication

X-API-Key
string
required
Your LatePoint API Key with read permissions

Path Parameters

id
integer
required
Unique ID of the customer to retrieve

Query Parameters

Included Fields

include
string
Additional fields to include in the response (comma-separated)Possible values:
  • bookings - Include all customer bookings
  • upcoming_bookings - Only future bookings
  • past_bookings - Only past bookings
  • stats - Include detailed statistics
  • custom_fields - Include custom fields
  • notes - Include customer notes
  • avatar - Include avatar information
bookings_limit
integer
default:"10"
Limit of bookings to include (when including bookings)
bookings_status
string
Filter bookings by specific statusPossible values:
  • pending - Pending
  • confirmed - Confirmed
  • completed - Completed
  • cancelled - Cancelled
  • no_show - No show

Response

Successful Response (200 OK)

status
string
Response status (“success”)
data
object
Complete customer object

Examples

Get Basic Customer

curl -X GET "https://your-site.com/wp-json/latepoint-api/v1/customers/45" \
  -H "X-API-Key: lp_live_1234567890abcdef"

Get Customer with Complete Information

curl -X GET "https://your-site.com/wp-json/latepoint-api/v1/customers/45?include=stats,bookings,custom_fields,preferences&bookings_limit=20" \
  -H "X-API-Key: lp_live_1234567890abcdef"

Get Only Future Bookings

curl -X GET "https://your-site.com/wp-json/latepoint-api/v1/customers/45?include=upcoming_bookings&bookings_limit=5" \
  -H "X-API-Key: lp_live_1234567890abcdef"

Example Response

Complete Customer

{
  "status": "success",
  "data": {
    "id": 45,
    "first_name": "John",
    "last_name": "Smith",
    "email": "john.smith@email.com",
    "phone": "+1 555 123 4567",
    "status": "active",
    "avatar_url": "https://your-site.com/wp-content/uploads/avatars/45.jpg",
    "date_of_birth": "1985-03-15",
    "gender": "male",
    "address": {
      "street": "123 Main Street",
      "city": "New York",
      "state": "NY",
      "postal_code": "10001",
      "country": "United States"
    },
    "created_at": "2023-06-15T10:30:00Z",
    "updated_at": "2024-01-20T14:15:00Z",
    "stats": {
      "total_bookings": 12,
      "completed_bookings": 10,
      "cancelled_bookings": 2,
      "no_show_bookings": 0,
      "pending_bookings": 1,
      "total_spent": "850.00",
      "average_booking_value": "70.83",
      "first_booking_date": "2023-06-20T14:30:00Z",
      "last_booking_date": "2024-01-15T14:30:00Z",
      "next_booking_date": "2024-01-25T16:00:00Z",
      "favorite_agent": {
        "id": 3,
        "display_name": "Dr. Sarah Johnson",
        "booking_count": 8
      },
      "favorite_service": {
        "id": 7,
        "name": "General Consultation",
        "booking_count": 6
      },
      "favorite_location": {
        "id": 1,
        "name": "Main Clinic",
        "booking_count": 10
      },
      "booking_frequency": "monthly"
    },
    "bookings": [
      {
        "id": 123,
        "booking_code": "LP-2024-001",
        "status": "confirmed",
        "start_date": "2024-01-25",
        "start_time": "16:00",
        "end_time": "17:00",
        "service": {
          "id": 7,
          "name": "General Consultation",
          "duration": 60
        },
        "agent": {
          "id": 3,
          "display_name": "Dr. Sarah Johnson",
          "email": "sarah.johnson@clinic.com"
        },
        "location": {
          "id": 1,
          "name": "Main Clinic",
          "address": "123 Main Street, NY"
        },
        "price": "75.00",
        "payment_status": "paid"
      },
      {
        "id": 118,
        "booking_code": "LP-2024-002",
        "status": "completed",
        "start_date": "2024-01-15",
        "start_time": "14:30",
        "end_time": "15:30",
        "service": {
          "id": 7,
          "name": "General Consultation",
          "duration": 60
        },
        "agent": {
          "id": 3,
          "display_name": "Dr. Sarah Johnson",
          "email": "sarah.johnson@clinic.com"
        },
        "location": {
          "id": 1,
          "name": "Main Clinic",
          "address": "123 Main Street, NY"
        },
        "price": "75.00",
        "payment_status": "paid"
      }
    ],
    "custom_fields": {
      "emergency_contact": "Jane Smith - +1 555 987 6543",
      "preferred_language": "en",
      "medical_notes": "Allergic to penicillin",
      "insurance_provider": "Blue Cross Blue Shield",
      "referral_source": "Google"
    },
    "notes": "Very punctual and friendly customer. Prefers afternoon appointments.",
    "notes": "Very punctual and friendly customer. Prefers afternoon appointments."
  }
}

Error Codes

{
  "status": "error",
  "error": {
    "code": "customer_not_found",
    "message": "Customer with ID 45 was not found"
  }
}

Common Use Cases

1. Complete Customer Profile

// Function to get complete customer profile
async function getCustomerProfile(customerId) {
  try {
    const params = new URLSearchParams({
      include: 'stats,upcoming_bookings,custom_fields,preferences,notes',
      bookings_limit: 10
    });
    
    const response = await fetch(
      `/wp-json/latepoint-api/v1/customers/${customerId}?${params}`,
      {
        headers: { 'X-API-Key': 'your_api_key' }
      }
    );
    
    if (!response.ok) {
      throw new Error(`Error ${response.status}: ${response.statusText}`);
    }
    
    const result = await response.json();
    
    if (result.status === 'success') {
      const customer = result.data;
      
      return {
        basicInfo: {
          id: customer.id,
          name: `${customer.first_name} ${customer.last_name}`,
          email: customer.email,
          phone: customer.phone,
          status: customer.status
        },
        stats: customer.stats,
        upcomingBookings: customer.bookings || [],
        preferences: customer.preferences,
        customFields: customer.custom_fields,
        notes: customer.notes
      };
    } else {
      throw new Error(result.error.message);
    }
  } catch (error) {
    console.error('Error getting customer profile:', error);
    throw error;
  }
}

// Usage
const profile = await getCustomerProfile(45);
console.log('Customer profile:', profile);

2. Check Booking History

// Function to analyze customer history
async function analyzeCustomerHistory(customerId) {
  const params = new URLSearchParams({
    include: 'stats,bookings',
    bookings_limit: 50
  });
  
  const response = await fetch(
    `/wp-json/latepoint-api/v1/customers/${customerId}?${params}`,
    {
      headers: { 'X-API-Key': 'your_api_key' }
    }
  );
  
  const result = await response.json();
  
  if (result.status === 'success') {
    const customer = result.data;
    const stats = customer.stats;
    const bookings = customer.bookings || [];
    
    // Pattern analysis
    const analysis = {
      customerInfo: {
        name: `${customer.first_name} ${customer.last_name}`,
        memberSince: customer.created_at,
        status: customer.status
      },
      loyaltyMetrics: {
        totalBookings: stats.total_bookings,
        completionRate: ((stats.completed_bookings / stats.total_bookings) * 100).toFixed(1),
        noShowRate: ((stats.no_show_bookings / stats.total_bookings) * 100).toFixed(1),
        averageValue: stats.average_booking_value,
        totalSpent: stats.total_spent
      },
      preferences: {
        favoriteAgent: stats.favorite_agent?.display_name,
        favoriteService: stats.favorite_service?.name,
        favoriteLocation: stats.favorite_location?.name,
        bookingFrequency: stats.booking_frequency
      },
      recentActivity: {
        lastBooking: stats.last_booking_date,
        nextBooking: stats.next_booking_date,
        daysSinceLastBooking: stats.last_booking_date ? 
          Math.floor((new Date() - new Date(stats.last_booking_date)) / (1000 * 60 * 60 * 24)) : null
      },
      riskAssessment: {
        riskLevel: calculateRiskLevel(stats),
        recommendations: generateRecommendations(stats, bookings)
      }
    };
    
    return analysis;
  }
  
  throw new Error('Error getting customer data');
}

function calculateRiskLevel(stats) {
  const daysSinceLastBooking = stats.last_booking_date ? 
    Math.floor((new Date() - new Date(stats.last_booking_date)) / (1000 * 60 * 60 * 24)) : 999;
  
  const noShowRate = (stats.no_show_bookings / stats.total_bookings) * 100;
  
  if (daysSinceLastBooking > 180 || noShowRate > 20) return 'high';
  if (daysSinceLastBooking > 90 || noShowRate > 10) return 'medium';
  return 'low';
}

function generateRecommendations(stats, bookings) {
  const recommendations = [];
  
  const daysSinceLastBooking = stats.last_booking_date ? 
    Math.floor((new Date() - new Date(stats.last_booking_date)) / (1000 * 60 * 60 * 24)) : 999;
  
  if (daysSinceLastBooking > 90) {
    recommendations.push('Send reactivation campaign');
  }
  
  if (stats.no_show_bookings > 2) {
    recommendations.push('Implement additional reminders');
  }
  
  if (stats.total_bookings > 10 && stats.total_spent > 500) {
    recommendations.push('Candidate for loyalty program');
  }
  
  return recommendations;
}

3. Customer Information Widget

// Create quick customer information widget
function createCustomerWidget(customerId, containerId) {
  async function loadCustomerWidget() {
    try {
      const params = new URLSearchParams({
        include: 'stats,upcoming_bookings',
        bookings_limit: 3
      });
      
      const response = await fetch(
        `/wp-json/latepoint-api/v1/customers/${customerId}?${params}`,
        {
          headers: { 'X-API-Key': 'your_api_key' }
        }
      );
      
      const result = await response.json();
      
      if (result.status === 'success') {
        const customer = result.data;
        const container = document.getElementById(containerId);
        
        container.innerHTML = `
          <div class="customer-widget">
            <div class="customer-header">
              <img src="${customer.avatar_url || '/default-avatar.png'}" alt="Avatar" class="avatar">
              <div class="customer-info">
                <h3>${customer.first_name} ${customer.last_name}</h3>
                <p class="email">${customer.email}</p>
                <p class="phone">${customer.phone}</p>
                <span class="status status-${customer.status}">${customer.status}</span>
              </div>
            </div>
            
            <div class="customer-stats">
              <div class="stat">
                <span class="label">Total Bookings:</span>
                <span class="value">${customer.stats.total_bookings}</span>
              </div>
              <div class="stat">
                <span class="label">Total Spent:</span>
                <span class="value">$${customer.stats.total_spent}</span>
              </div>
              <div class="stat">
                <span class="label">Last Visit:</span>
                <span class="value">${formatDate(customer.stats.last_booking_date)}</span>
              </div>
            </div>
            
            <div class="upcoming-bookings">
              <h4>Upcoming Appointments</h4>
              ${customer.bookings && customer.bookings.length > 0 ? 
                customer.bookings.map(booking => `
                  <div class="booking-item">
                    <span class="date">${formatDate(booking.start_date)} ${booking.start_time}</span>
                    <span class="service">${booking.service.name}</span>
                  </div>
                `).join('') : 
                '<p class="no-bookings">No upcoming appointments</p>'
              }
            </div>
          </div>
        `;
      }
    } catch (error) {
      console.error('Error loading customer widget:', error);
      document.getElementById(containerId).innerHTML = 
        '<div class="error">Error loading customer information</div>';
    }
  }
  
  function formatDate(dateString) {
    if (!dateString) return 'N/A';
    return new Date(dateString).toLocaleDateString('en-US');
  }
  
  loadCustomerWidget();
}

// Usage
createCustomerWidget(45, 'customer-widget-container');

4. Customer Validation for Bookings

// Validate customer before creating a booking
async function validateCustomerForBooking(customerId) {
  try {
    const params = new URLSearchParams({
      include: 'stats,upcoming_bookings'
    });
    
    const response = await fetch(
      `/wp-json/latepoint-api/v1/customers/${customerId}?${params}`,
      {
        headers: { 'X-API-Key': 'your_api_key' }
      }
    );
    
    const result = await response.json();
    
    if (result.status === 'success') {
      const customer = result.data;
      const validation = {
        isValid: true,
        warnings: [],
        errors: [],
        customer: customer
      };
      
      // Check customer status
      if (customer.status === 'blocked') {
        validation.isValid = false;
        validation.errors.push('Customer blocked - cannot make bookings');
      }
      
      if (customer.status === 'inactive') {
        validation.warnings.push('Customer inactive - verify information');
      }
      
      // Check no-show history
      const noShowRate = (customer.stats.no_show_bookings / customer.stats.total_bookings) * 100;
      if (noShowRate > 20) {
        validation.warnings.push(`High no-show rate (${noShowRate.toFixed(1)}%)`);
      }
      
      // Check pending bookings
      const pendingBookings = customer.bookings?.filter(b => b.status === 'pending') || [];
      if (pendingBookings.length > 2) {
        validation.warnings.push(`Has ${pendingBookings.length} pending bookings`);
      }
      
      // Check contact information
      if (!customer.phone || !customer.email) {
        validation.warnings.push('Incomplete contact information');
      }
      
      return validation;
    } else {
      return {
        isValid: false,
        errors: ['Customer not found'],
        warnings: [],
        customer: null
      };
    }
  } catch (error) {
    return {
      isValid: false,
      errors: ['Error validating customer'],
      warnings: [],
      customer: null
    };
  }
}

// Usage
const validation = await validateCustomerForBooking(45);

if (validation.isValid) {
  if (validation.warnings.length > 0) {
    console.warn('Warnings:', validation.warnings);
  }
  console.log('Customer valid for booking');
} else {
  console.error('Errors:', validation.errors);
}

Best Practices

1. Efficient Use of Include Parameter

// Only include data you actually need
const basicCustomer = await getCustomer(45); // Basic data only
const customerWithStats = await getCustomer(45, 'stats'); // With statistics
const fullCustomer = await getCustomer(45, 'stats,bookings,custom_fields'); // Complete

2. Customer Data Caching

// Implement cache for customer data
const customerCache = new Map();

async function getCachedCustomer(customerId, include = '') {
  const cacheKey = `${customerId}_${include}`;
  
  if (customerCache.has(cacheKey)) {
    const cached = customerCache.get(cacheKey);
    if (Date.now() - cached.timestamp < 300000) { // 5 minutes
      return cached.data;
    }
  }
  
  const params = include ? `?include=${include}` : '';
  const response = await fetch(`/wp-json/latepoint-api/v1/customers/${customerId}${params}`);
  const result = await response.json();
  
  customerCache.set(cacheKey, {
    data: result,
    timestamp: Date.now()
  });
  
  return result;
}

3. Robust Error Handling

// Function with complete error handling
async function safeGetCustomer(customerId, include = '') {
  try {
    const params = include ? new URLSearchParams({ include }) : '';
    const url = `/wp-json/latepoint-api/v1/customers/${customerId}${params ? '?' + params : ''}`;
    
    const response = await fetch(url, {
      headers: { 'X-API-Key': 'your_api_key' }
    });
    
    if (!response.ok) {
      if (response.status === 404) {
        throw new Error('Customer not found');
      } else if (response.status === 403) {
        throw new Error('No permission to access this customer');
      } else {
        throw new Error(`Server error: ${response.status}`);
      }
    }
    
    const result = await response.json();
    
    if (result.status === 'success') {
      return result.data;
    } else {
      throw new Error(result.error.message);
    }
  } catch (error) {
    console.error(`Error getting customer ${customerId}:`, error.message);
    throw error;
  }
}

Important Notes

Sensitive Information: Customer data may include sensitive information. Make sure to handle it according to applicable privacy regulations.
Optimization: Use the include parameter selectively to get only the data you need and improve performance.
Cache: If you implement customer data caching, make sure to invalidate it when customer information is updated.
Statistics: Statistics are calculated in real time, so they may affect response time if the customer has many bookings.