Migrating from Ecommerce Bridge v1 to v2

The v2 update to the Ecommerce Bridge API is designed to be backwards compatible, so your existing integration will continue to work.

For more general details, please see the v2 overview.

For more details about the API endpoints, please see the v2 API reference.

Differences between v1 and v2

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.

Default Store

Any HubSpot accounts that were installed with using the v1 bridge will have a default store, using the store ID default.

Notes:
  • Any sync messages sent using the v1 sync endpoint use this default store behind the scenes.
  • This default store can be used with the v2 sync endpoint without creating a new store.

This default store will allow you to transition to the v2 endpoints without needing to configure stores for individual accounts:

  • While using the v1 endpoint, everything automatically syncs using the default store
  • At any time, you can switch to the v2 endpoint, referencing the "default" storeId.
  • The v1 and v2 endpoints can be used at the same time for the same account, so you could leave an existing process using the v1 endpoint in place while spinning up a new service that uses the v2 endpoint with the default 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.

Default store API reference

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

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"
        ]
      }
    }
  ]
}

Imports

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
}