Applies to: Customers API | Cards API | Loyalty API
Customer records in Square's system may contain duplicates that accumulate over time. These duplicates can originate from various sources, including Square API integrations and Square's own products. Your application needs to implement a robust strategy for handling duplicates.
When developing your application, you need to account for several customer data scenarios. Your system must handle search requests that return multiple records for the same customer, recognizing that these duplicates can arise from various, sometimes untraceable sources. Additionally, since duplicate customer records may be merged over time, your application should implement special handling procedures to manage these consolidated profiles effectively.
To prevent customer duplication, carefully search for existing customers before creating new ones. This search should use unique identifiers such as email addresses and phone numbers to identify potential matches. Furthermore, when processing payments, include the customer_id
in your requests whenever it's available, as this makes Square use your customer instead of searching for a match and then creating a new customer if the search doesn't turn up a customer.
Your application might encounter customer duplication even after you've implemented best practices to avoid duplicating customers. To catch potential duplication before adding a new customer, implement these practices:
- Check for similar customer records using available identifiers
- Compare key fields like name, email, and phone number
- Consider fuzzy matching for slight variations in contact details
Proper handling of customer record merges is crucial for maintaining data integrity across Square's ecosystem, as these operations affect multiple interconnected services and resources.
Square handles duplicate customer profiles through two methods: sellers can manually merge duplicates through the Square Dashboard, or Square can perform automatic merges. In both cases, when a merged customer's ID is requested via the Customer API, Square maintains the original records but returns the new merged customer ID, ensuring all references remain valid.
Important
Customer profiles that have been merged into a new profile are never returned by the Customers API. To get objects related to the merged customer profiles, you need to detect customer merges and store the merged IDs.
While it may seem possible to use the Customers API to merge customers by:
- Creating a new customer
- Copying profile data
- Deleting the old customer
This approach will break existing relationships because:
- Customer IDs are used as foreign keys in many Square resources:
- Payments
- Orders
- Loyalty Programs
- Gift Cards
- Subscriptions
- Invoices
- Custom attributes
Important
When you delete a customer, these relationships become orphaned and cannot be redirected to a new customer ID.
.
When Square merges duplicate customer profiles, your application needs to maintain mappings to access resources associated with merged customers. Here's how to implement this:
Webhook Events
- Listen for customer.created events
- Check CustomerCreatedEventObject.event_context
- If created by merge, the context will indicate this
API Response Analysis
- When calling RetrieveCustomer
- Compare the returned customer ID with your request ID
- If IDs differ but email/phone match, a merge occurred
In the following implementation examples, a seller had two sets of duplicated customers. Their IDs are represented by the following lists:
["previous_id_A", "previous_id_B"]
["previous_id_C", "previous_id_D", "previous_id_E"]
.
Two new customer profiles created from the merge operations:
"new_customer_id_1"
"new_customer_id_2"
Any Customer API responses for these customers after the merge return only these new profile IDs.
The seller used the Square Dashboard to merge these customers into new customer profiles which generated a customer.created webhook event for each merge. The application's webhook handler updated a dictionary by adding the ID of the profile the duplicates were merged into and the IDs of the duplicates. In the following example dictionary, the results of the two merges are recorded.
Maintaining a dictionary of merged customer profiles:
{ "new_customer_id_1": ["previous_id_A", "previous_id_B"], "new_customer_id_2": ["previous_id_C", "previous_id_D", "previous_id_E"] }
When searching for customer-associated resources (e.g., orders), the application needs to find all resources that reference the current customer profile and those that reference the old merged customer profiles.
The following Square Python SDK example uses the merged customer profile dictionary to find all orders for current ID and any ID merged into the new profile:
- Get all customer IDs - Look the current customer ID up in the dictionary and return all related customer IDs (both current and previous)
- Get all orders - Search for all orders associated with a customer, including orders linked to their previous profiles
from square import Square import os from typing import List, Dict, Any def get_all_related_customer_ids(current_id: str, id_mapping: Dict[str, List[str]]) -> List[str]: """ Given a current (post-merge) customer ID, return all related customer IDs (both current and previous) Args: current_id: The current customer profile ID id_mapping: Dictionary mapping new IDs to lists of previous IDs Returns: List of all related customer IDs (current ID + all previous IDs) """ # Start with the current ID all_ids = [current_id] # Add any previous IDs associated with this current ID if current_id in id_mapping: all_ids.extend(id_mapping[current_id]) return all_ids def search_customer_orders( current_id: str, id_mapping: Dict[str, List[str]], location_ids: List[str], client: Square ) -> List[Dict[str, Any]]: """ Search for all orders associated with a customer, including orders linked to their previous profiles Args: current_id: The current (post-merge) customer profile ID id_mapping: Dictionary mapping new IDs to lists of previous IDs location_ids: List of Square location IDs to search client: Initialized Square client Returns: List of all orders found across all related customer profiles """ # Get all customer IDs (current and previous) customer_ids = get_all_related_customer_ids(current_id, id_mapping) # Create the search query with customer filter search_query = { "filter": { "customer_filter": { "customer_ids": customer_ids } }, "sort": { "sort_field": "CLOSED_AT", "sort_order": "DESC" } } try: # Search orders using the Square SDK result = client.orders.search( body={ "location_ids": location_ids, "query": search_query } ) if result.is_success(): return result.body.get('orders', []) else: print(f"Error searching orders: {result.errors}") return [] except Exception as e: print(f"Exception when searching orders: {str(e)}") return [] # Example usage: def main(): # Initialize the Square client client = Square( access_token=os.environ.get("SQUARE_TOKEN"), environment='sandbox' # Use 'production' for production environment ) # Example mapping of new IDs to previous IDs id_mapping = { "NEW_ID_1": ["OLD_ID_A", "OLD_ID_B"], "NEW_ID_2": ["OLD_ID_C", "OLD_ID_D"] } # Example location IDs - replace with actual location IDs location_ids = ["057P5VYJ4A5X1", "18YC4JDH91E1H"] # Search for all orders, including those from previous profiles orders = search_customer_orders( current_id="NEW_ID_1", id_mapping=id_mapping, location_ids=location_ids, client=client ) # Process the orders for order in orders: print(f"Order ID: {order.get('id')}") # Process other order fields as needed
Did you know?
You should update your ID mappings immediately when detecting merges to maintain data consistency.
The process for handling loyalty reward programs associated with duplicate customers is a little complex and needs to be explained.
The way loyalty accounts are handled depends on how a customer profile merge happened. A seller can use the Square Dashboard to manually merge customers or ask Square to automatically merge duplicated customers. The rules are as follows:
Manual merges - When a seller merges two customer profiles that both have loyalty accounts:
- Seller selects which phone number to retain
- Activity from both loyalty accounts combines into the selected account. The
loyalty_account.mapping.phone_number
remains the same.
Automatic Merges - Automatic merging can occur only when:
- One profile has a loyalty account
- The other profile has no loyalty account
- Existing loyalty account gets the new
loyalty_account.customer_id
Important
Square will never automatically merge two profiles that both have loyalty accounts. This prevents accidental combination of active loyalty programs.