If you started using custom objects in Zendesk prior to September 26, 2023 and weren't part of the Custom objects EAP, you're using legacy custom objects. There are many benefits to switching over to the new custom object experience, including low-or-no-code implementations, a native agent experience with custom data, object-level permissions, and support for integrating custom objects and records into your triggers and analytics. This article describes considerations, key differences, and a migration plan for moving your legacy custom objects and data into the new custom object experience.

Understanding key differences between legacy and new custom objects

Legacy and new custom objects both have the same goal: enable users to model their unique business data within Zendesk. However, these two solutions have fundamentally different data paradigms and structure for your data. Fully migrating away from custom objects may require a redesign of your data models and integrations.

There are three components of custom objects for which you need to understand the differences:

Object types

For developers, one of the best ways to conceptualize Zendesk custom objects is as a database management system.

Legacy custom objects function similarly to a document-oriented database. Schemas are defined with the JSON Schema standard and support lists types and nested objects.

The new custom objects model schemas by creating an object and adding custom fields to it, as you might for standard Zendesk objects such as tickets or users. This model is more conceptually similar to relational databases where you create a table and add columns to it.

Limitations of new custom objects

  • The most important limitation of the custom fields approach to defining custom object schemas is that it can't model nested or hierarchical data. Legacy custom objects that relied on this functionality must be remodeled into multiple separate objects.

  • Additionally, in the new custom objects experience, every object has a required name field. This field is used in the user interface to label the object in various contexts. When migrating legacy custom objects, you must identify an attribute from the legacy object that maps to the name field. Alternatively, you could denormalize or generate some new value to populate in the name field.

  • It's also worth noting that fields can't be marked as required for new custom objects.

Relationships

Continuing the database metaphor, legacy custom objects model relationships between objects similarly to a graph database. Legacy object relationship records are standalone entities and function as an edge between nodes.

For new custom objects, relationships are handled similarly to foreign keys in a relational database. Relationships are implemented through lookup relationship fields, which are a type of custom field. As such, new custom object relationships are defined directly as part of an object and relate to specific target objects. Lookup relationship fields create one-to-many (1:many) relationships. For example, if using custom objects to manage assets, you might determine "a user can have many IT assets." In that case, you would define the lookup field on the IT assets object and relate it to Users.

Limitations of new custom object relationships

  • Legacy custom objects allowed relationships between the legacy custom objects and standard objects in Zendesk Support, Chat, and Sell. The new custom object experience that relies on lookup relationship fields only permits relationships between custom objects and other custom objects or the standard Zendesk Support objects (tickets, users, and organizations).

  • One-to-one (1:1) relationships aren't directly supported in the new custom object experience. When dealing with foreign keys in relationship databases, one-to-one and one-to-many relationships are generally modeled the same way, just with validation or uniqueness constraints to prevent many source records being related. You can attempt to define one-to-one relationships with lookup relationship fields, but without these constraints, there is no way to enforce the one-to-one nature.

  • The process of migrating legacy relationship records may require you to update tickets. However, tickets can't be modified after they've been closed or archived. Evaluate whether preserving relationships to closed tickets is necessary for your purposes. If so, consider alternative storage for this data.

APIs

Legacy custom objects and new custom objects both provide APIs. However, the endpoints, requests, and response schemas are incompatible. They can't be used together. For more information about them, see:

Migrating your legacy custom objects and relationships

At this time, there isn't an automated way to migrate your legacy custom objects to the new custom objects. Instead, you'll need to create a plan that maps your legacy object types, schemas, and relationships to new custom objects and custom fields. Then you need to copy the data over.

Planning your migration

Before you begin planning your migration, you must understand the data stored in your legacy custom objects and how that data is used by integrations. Start by reviewing your object types and relationship types, either in Admin Center or directly via the APIs. Identify whether any data is redundant, obsolete, or trivial (commonly known as "ROT" data). With that in mind, determine what types are essential and what might be left behind when you migrate. During this evaluation, identify each object's source of truth. If an object is duplicating an upstream source of truth, such as a third-party system or external database, consider re-importing this data from your source of truth during the migration rather than from your legacy object records. This would not only increase accuracy, but also simplify the data migration.

