There's a new version of the HubSpot API
As of November 30, 2022, HubSpot API Keys are being deprecated and are no longer supported. Continued use of HubSpot API Keys is a security risk to your account and data. Your API Keys could be deactivated at any time after Nov. 30th, and we recommend that you migrate to Private Apps as soon as possible so you do not lose business-critical functionality.
The v2 update to the Ecommerce Bridge API is designed to be backwards compatible, so your existing integration will continue to work.
For details about the original v1 API, see the v1 overview documentation.
For more general details about the newer v2 API, please see the v2 overview.
For more details about the v2 API endpoints, please see the v2 API reference.
The main difference between v1 and v2 is the support for multiple stores. The store of an ecommerce transaction can be used to segment records in HubSpot.
As a result, a store ID is required for any sync messages that are sent. This store ID is stored in a property for the synced object, which will allow HubSpot users to segment their objects based on the specific store that the object came from.
For custom integrations using an API key, another primary difference is that there is no longer a separate installation endpoint. Creating your first store will now perform the initial setup for the managed properties, workflows, and reports that the install endpoint previously handled.
Any HubSpot accounts that were installed with using the v1 bridge will have a default store, using the store ID default
.
This default store will allow you to transition to the v2 endpoints without needing to configure stores for individual accounts:
default
" storeId
.storeId
.The default store starts with the following definition:
{ "id": "default", "label": "Custom", "adminUri": "string" }
Note: For app integrations using OAuth, the label
will the be name of your app.
There are a few endpoints that can be used to manage this default store.
GET /v2/stores/default
Returns the default store if one exists, otherwise will return a 404
{ "id": "default", "label": "Custom", "adminUri": "string" }
DELETE /v2/stores/default
Deletes the default store. The actual default index remains, so if one recreated the store, the ecommerce bridge will recognize that the default store has been recreated.
POST /v2/stores/default/replace
Replaces the default store with yours. This is the only way to change the default store.
Specifically, this deletes the old store definition, creates a new store definition with the given details, and creates an alias of given-store-id
-> default
For example, using the POST data below, we know that when you use the store ID updated-store
, the internal system should map that to default
, and vice versa.
Example usage:
POST /v2/stores/default/replace { "id": "udpated-store", "label": "Updated Store", "adminUri": "http://updated-store.ecommsite.com" }
Returns the details for the new store:
{ "id": "udpated-store", "label": "Updated Store", "adminUri": "http://updated-store.ecommsite.com" }
Sync messages work much like they did with v1, with the addition of the storeId
being required. Each sync message request is tied to a specific store, so you can only batch message for a single store.
When migrating from an existing v1 integration, you can migrate to the v2 endpoint, using the default
store without creating a new store. Again, the default store is automatically used in the background with the v1 endpoint.
PUT https://api.hubapi.com/extensions/ecomm/v2/sync/messages { "storeId": "default", "objectType": "DEAL", "messages": [ { "action": "UPSERT", "changedAt": "1542092841947", "externalObjectId": "1000", "properties": { "name": "1000", "stage": "processed", "purchase_date": "1542092841947" }, "associations": { "CONTACT": [ "daniel452834529" ] } } ] }
Import also work much the same as v1, but are store specific. Users will have an import button for each store, and the storeId will be included in the initial import webhook request. The ID of the store is also required in the POST requests for importing the data.
The initial webhook sent when starting the import will include the accountId field, which will be the ID of the store:
{ "portalId": 1234567, "storeId": "store-to-import-id", "importStartedAt": 1552678940201, "settingsToImport": [ { "settingsId": 1, "objectType": "PRODUCT" }, { "settingsId": 2, "objectType": "CONTACT" }, { "settingsId": 3, "objectType": "LINE_ITEM" }, { "settingsId": 4, "objectType": "DEAL" } ] }
Each page will also need to include the accountId field, set to the store ID:
POST /extensions/ecomm/v2/imports/page { "portalId": 1234567, "storeId": "store-to-import-id", "importStartedAt": 1552678940201, "objectType": "DEAL", "messages": [ { "externalObjectId": "1234abc", "properties": { "amount": 24 } }, { "externalObjectId": "234fdc", "properties": { "amount": 24 }, "associations": { "CONTACT": [ "2344a" ] } } ] }
The final request to signal the end of the import also requires the store ID in the accountId field.
POST extensions/ecomm/v2/imports/end { "portalId": 1234567, "storeId": "store-to-import-id", "importStartedAt": 1552678940201, "objectType": "DEAL", "pageCount": 12, "itemCount": 1123 }