Contacts migration

An upcoming update to Contacts in Front will reduce the prevalence of duplicated contacts by replacing Team-based contacts with a unified Company-wide contact record. A summary of these changes is available on our help center. From an API perspective, these changes will mean that:

  • Contacts created through the API will be company-wide contacts or fully private to a single user. For multi-team Front instances, contacts that are unique to a single team will no longer be supported. Instead, Teams will share a set of company-wide contacts.
  • All team contacts will be migrated to a new company contact with a new ID
  • Contacts duplicated across teams will be merged into a single contact

The release will happen gradually over the course of the next couple of months. While it will mostly be transparent for our users, it might be more noticeable for our API developers and partners.

If you are storing Front Contact ID

If your system is storing Contact IDs, you will most likely want to adapt the logic to map the migrated contact IDs to the new contact IDs.

With this change, we are introducing a new _migration property to our Contact data model. If a contact is the result of the migration, the core API will expose an array containing the ID(s) of the contact that were migrated into it.
Note: The _migration property can be undefined if the contact was not migrated.

The example bellow shows what a company contact would look like if it is the result of the migration of two team contacts:

{
  "_migration": {
    "legacy_ids": ["crd_55c8c149", "crd_sir4pc6i"]
  },
  "id": "crd_xxx"
  // ... other contact properties.
}

With this data, you can now update the contact IDs when you encounter a contact (eg: via a webhook) or you can proactively iterate through all the contacts using GET /contacts.

const {Sequelize, QueryTypes} = require('sequelize');

async function updateFrontContactId(contact) {
  const legacyIds = contact._migration && contact._migration.legacy_ids;

  // Nothing to do if this contact is not the result of the migration.
  if (!legacyIds)
    return;
 
  // Update our records.
  // Below is an example usinq sequelize.
  const sequelize = new Sequelize('sqlite::memory:')
  
  await sequelize.query(
    'UPDATE my_table SET front_contact_id = :newId WHERE front_contact_id IN (:legacyIds)',
    {
    	replacements: {newId: contact.id, legacyIds},
	    type: QueryTypes.UPDATE
  	}
  );
}

👍

What do I need to do?

Update your Contact IDs using the new _migration property from the Contact data model.

If you are using team-specific Contact endpoints

Affected endpoints:

  • GET /teams/:team_id/contacts
  • POST /teams/:team_id/contacts

Team specific endpoints are now deprecated. Once the migration is complete, they will respectively behave like GET /contacts (to list all accessible contacts) and POST /contacts (to create a company contact).

👍

What do I need to do?

Change your requests pointing to /teams/:team_id/contacts to point to /contacts instead.

If you are using Contact resource endpoints

Affected endpoints:

  • All routes nested under the path /contacts/:contact_id.

If the requested Contact has been migrated, the Core API will respond with a 301 Redirect HTTP Status code.
The URL of the new Contact will be available in the value of the HTTP Header Location:

HTTP/1.1 301 Moved Permanently
Location: https://api.frontapp.com/contacts/crd_xxx

👍

What do I need to do?

Configure your HTTP client to follow redirect or make sure your code properly handles 301 Redirect responses.

If you are using Contact ID in the body of your request

Affected endpoints:

  • POST /contact_groups/:contact_group_id/contacts
  • POST /channels/:channel_id/incoming_messages

If the requested Contact has been migrated, the Core API will transparently fetch the new Contact it had been migrated to and will use it instead.

👍

What do I need to do?

Nothing to do on your side.