You'll also need to identify any object and relationship types that are incompatible with the new custom object experience, such as object types with lists or nested objects. These would need to be remodeled using multiple objects and lookup relationship fields or, perhaps, they could be flattened. Lists can be stored as comma-separated values in a text field. Attributes of nested objects can be flattened into custom fields on an object.

Finally, you must identify what integrations are consuming your legacy custom object records and relationships. Affected integrations could include the legacy Sunshine Custom Objects app, custom-built Agent Workspace apps, Zendesk Marketplace apps, ZIS integrations, and custom services running outside of the Zendesk ecosystem. If you're using custom-built integrations, make sure to coordinate with your developers to adapt them to the new custom object APIs and data model.

After reviewing your legacy object types, relationship types, incompatibilities with the new custom object experience, and how your legacy data is used, you're ready to map your existing schema and data to the new custom objects and fields model.

Copying your legacy data over

After you determine how to map your legacy objects, relationships, and records to new custom objects, you need a way to get your data into the new model. The data migration is, effectively, an extract, transform, and load (ETL) process. In a literal sense, you would use the Legacy Custom Object APIs to extract the data, transform the extracted JSON to match the new custom objects model, and then load the data with the new Custom Objects APIs.

The recommended order of operations for copying your data is:

  1. Disable write access to legacy custom objects via the Legacy Custom Objects Permissions APIs. This step is optional, but recommended because data can be lost if records change during the migration process.

  2. Copy your legacy custom object types. To do this, use /api/v2/custom_objects endpoint to create a custom object. Then use the /api/v2/custom_objects/{custom_object_key}/fields endpoint to create custom object fields that map each property of the legacy object to the new custom object. Alternatively, you can create your new custom objects and fields in Admin Center.

  3. Copy your legacy relationship types. Recreate the relationships as custom fields on the "many" side of the one-to-many relationship. The lookup relationship field may be added to a custom object or to a standard Zendesk Support object (tickets, users, or organizations). See Connecting your object with lookup relationship fields and the Lookup Relationships APIs.

  4. Copy your legacy custom object records. To do this via the API, use the /api/v2/custom_objects/{custom_object_key}/records endpoint to create custom object records. Alternatively, you can use a CSV file to perform a bulk import of your custom object records via the Data importer in Admin Center. Note that when creating new object records, the id property will be regenerated. If you need to be able to reference legacy record ids from the new records, consider copying either the legacy records' external_id if present or id property into the new record's external_id property. It may be helpful to track the mapping of the legacy record ids to new record ids locally in a simple database.

  5. Copy your legacy relationship records. Depending on where the lookup relationship field was created, this might require calling the Update endpoint for custom object records, tickets, users, or organizations.

  6. Update your integrations to use your new custom objects. When planning your migration, you identified any integrations you are using that consumed your legacy custom object records and relationships. Now you can update the integrations to use your new custom objects and records.

  7. Delete your legacy custom objects after verifying the successful migration of your data. A safe and reversible first step towards this is to use the Update Legacy Object Type Policies and Update Legacy Relationship type Policies endpoint to remove access to all migrated object and relationship types. This can help build confidence that your critical data and integrations have been migrated properly before you actually delete the legacy custom objects, which can't be undone.

Best practices for creating a custom migration tool

If you plan to create your own custom migration tool, keep the following in mind:

  • Migrations need to respect API rate limiting. Monitor your request activity and use the Retry-After header if you encounter a 429 error.

  • When writing to the new Custom Objects APIs, use the idempotency-key request header to avoid duplicate records when retrying temporary failures.

  • For large record collections, your tool should save the state of its progress through the collection at regular intervals.

  • Custom object keys can't be reused within an instance, even if the object that originally used it has been deleted.