Synchronize a Catalog with an External Platform

Applies to: Catalog API | Subscriptions API

Learn about using the Square API to synchronize an external platform with a Square catalog.

Link to section

Overview

When a seller's catalog exists in the Square Developer platform under their Square account and a duplicate catalog exists in an external platform, the two catalogs should be periodically synchronized to maintain parity. For example, a seller uses an enterprise resource planning (ERP) system to keep a catalog for functions such as cost accounting, inventory, or sales through another channel. The seller uses the catalog in Square Point of Sale to complete item purchases and process payments in a physical retail location.

Did you know?

A seller's catalog is the source of the Square Dashboard item library and for items shown in Square Point of Sale.

You need to know which platform hosts the master ("source of truth") catalog. Changes should be synchronized from the master catalog to the catalog in the other platform.

Link to section

Use reference IDs

Regardless of whether the Square platform hosts the seller's master catalog or the external system does, you should store the ID of the external item with the Square CatalogObject and the ID of the Square CatalogObject in its equivalent object in the external catalog. A good place to store the external ID is as a custom_attribute_values (CatalogCustomAttributeValue) property value. For information about using catalog custom attributes, see Add Custom Attributes.

Link to section

Source of catalog updates

Catalog objects can be inserted, changed, or deleted by sellers in the Square Dashboard item library or from Square Point of Sale. These updates can also be made from any other catalog integration that a seller is using. Your sync logic needs to catch any updates made to the catalog, regardless of the source of the update.

Link to section

Sync from Square to an external platform

To sync to an external platform, your application periodically gets changes to the catalog in a Square account and writes them to the external platform. There are a couple of useful strategies to drive the periodic catalog reads:

Both strategies use the begin_time property of SearchCatalogObjects to return only Catalog objects that have been updated after the time you set in the search request. The results of the search request include only the objects that you're interested in. For Catalog objects returned in the result, you need to push the new objects or updates to the external platform.

Warning

Whichever strategy you use, don't call ListCatalog on interval or event unless you're listing for the current catalog version number and limiting the scope of object types. Otherwise, your result set can be very large and subject your application to rate limiting.

Link to section

Sync on notification of a change

Synchronize when this webhook event is fired. It's fired once for every UpsertCatalogObject, DeleteCatalogObject, BatchUpsertCatalogObjects, or BatchDeleteCatalogObjects API call.

Note

Deleted Catalog objects are returned in future SearchCatalogObjects responses. Such an object has an is_deleted property whose value is true. For more information about deleting Catalog objects, see Delete Catalog Objects and Query Deleted Objects.

Insert, update, and delete operations trigger the generation of a new catalog version number, which is then assigned to every inserted, updated, or deleted object. In a given catalog.version.updated webhook event, object.catalog_version.updated_at gives the timestamp for the creation of that new version. If you call SearchCatalogOjbects with that timestamp, you get all updates completed after the version increment event. To get the object updates that triggered the webhook, you should use the updated_at timestamp for the previous webhook event.

Link to section

BatchUpsertCatalogObjects benefits

A positive side-effect of using BatchUpsertCatalogObjects instead of making a single object update with UpsertCatalogObject is that you receive a single webhook notification for all batches in the batch request. Because BatchUpsertCatalogObjects accepts up to 10,000 objects to be added or updated, it results in one webhook event rather than thousands. Batch delete operations have the same benefit.

Link to section

Webhook usage example

To get all Catalog object changes since the last time you synced, you need two things:

  1. The timestamp of your previous sync - This timestamp should be the moment the previous catalog version was set. The timestamp is provided in the previous webhook event (object.catalog_version.updated_at).
  2. A new webhook notification - This webhook tells you that the catalog has changed and that there's a new version.

The timestamp marks the start of a time range in which new catalog changes were made. The SearchCatalogObjects request takes that date (the date of your last sync) as the begin_time property of the request. When you make the search request, you're asking Square to return all catalog changes since the last sync. The response carries all changes from then to the moment you make the search request.

You can further scope the SearchCatalogObjects request to only those catalog types that you're syncing. For example, the external platform might only store items and variations. It might not store discounts, pricing rules, taxes, or other catalog types. In this case, add a search clause like the following example:

"object_types": [ "ITEM", "ITEM_VARIATION" ]
Link to section

Trigger sync with a webhook

