Customer Custom Fields
Extend customer profiles with custom data fields for memberships, preferences, and business-specific information.
Environment tip: All examples use
v3.onsched.comfor production. Replace the host withapi-stage.onsched.comwhen calling the staging environment.
What Are Customer Custom Fields?
Customer Custom Fields allow you to store additional information beyond the standard profile fields (name, email, phone). Use them to track:
- Membership data – Tier level, member ID, expiration dates
- Preferences – Preferred times, staff, services
- Demographics – Age, birthday, location details
- Marketing data – Referral source, campaign codes
- CRM integration – External system IDs, sync tokens
Custom Fields are key-value pairs stored with each customer record.
How Custom Fields Work
Data Structure
Custom Fields use PostgreSQL HSTORE format:
{
"CustomFields": {
"membershipTier": "platinum",
"birthday": "1985-03-22",
"preferredStylist": "Jamie",
"referralSource": "facebook",
"loyaltyPoints": "5420"
}
}- Keys: Field names (strings)
- Values: Field values (strings only)
All values are strings—store numbers, booleans, or dates as strings and parse in your application.
##Creating Customers with Custom Fields
During Customer Creation
curl -X POST https://v3.onsched.com/v3/customer \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Jordan",
"lastName": "Lee",
"email": "[email protected]",
"phone": "+15550123",
"CustomFields": {
"membershipId": "MEM-98765",
"membershipTier": "gold",
"birthday": "1992-07-15",
"preferredContact": "email",
"newsletter": "true"
}
}'Response includes CustomFields:
{
"id": "customer-uuid",
"firstName": "Jordan",
"lastName": "Lee",
"email": "[email protected]",
"CustomFields": {
"membershipId": "MEM-98765",
"membershipTier": "gold",
"birthday": "1992-07-15",
"preferredContact": "email",
"newsletter": "true"
},
"createdAt": "2025-11-25T10:00:00Z"
}During Appointment Booking
Create customer with CustomFields inline:
curl -X POST "https://v3.onsched.com/v3/appointment?..." \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"Customer": {
"firstName": "Alex",
"lastName": "Chen",
"email": "[email protected]",
"CustomFields": {
"howDidYouHear": "instagram",
"firstVisit": "true"
}
},
"Unavailability": {...},
"duration": 30
}'Customer record is created with CustomFields included.
Updating Custom Fields
Replacing All Custom Fields
Use PUT /v3/customer/:id to replace CustomFields entirely:
curl -X PUT https://v3.onsched.com/v3/customer/CUSTOMER_ID \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"CustomFields": {
"membershipTier": "platinum",
"loyaltyPoints": "6500",
"lastVisit": "2025-11-20"
}
}'This replaces all existing CustomFields with the new object.
Partial Updates
To update specific fields without losing others:
- Retrieve current customer
- Merge new fields with existing CustomFields
- Send complete CustomFields object via PUT
Example:
# Step 1: Get current customer
curl https://v3.onsched.com/v3/customer/CUSTOMER_ID \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Response includes current CustomFields
{
"CustomFields": {
"membershipTier": "gold",
"loyaltyPoints": "5420"
}
}
# Step 2: Merge in application (add newsletter: "true")
# Step 3: Update with merged fields
curl -X PUT https://v3.onsched.com/v3/customer/CUSTOMER_ID \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"CustomFields": {
"membershipTier": "gold",
"loyaltyPoints": "5420",
"newsletter": "true"
}
}'Retrieving Custom Fields
CustomFields are included in all customer responses:
# Get single customer
curl https://v3.onsched.com/v3/customer/CUSTOMER_ID \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# List customers (includes CustomFields for each)
curl https://v3.onsched.com/v3/customers?limit=50 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Empty CustomFields return as {}, never null.
Common Use Cases
Membership Programs
Track membership status and benefits:
{
"CustomFields": {
"membershipId": "MEM-12345",
"membershipTier": "platinum",
"memberSince": "2023-06-01",
"renewalDate": "2026-06-01",
"autoRenew": "true",
"membershipStatus": "active"
}
}Query customers by membership tier for targeted promotions.
Loyalty Programs
Store points and rewards:
{
"CustomFields": {
"loyaltyPoints": "12500",
"lifetimePoints": "45000",
"rewardsRedeemed": "3",
"nextRewardAt": "15000",
"tierProgress": "2500 points to Diamond"
}
}Update points after each appointment.
Demographics
Collect demographic information:
{
"CustomFields": {
"birthday": "1988-12-05",
"age": "36",
"gender": "female",
"zipCode": "90210",
"referredBy": "friend"
}
}Use for targeted marketing and personalization.
Preferences
Store customer preferences:
{
"CustomFields": {
"preferredTime": "mornings",
"preferredDays": "weekdays",
"preferredStylist": "Jamie Rodriguez",
"preferredService": "balayage",
"communicationPreference": "email"
}
}Suggest appointments based on preferences.
Marketing Attribution
Track acquisition sources:
{
"CustomFields": {
"referralSource": "google-ads",
"campaign": "spring-promo-2025",
"utmSource": "google",
"utmMedium": "cpc",
"utmCampaign": "haircut-special",
"referralCode": "FRIEND20"
}
}Measure marketing ROI by analyzing customer sources.
Health & Safety
For health-related services:
{
"CustomFields": {
"allergies": "latex, fragrance",
"medications": "none",
"conditions": "sensitive skin",
"emergencyContact": "Pat Lee",
"emergencyPhone": "+15550999",
"consentFormSigned": "2025-01-15"
}
}Ensure staff have critical information before appointments.
CRM Integration
Link to external systems:
{
"CustomFields": {
"salesforceContactId": "003xx000004TmiD",
"hubspotId": "67890",
"stripeCustomerId": "cus_AbCdEf123456",
"externalCustomerId": "CUST-2025-001",
"lastSyncedAt": "2025-11-25T10:30:00Z"
}
}Maintain bidirectional sync between OnSched and CRM.
Data Types and Formatting
String Values Only
All CustomFields values are strings:
{
"CustomFields": {
"loyaltyPoints": "12500", // number as string
"autoRenew": "true", // boolean as string
"birthday": "1990-05-15", // date as ISO string
"joinedAt": "2024-01-15T10:00:00Z", // datetime as ISO string
"preferences": "{\"email\":true}" // JSON as escaped string
}
}Parse values in your application.
Multi-Value Fields
For fields with multiple values, use delimiters:
{
"CustomFields": {
"allergies": "peanuts,shellfish,latex",
"languages": "en|es|fr",
"interests": "yoga,meditation,nutrition"
}
}Split on delimiter (, or |) when processing.
Null or Empty Values
To remove a field:
{
"CustomFields": {
"fieldToRemove": ""
}
}Or omit it from the update. Empty strings are stored as-is.
Best Practices
Plan Your Schema
Document CustomFields before implementation:
Field Name | Type | Purpose | Example
------------------|--------|----------------------|------------------
membershipTier | string | Membership level | "gold"
loyaltyPoints | string | Numeric points | "5420"
birthday | string | ISO date | "1985-03-22"
preferredStylist | string | Staff name | "Jamie Rodriguez"
Consistency makes queries and reporting easier.
Use Descriptive Names
Avoid cryptic keys:
- Bad:
cf1,data,temp,x - Good:
membershipTier,loyaltyPoints,birthday
Clear names make code maintainable.
Keep Values Structured
For dates, use ISO format:
- Good:
"2025-11-25" - Bad:
"11/25/2025","25-Nov-2025"
For booleans, use consistent strings:
- Good:
"true"/"false" - Bad:
"yes"/"no","1"/"0"
Don't Overload CustomFields
For extensive data, consider:
- Separate customer notes field – Long-form text
- External database – Link via ID in CustomFields
- Multiple CustomFields – Break large objects into separate fields
Keep fields focused and manageable.
Version Your Schema
If schema evolves over time:
{
"CustomFields": {
"schemaVersion": "2",
"membershipTier": "gold"
}
}Helps with migrations and supporting multiple versions.
Validate in Your Application
OnSched doesn't validate CustomFields. You must:
- Check required fields exist
- Validate formats (dates, emails, numbers)
- Enforce business rules
- Sanitize user input
Security and Privacy
Sensitive Data
Be cautious with sensitive information:
- PII (Personally Identifiable Information) – Secure your database
- Health data – Ensure HIPAA compliance if applicable
- Financial data – Never store full credit card numbers
CustomFields are stored in plaintext. Encrypt sensitive data before storing if necessary.
GDPR and Privacy
If operating in regions with privacy laws:
- Document what CustomFields you collect and why
- Enable customers to view/edit their data
- Support data deletion requests
- Obtain consent for marketing fields
Access Control
CustomFields are visible to:
- Authenticated company users
- Anyone with API access to customer records
Don't store internal-only data that customers shouldn't see.
Searching and Filtering
Limitations
OnSched's API doesn't currently support filtering customers by CustomFields directly in list endpoints.
Workaround:
- Retrieve all customers via
GET /v3/customers - Filter by CustomFields in your application
Example:
const customers = await fetchCustomers();
const goldMembers = customers.filter(c =>
c.CustomFields.membershipTier === 'gold'
);Future Enhancements
Check API documentation for updates on CustomFields search capabilities.
Integration Patterns
Syncing with CRM
Store CRM IDs for bidirectional sync:
{
"CustomFields": {
"crmId": "SF-003xx000004TmiD",
"crmLastSync": "2025-11-25T10:00:00Z",
"crmSyncStatus": "success"
}
}Update CustomFields after successful syncs.
Loyalty Point Updates
After each appointment:
- Calculate points earned
- Retrieve customer record
- Update
loyaltyPointsCustomField - Save customer
# Get current points
curl https://v3.onsched.com/v3/customer/CUSTOMER_ID
# Update with new total
curl -X PUT https://v3.onsched.com/v3/customer/CUSTOMER_ID \
-d '{"CustomFields": {"loyaltyPoints": "NEW_TOTAL"}}'Birthday Campaigns
Query customers with upcoming birthdays:
- Retrieve all customers
- Filter by
birthdayCustomField - Send birthday promotions
const today = new Date();
const customers = await fetchCustomers();
const birthdayCustomers = customers.filter(c => {
const birthday = new Date(c.CustomFields.birthday);
return birthday.getMonth() === today.getMonth() &&
birthday.getDate() === today.getDate();
});Troubleshooting
CustomFields not appearing in response
Check:
- Fields were included in create/update request
- Request succeeded (check status code)
- Using authenticated endpoints (not public endpoints)
CustomFields lost after update
Cause: Updates replace CustomFields entirely, not merge.
Solution: Always include all CustomFields in updates, even unchanged ones.
Cannot filter customers by CustomField
Limitation: Direct API filtering not supported.
Solution: Filter in application layer after fetching.
CustomFields appearing as null
Cause: Customer created without CustomFields.
Behavior: OnSched returns {} for empty CustomFields, not null. Check response parsing logic.
Common Questions
Can I rename CustomFields?
You can add new fields anytime. To "rename" across all customers, write a migration script.
Is there a limit on number of fields?
No hard limit, but keep it reasonable (typically under 30 fields). Excessive fields increase complexity.
Can I store arrays or objects?
Not natively. Serialize as JSON strings:
{
"CustomFields": {
"preferences": "{\"email\":true,\"sms\":false}"
}
}Parse in your application.
Are CustomFields searchable?
Indexed in PostgreSQL HSTORE, but API endpoints don't currently expose CustomField filtering directly.
Can customers see their CustomFields?
Depends on your UI implementation. Control visibility in your customer portal.
Related Documentation
- Customers Overview – Customer management basics
- Appointment Custom Fields – Appointment-level CustomFields
- Customer SMS – SMS notification configuration
- Services Overview – Service CustomFields
Customer Custom Fields enable powerful customization. Plan your schema carefully, document field purposes, and use CustomFields to tailor OnSched to your exact customer relationship needs.
Updated 4 days ago
