This article describes how to migrate the records created from your legacy objects to the new custom objects experience.

Topics covered in this article:

This is the fourth article in a series on migrating legacy custom objects:

Disclaimer: Zendesk provides this article for instructional purposes only. Zendesk doesn't provide support for the example code in this article. Zendesk doesn't support third-party technologies such as Python.

Understanding how legacy records map to records in the new custom objects experience

The data of a legacy record is stored in the attributes property of the record. Example:

{      "attributes": {        "id": "3b0ff066-e8ec-11e6-bf01-fe55135034f3",        "name": "Miso",        "breed": "Corgi",        "training": false    }}

In the new custom objects experience, the data of a record is stored in the custom_object_fields property as well as the name property. For example, after migrating the legacy record above to the new custom object experience, the new record should look as follows:

{  "custom_object_record": {    "custom_object_fields": {      "breed": "Corgi",      "training": false    },    "name": "Miso",    "id": "01GDXYEY1FQYN066VHF49YHJ21"  }}

The name property is the standard name field for the object. See Custom Object Fields. If you selected autonumbering in Admin Center for the custom object's standard name field, then the name property isn't allowed because the value is automatically generated. If uniqueness is enforced for the standard name field, then the name value must be unique.

Migrating legacy object records

Migrating legacy object records consists of retrieving the records of a legacy object and then using each record to create a corresponding record in the new experience.

Example main function logic

The following example main() function shows the general logic of migrating legacy records to the new custom objects experience. The called functions are explained in the follow-up sections.

def main():    record_map = {}
    object_types = get_object_types()    for object_type in object_types:        object_records = get_object_records(object_type)        for record in object_records:            migrate_object_record(record, record_map)
    write_json_file('record_map.json', record_map)
# utility functiondef write_json_file(file_path, file_data):    with open(file_path, mode='w', encoding='utf-8') as f:        json.dump(file_data, f, sort_keys=True, indent=2)

Example function for getting the object records

The following example Python function gets the records of a legacy object.

The function uses the List Legacy Object Records endpoint to export a list of records for a given object:

  • GET /api/sunshine/objects/records

You don't need to get the records of standard Zendesk objects (tickets, users, and organizations). They're shared between the two custom objects experiences in the same account.

def get_object_records(object_type) -> list[dict]:    object_records: list[dict] = []    params = {'type': object_type['key'], 'per_page': 1000}    endpoint = 'api/sunshine/objects/records'    url = f'https://{ZENDESK_SUBDOMAIN}.zendesk.com/{endpoint}'    auth = f'{ZENDESK_USER_EMAIL}/token', ZENDESK_API_TOKEN    response = requests.get(url, params=params, auth=auth)
    # paginate through results    while url:        if response.status_code != 200:            print(f'Failed to retrieve {object_type["key"]} records: {response.status_code}: {response.text}')            return []
        records = response.json()['data']        if records:            object_records.extend(records)
        links = response.json()['links']        if links['next']:            url = f'https://{ZENDESK_SUBDOMAIN}.zendesk.com{links["next"]}'            response = requests.get(url, auth=auth)        else:            url = ''
    return object_records

Example function for migrating a record

The following example Python function creates a record in the new experience based on a legacy record.

The function uses the Create Custom Object Record endpoint:

  • POST /api/v2/custom_objects/{custom_object_key}/records

The body of a request consists of a custom_object_record object such as the following:

{  "custom_object_record": {    "custom_object_fields": {      "breed": "Corgi",      "training": false    },    "name": "Miso"  }}

The name property corresponds to the standard name field for the custom object. If you didn't map a field to it from the schema of the legacy object, you must provide a value when you create each record for the object. If you selected auto-numbering in Admin Center for the standard name field, then you can omit the name property from records because the value is automatically generated. If uniqueness is enforced for the standard name field, then make sure the name value is unique.

The example function assumes name auto-numbering and uniqueness are not enabled in Admin Center.

It's also important to get the id of each record you create and map it to the id of its associated legacy record, then save the map. You'll need this map to recreate the relationships between the records in the next step.

If you get errors, check the fields of the custom object to make sure they're correctly mapped to the schema of the legacy custom object. In Admin Center, click Objects and rules in the sidebar, then select Custom objects > Objects. Select the object, then click the Fields tab.

def migrate_object_record(record, record_map):
    # set the record name    if 'name' in record['attributes']:        name = record['attributes']['name']        del record['attributes']['name']    else:        name = record['type'].replace('_', ' ').capitalize()
    # create the request body    data = {        'custom_object_record': {            'custom_object_fields': record['attributes'],            'name': name        }    }
    # make the request    custom_object_key = record['type']      # assumes legacy and new object keys are same    endpoint = f'api/v2/custom_objects/{custom_object_key}/records'    url = f'https://{ZENDESK_SUBDOMAIN}.zendesk.com/{endpoint}'    response = requests.post(url, json=data, auth=AUTH)    if response.status_code != 201:        print(f'- Failed to create record for record {record["id"]}: {response.status_code}: {response.text}')        return {}
    data = response.json()    created_record_id = data['custom_object_record']['id']    record_map[record['id']] = created_record_id

Next steps

After migrating the records of your legacy custom objects, you can recreate the relationships between them. See Step 5: Migrating the relationship records of legacy custom objects.