Customer Custom Fields

Extend customer profiles with custom data fields for memberships, preferences, and business-specific information.

Environment tip: All examples use v3.onsched.com for production. Replace the host with api-stage.onsched.com when 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:

  1. Retrieve current customer
  2. Merge new fields with existing CustomFields
  3. 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:

  1. Retrieve all customers via GET /v3/customers
  2. 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:

  1. Calculate points earned
  2. Retrieve customer record
  3. Update loyaltyPoints CustomField
  4. 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:

  1. Retrieve all customers
  2. Filter by birthday CustomField
  3. 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:

  1. Fields were included in create/update request
  2. Request succeeded (check status code)
  3. 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

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.