Complete the following steps to start syncing a catalog from Square to an external system by using Square webhook notifications:

  1. Subscribe to catalog.version.updated using the Developer Console or subscribe programmatically with the Subscriptions API.
  2. Make a full copy of the master catalog in the target platform.
  3. Cache an arbitrary start date. Usually this is the date the target catalog is created.
  4. Handle the next catalog.version.updated webhook event.
    1. Call SearchCatalogObjects with the cached date.
    2. Replace the cached date with the value of object.catalog_version.updated_at.
    3. Parse the response to SearchCatalogObjects, which has all Square catalog changes since the last sync (or initial copy).
    4. Sync updates to the external platform.

The following object is the body of a catalog.version.updated webhook event payload. Note the object.catalog_version.updated_at property.

{ "merchant_id": "S1JEG5YR89KNM", "type": "catalog.version.updated", "event_id": "ce50c3de-7f60-36e6-af1f-21b9867f6f4d", "created_at": "2024-10-02T21:36:39.343216712Z", "data": { "type": "catalog_version", "id": "", "object": { "catalog_version": { "updated_at": "2024-10-02T21:36:36.932Z" } } } }

The following example shows the use of a webhook timestamp to get all catalog updates after the catalog version was incremented:

To request all Catalog objects that have changed after the previous webhook event (2024-10-02T21:31:36.932Z) , make a SearchCatalogOjbects request like the following example:

Search catalog objects

Link to section

Sync on regular interval polling

Polling replaces the non-deterministic webhook event trigger with a regular cadence that you establish in your application. For example, you can set a chron job to fire an event every 15 minutes to get all catalog updates made since the last time a chron event fired.

Link to section

Trigger sync from your chron job

Complete following steps to start syncing a catalog from Square to an external system by using a timer that you add to your application backend:

  1. Make a full copy of the master catalog in the target platform.
  2. Cache an arbitrary start date. Usually this is the date the target catalog is created.
  3. Start your chron job.
  4. When a chron event fires:
    1. Call SearchCatalogObjects with the cached date,
    2. Replace the cached date with the timestamp of the chron event.
    3. Parse the response to SearchCatalogObjects, which has all Square catalog changes since the initial copy.

The following example shows the use of a chron event timestamp to get all catalog updates after the catalog version was incremented:

To request all Catalog objects that have changed after the previous chron event (2024-10-02T21:31:36.932Z) , make a SearchCatalogOjbects request like this request.

Search catalog objects

Link to section

Sync from an external platform to Square

Syncing from an external platform to Square applies where the external platform hosts the master catalog.

Using whatever mechanism is appropriate for the external platform that your application supports, you parse any external updates and push them into the catalog in the seller's Square account by using UpsertCatalogObject, DeleteCatalogObject, BatchUpsertCatalogObjects, or BatchDeleteCatalogObjects API calls.

It's a good idea to group like operations so you can call the Catalog API batch endpoints and reduce the number of API calls you make. For example, you can pull all the delete operations into a single BatchDeleteCatalogObjects API call.

For each Catalog object that exists in both platforms, apply the external update by first retrieving the Square Catalog object by the CatalogObject ID that you stored in the external platform. For information about retrieving a Catalog object by ID, see Retrieve a catalog object with a specified ID and catalog version.

To learn about updating existing Square Catalog objects with changes to the same object in an external platform, see Update Catalog Objects.

If an external catalog item is deleted, call DeleteCatalogObject.

Link to section

Verify updates

You can verify updates synchronously by catching the response to upsert or delete requests. If you get a 200 response, that means the catalog change succeeded. You can parse the call response to verify if necessary.

If you want to run verification in a webhook listener process, you can use the webhook events generated by the Catalog API operations. You need to provide a timestamp representing your first Catalog API call to that verify process.

To process verifications triggered by webhook events, first subscribe to catalog.version.updated using the Developer Console or subscribe programmatically with the Subscriptions API. The webhook listener you use needs to be running before you make your first Catalog API call to push updates.

Link to section

Bi-directional syncing

Bi-directional catalog synchronization can be difficult to implement because of the large number of endpoints involved in both systems. Catalog object updates in either system result in risky operations such as:

  • CRUD operations - Risks arise from concurrency, merging, duplication, and deletion issues if both systems have CRUD operations around the same time.
  • Price changes - An accounting integrity risk can arise from a user on either system inadvertently updating the other system. For example, a Square user updates the POS price, which then updates the online price in the other system with that new price. A seller might intend for item prices to be different across sales channels.

If your application must address a bi-directional use case, you need to account for these side-effects, which are beyond the scope of this topic. However, you can use the preceding sections to understand the mechanisms you can use to build either direction of your use case.