Applies to: Catalog API | Subscriptions API
Learn about using the Square API to synchronize an external platform with a Square catalog.
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.
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.
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.
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:
- On notification of a change - Use catalog.version.updated to trigger a sync. The event provides the timestamp of a catalog update. Make a SearchCatalogObjects request with the begin_time request property set to the previous event timestamp.
- Regular interval polling - On a set time interval, make a SearchCatalogObjects request with the begin_time request property set to the previous interval timestamp.
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.
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.
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.
To get all Catalog
object changes since the last time you synced, you need two things:
- 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
). - 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" ]
Complete the following steps to start syncing a catalog from Square to an external system by using Square webhook notifications:
- Subscribe to catalog.version.updated using the Developer Console or subscribe programmatically with the Subscriptions API.
- Make a full copy of the master catalog in the target platform.
- Cache an arbitrary start date. Usually this is the date the target catalog is created.
- Handle the next
catalog.version.updated
webhook event.- Call
SearchCatalogObjects
with the cached date. - Replace the cached date with the value of
object.catalog_version.updated_at
. - Parse the response to
SearchCatalogObjects
, which has all Square catalog changes since the last sync (or initial copy). - Sync updates to the external platform.
- Call
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
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.
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:
- Make a full copy of the master catalog in the target platform.
- Cache an arbitrary start date. Usually this is the date the target catalog is created.
- Start your chron job.
- When a chron event fires:
- Call
SearchCatalogObjects
with the cached date, - Replace the cached date with the timestamp of the chron event.
- Parse the response to
SearchCatalogObjects
, which has all Square catalog changes since the initial copy.
- Call
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
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.
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.
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.