{"revision":"c10276e953456835cdbb1f3a60d58ae1980be353","document":{"id":736,"path":"api-reference/server-api-reference/CopyDynamicSchemaAPI.md","title":"CopyDynamicSchemaAPI - Scoped, Global","bundle":null,"doc_type":null,"release":"australia","body":"\n# CopyDynamicSchemaAPI- Scoped, Global\n\nThe CopyDynamicSchemaAPI class provides methods and extension points for duplicating dynamic schema metadata.\n\nThe CopyDynamicSchemaAPI API accepts a specified dynamic category as input and proceeds to copy all associated metadata through an asynchronous background process. Metadata includes child categories, category members, attributes, choice sets, choices, and choice overrides.\n\nFor example, metadata schema is used to describe product characteristics like color, screen size, or network speed. These characteristics change over time, and the schema helps track those changes across versions for things like tech support or warranties. The CopyDynamicSchemaAPI allows you to duplicate these volumes of metadata in a single request.\n\nThis API provides a transaction ID and verification key for security purposes and to ensure that your logic only applies to authorized operations. This API additionally allows for customized naming and partial duplication by indicating which records to skip in the copy process. Should any part of the copy process fail, the system automatically initiates a rollback to reverse all changes made during the operation.\n\n## Requirements\n\nThis API requires the Dynamic Schema Support \\(com.glide.dynamic\\_schema\\) plugin and the Admin or dynamic\\_schema\\_writer role to access it.\n\n## Extension point methods\n\nThe copyDynamicSchema API supports a JavaScript class called DynamicSchemaCopyController, which implements three **optional** extension‑point methods that you define using custom logic. If you choose to implement the extension points, you must first create and define it before calling any API methods. Runtime invocation of extension point methods happens after your script calls runAsync\\(\\).\n\n**Note:** Presets \\(skipAttributes\\(\\), skipChoiceSets\\(\\), skipChoiceOverrrides\\(\\)\\) take precedence over extension method behavior.\n\nThese extension point methods define whether the copy process applies to the current transaction, whether a particular record is copied or skipped, and what the new copy name is. This allows you to control whether to skip certain metadata, rename items, enforce business rules, or avoid copying sensitive information.\n\nIf no extension points are provided, the API copies everything \\(unless the API is called with any of the skip methods, for example skipAttributes\\(\\)\\) and generates names for the copied elements.\n\nThe extension point methods are as follows:\n\n1.  [CopyDynamicSchemaAPI - verifyCopyOperation\\(String transactionId\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md) - Called before copying each major component type. Must return the same verification key supplied to getCopyApi\\(\\). If the method returns null, the extension point logic is ignored for this operation.\n2.  [CopyDynamicSchemaAPI - shouldCopy\\(Object recordData\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md) - If false, skips the copy of that record.\n3.  [CopyDynamicSchemaAPI - getCopyName\\(Object recordData\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md) - Creates a custom or auto-generated name for the copy.\n\n## CopyDynamicSchemaAPI workflow\n\nThe following workflow shows the order in which to call CopyDynamicSchemaAPI methods in your scripts:\n\n**Note:** If you choose to implement any extension point methods, you must first define them before calling the following API methods.\n\n1.  [CopyDynamicSchemaAPI - getCopyApi\\(String categoryToCopy, String verificationKey\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md) - Creates an object used later in the copy operation and validates inputs.\n2.  [CopyDynamicSchemaAPI - skipAttributes\\(\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md), [CopyDynamicSchemaAPI - skipChoiceSets\\(\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md), [CopyDynamicSchemaAPI - skipChoiceOverrides\\(\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md) - Presets to optionally skip attributes, choices, choice sets, and choice overrides during the copy operation. Must be called before runAsync\\(\\).\n3.  [CopyDynamicSchemaAPI - getTransactionId\\(\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md) - Used to store the transaction ID so your extension point can recognize this specific copy operation.\n4.  [CopyDynamicSchemaAPI - runAsync\\(\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md) - Starts the asynchronous copy process and triggers the extension points for each record being copied. Returns the transaction ID.\n5.  After runAsync\\(\\), the system runs the extension point methods you may have previously defined: verifyCopyOperation\\(\\), shouldCopy\\(\\), getCopyName\\(\\).\n\nIf any step fails, the API rolls back the entire transaction. You can monitor the operation's status in the Progress Worker \\[sys\\_progress\\_worker\\] table, Name column with a name format like `Copy Dynamic Schema – <transaction ID>`.\n\n**Parent Topic:**[Server API reference](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/api-server.md)\n\n## CopyDynamicSchemaAPI - getCopyApi\\(String categoryToCopy, String verificationKey\\)\n\nCreates and returns a CopyDynamicSchemaAPI object used to execute the copy operation. This method is provided in the DynamicSchemaCopyController class.\n\n<table id=\"table_rlv_v5c_xgc\" class=\"parameters\"><thead><tr><th>\n\nName\n\n</th><th>\n\nType\n\n</th><th>\n\nDescription\n\n</th></tr></thead><tbody><tr><td>\n\ncategoryTocopy\n\n</td><td>\n\nString\n\n</td><td>\n\nThe namespace name that uniquely identifies the given category to copy from.Example: `\"tech_store/u_device_specs/u_mobile_devices\"`\n\nTable: Dynamic Categories \\[dynamic\\_categories\\], \\(Computed\\) Namespaced Name column\n\n**Note:** You may need to manually add this column to your table view using the gear icon.\n\n</td></tr><tr><td>\n\nverificationKey\n\n</td><td>\n\nString\n\n</td><td>\n\nVerification key to authorize the copy operation. See [CopyDynamicSchemaAPI - getTransactionId\\(\\)](https://raw.githubusercontent.com/ServiceNow/ServiceNowDocs/australia/markdown/australia/api-reference/server-api-reference/CopyDynamicSchemaAPI.md) for more information.\n\n</td></tr></tbody>\n</table>|Type|Description|\n|----|-----------|\n|Object|A CopyDynamicSchemaAPI object used to get the transaction ID, perform the copy, or configure a preset strategy. Only returns null if unauthorized. Throws an exception if invalid or category isn't found.|\n\nThe following example script shows how to use getCopyApi\\(\\) to get a CopyDynamicSchemaAPI object that allows you to duplicate an existing category. To do this, the example calls getCopyApi\\(\\) with the target category's namespaced name \\(`tech_store/u_device_specs`\\) where `u_mobile_devices` is the name, and with a verification key \\(`verification_key`\\).\n\n```\nvar api = DynamicSchemaAPI.get().getCopyApi(\"tech_store/u_device_specs/u_mobile_devices\", \"verification_key\"); \n\napi.runAsync();\n```\n\nThis script returns a CopyDynamicSchemaAPI object. Output:\n\n```\n{CopyDynamicSchemaAPI@13721}\n```\n\nWith this object, you can monitor the operation, configure presets as needed, and initiate the copy process using additional copyDynamicSchema API methods.\n\n## CopyDynamicSchemaAPI - skipAttributes\\(\\)\n\nPreset enabling users to skip the copying of attributes during the copy operation.\n\n|Name|Type|Description|\n|----|----|-----------|\n|None| | |\n\n|Type|Description|\n|----|-----------|\n|Object|Returns a CopyDynamicSchemaAPI object with attributes omitted. Used to get the transaction ID, perform the copy, or configure a preset strategy. Only returns null if unauthorized. Throws an exception if invalid or category isn't found.|\n\nThe following example demonstrates how to use skipAttributes\\(\\) to skip the copying of attributes. Category members are still copied, but link to the original attribute as attributes themselves aren't copied. Additionally, any choices or choice overrides associated solely with attributes aren't included.\n\n```\nvar api = DynamicSchemaAPI.get().getCopyApi(\"tech_store/u_device_specs/u_mobile_devices\", \"verification_key\"); \n\napi.skipAttributes().runAsync(); \n```\n\nOutput:\n\n```\n{CopyDynamicSchemaAPI@13721}\n```\n\n## CopyDynamicSchemaAPI - skipChoiceOverrides\\(\\)\n\nPreset enabling users to skip the copying of all choice overrides during the copy operation.\n\n|Name|Type|Description|\n|----|----|-----------|\n|None| | |\n\n|Type|Description|\n|----|-----------|\n|Object|Returns a CopyDynamicSchemaAPI object with choice overrides omitted. Used to get the transaction ID, perform the copy, or configure a preset strategy. Only returns null if unauthorized. Throws an exception if invalid or category isn't found.|\n\nThe following example demonstrates how to use skipChoiceOverrides\\(\\). When this preset is applied, no choice overrides will be copied.\n\n```\nvar api = DynamicSchemaAPI.get().getCopyApi(\"tech_store/u_device_specs/u_mobile_devices\", \"verification_key\"); \n\napi.skipChoiceOverrides().runAsync();\n```\n\nOutput:\n\n```\n{CopyDynamicSchemaAPI@13721}\n```\n\n## CopyDynamicSchemaAPI - skipChoiceSets\\(\\)\n\nPreset enabling users to skip the copying of all choice sets and choices during the copy operation. All copied elements that would’ve linked to the copied choice set or choice will link to the original choice set or choice instead.\n\n|Name|Type|Description|\n|----|----|-----------|\n|None| | |\n\n|Type|Description|\n|----|-----------|\n|Object|Returns a CopyDynamicSchemaAPI object with choice sets and choices omitted. Used to get the transaction ID, perform the copy, or configure a preset strategy. Only returns null if unauthorized. Throws an exception if invalid or a category isn't found.|\n\nThe following example demonstrates how to use skipChoiceSets\\(\\). When this preset is applied to skip choice sets or choices in the copy operation. Choice overrides are still copied, but link to the original choice as choices themselves aren't copied.\n\n```\nvar api = DynamicSchemaAPI.get().getCopyApi(\"tech_store/u_device_specs/u_mobile_devices\", \"verification_key\"); \n\napi.skipChoiceSets().runAsync();\n```\n\nOutput:\n\n```\n{CopyDynamicSchemaAPI@13721}\n```\n\n## CopyDynamicSchemaAPI - getTransactionId\\(\\)\n\nGenerates and returns a unique transaction ID for each copy operation you start. This ID is used to track the operation and is passed to extension points for validation and custom logic. This method is provided in the DynamicSchemaCopyController class.\n\nThe transaction ID is used by extension points like getCopyName\\(\\) to ensure that custom logic only applies to the correct copy transaction. You can store this ID in a custom table to reference it later or to coordinate with other scripts.\n\n|Name|Type|Description|\n|----|----|-----------|\n|None| | |\n\n<table id=\"table_wqx_wvc_xgc\" class=\"returns\"><thead><tr><th>\n\nType\n\n</th><th>\n\nDescription\n\n</th></tr></thead><tbody><tr><td>\n\nString\n\n</td><td>\n\nTransaction ID that can be used to identify the copy operation. You can check the status of the copy operation in the Progress Worker \\[sys\\_progress\\_worker\\] table, Name column.Naming format: Copy Dynamic Schema - &lt;transaction ID&gt;\n\n</td></tr></tbody>\n</table>The following example shows how to use getTransactionId\\(\\) to retrieve and store a transaction ID before copying a dynamic schema. The user calls getTransactionId\\(\\) to obtain the transaction ID and store it in a custom table. When the extension point implementation is invoked during the copy process, it can check against stored transaction IDs to determine whether it should provide custom naming logic or return null to ignore the transaction.\n\n```\nvar api = DynamicSchemaAPI.get().getCopyApi(\"tech_store/u_device_specs/u_mobile_devices\", \"verification_key\"); \nvar id = api.getTransactionId(); \n\nvar gr = new GlideRecord(\"u_copy_transactions\"); \ngr.initialize(); \ngr.setValue(\"u_transaction_id\", id); \ngr.insert(); \n\napi.runAsync(); \n```\n\nOutput returns the unique transaction ID:\n\n```\n“9a8e0f92ff5032103c16ffffffffff82”\n```\n\n## CopyDynamicSchemaAPI - runAsync\\(\\)\n\nStarts the copy process for dynamic schema components and returns a transaction ID for identifying the copy operation. This method is provided in the DynamicSchemaCopyController class.\n\nThe runAsync\\(\\) method runs the copy operation asynchronously in the background, and calls the extension points, getCopyName\\(\\), shouldCopy\\(\\), and verifyCopyOperation\\(\\), during the copy process to customize naming and security. To view the status of the copy operation, see the Progress Worker \\[sys\\_progress\\_worker\\] table, Name column with a naming format of `Copy Dynamic Schema - <transaction ID>`.\n\nIf any part of the copy fails, the API automatically rolls back all changes to maintain data consistency.\n\n|Name|Type|Description|\n|----|----|-----------|\n|None| | |\n\n<table id=\"table_ifr_2wc_xgc\" class=\"returns\"><thead><tr><th>\n\nType\n\n</th><th>\n\nDescription\n\n</th></tr></thead><tbody><tr><td>\n\nString\n\n</td><td>\n\nTransaction ID used to identify the copy operation. The copy process is asynchronous, but you can check the status of the copy operation in the Progress Worker \\[sys\\_progress\\_worker\\] table, Name column with a naming format of `Copy Dynamic Schema - <transaction ID>`.The copying behavior depends on the extension point implementation and the skip method presets. Components are only skipped if the skip\\(\\) method presets are called or if the extension point shouldCopy\\(\\) returns false.\n\n</td></tr></tbody>\n</table>The following example script shows how to initiate a dynamic schema copy operation using the runAsync\\(\\) method where `tech_store/u_device_specs/u_mobile_devices` is the unique name of the category to copy and `verification_key` is a verification key. After obtaining the copy API instance and storing the transaction ID for extension point reference, runAsync\\(\\) begins the copy process for all schema components \\(categories, category members, attributes, choice sets, choices, and choice overrides\\).\n\n```\nvar api = DynamicSchemaAPI.get().getCopyApi(\"tech_store/u_device_specs/u_mobile_devices\", \"verification_key\"); \n\napi.runAsync();\n```\n\nOutputs the transaction ID:\n\n```\n“9a8e0f92ff5032103c16ffffffffff82”\n```\n\n## CopyDynamicSchemaAPI - getCopyName\\(Object recordData\\)\n\nExtension point method allowing custom names for a copy or an auto-generated name if empty or null. This extension point method is provided in the DynamicSchemaCopyController JavaScript class.\n\n<table id=\"table_fb1_1fz_13c\" class=\"parameters\"><thead><tr><th>\n\nName\n\n</th><th>\n\nType\n\n</th><th>\n\nDescription\n\n</th></tr></thead><tbody><tr><td>\n\nrecordData\n\n</td><td>\n\nObject\n\n</td><td>\n\nObject containing record metadata: -   `name`: record name\n-   `namespaced_name`: namespace + record name\n-   `table_name`: table name\n-   `sys_id`: unique system ID\n\n</td></tr></tbody>\n</table><table id=\"table_gb1_1fz_13c\" class=\"returns\"><thead><tr><th>\n\nType\n\n</th><th>\n\nDescription\n\n</th></tr></thead><tbody><tr><td>\n\nString\n\n</td><td>\n\nProposed name for this copy.Possible errors:\n\n-   Name is more than 60 characters.\n-   Copy name already exists.\n\n</td></tr><tr><td>\n\nString \\(empty or null\\)\n\n</td><td>\n\nAutogenerated name for this copy.\n\n</td></tr></tbody>\n</table>This example shows an implementation of the extension point. After the shouldCopy\\(\\) method returns `true` to confirm the user's intent to copy the record, the user provides a custom name for the copy by defining getCopyName\\(\\). For example, the user can append \"\\_copy\" to the original name as a chosen label, or allow the system to automatically generate a name.\n\n```\nvar DynamicSchemaCopyController = Class.create(); \nDynamicSchemaCopyController.prototype = { \n \n    initialize: function() {}, \n\n    verifyCopyOperation: function(transactionId) { \n        var transactionIdExist = new GlideRecord('u_copy_transactions'); \n        transactionIdExist.addQuery('u_transaction_id', transactionId); \n        transactionIdExist.query(); \n \n        if (transactionIdExist.hasNext()) { \n            return 'verification_key'; \n        } \n        else { \n            return null; \n        } \n    }, \n \n    shouldCopy: function(recordData) { \n        var namespacedNameSkip = [ \n            'tech_store/u_device_specs/u_phone', \n            'tech_store/u_device_specs/u_storage' \n        ]; \n        var recordNamespacedName = String(recordData.get('namespaced_name')); \n        if (namespacedNameSkip.includes(recordNamespacedName)) { \n            return false; \n        } \n        return true; \n    }, \n \n    getCopyName: function(recordData) { \n        return String(recordData.get('name') + '_copy'); \n    }, \n \n    type: 'DynamicSchemaCopyController' \n\n};\n```\n\nOutput:\n\n```\nRecord's name + \"_copy\"\n```\n\n## CopyDynamicSchemaAPI - shouldCopy\\(Object recordData\\)\n\nExtension point method for creating custom copy operations by allowing users to specify whether a particular record should be copied. The method returns true if the record is to be copied and false if it should be skipped.\n\nThis extension point method is provided in the DynamicSchemaCopyController class, and provides flexibility for users to control which records are included in the copy process based on their requirements.\n\n<table id=\"table_z44_mdz_13c\" class=\"parameters\"><thead><tr><th>\n\nName\n\n</th><th>\n\nType\n\n</th><th>\n\nDescription\n\n</th></tr></thead><tbody><tr><td>\n\nrecordData\n\n</td><td>\n\nJava HashMap\n\n</td><td>\n\nJava HashMap containing record metadata: -   name: record name\n-   namespaced\\_name: namespace + record name\n-   table\\_name: table name\n-   sys\\_id: unique system ID\n\n</td></tr></tbody>\n</table><table id=\"table_ap4_mdz_13c\" class=\"returns\"><thead><tr><th>\n\nType\n\n</th><th>\n\nDescription\n\n</th></tr></thead><tbody><tr><td>\n\nBoolean\n\n</td><td>\n\nReturns true if a copy should be made and false otherwise.Flag that indicates whether a copy should be made.\n\nValid values:\n\n-   true: Make a copy.\n-   false: Don't make a copy.\n\n</td></tr></tbody>\n</table>This example shows an implementation of the shouldCopy\\(\\) extension point. Once verification is complete, the method enables users to implement custom copying logic, allowing them to skip records according to criteria such as name, namespaced\\_name, table, or sys\\_id.\n\n```\nvar DynamicSchemaCopyController = Class.create(); DynamicSchemaCopyController.prototype = { \n \n    initialize: function() {}, \n\n    verifyCopyOperation: function(transactionId) { \n        var transactionIdExist = new GlideRecord(‘u_copy_transactions’); \n        transactionIdExist.addQuery(‘u_transaction_id’, transactionId); \n        transactionIdExist.query(); \n \n        if (transactionIdExist.hasNext()) { \n            return ‘verification_key’; \n        } \n        else { \n            return null; \n        } \n    }, \n \n    shouldCopy: function(recordData) { \n        var namespacedNameSkip = [ \n            ‘tech_store/u_device_specs/u_phone’, \n            ‘tech_store/u_device_specs/u_storage’ \n        ]; \n        var recordNamespacedName = String(recordData.get(‘namespaced_name’)); \n        if (namespacedNameSkip.includes(recordNamespacedName)) { \n            return false; \n        } \n        return true; \n    }, \n \n    getCopyName: function(recordData) { \n        return String(recordData.get(‘name’) + ‘_copy’); \n    }, \n \n    type: 'DynamicSchemaCopyController' \n\n};\n```\n\nReturns `true` if the namespaced\\_name isn’t equal to `tech_store/u_device_specs/u_phone` or `tech_store/u_device_specs/u_storage`.\n\n## CopyDynamicSchemaAPI - verifyCopyOperation\\(String transactionId\\)\n\nExtension point method used to verify the transaction ID of the copy operation before returning the matching verification key from getCopyApi\\(\\), ensuring relevance to the extension point implementation. This extension point method is provided in the DynamicSchemaCopyController class.\n\n|Name|Type|Description|\n|----|----|-----------|\n|transactionId|String|A unique string that identifies each copy operation.|\n\n|Type|Description|\n|----|-----------|\n|String|Verification key from getCopyApi\\(\\), or null if the transaction ID isn't relevant to this extension point.|\n\nThis example shows an implementation of the verifyCopyOperation\\(\\) extension point. The user is required to verify the transaction ID associated with the copy operation before returning the verification key. The verification key must correspond to the value provided as an argument to the getCopyApi\\(\\) method.\n\n```\nvar DynamicSchemaCopyController = Class.create(); DynamicSchemaCopyController.prototype = { \n \n    initialize: function() {}, \n\n    verifyCopyOperation: function(transactionId) { \n        var transactionIdExist = new GlideRecord(‘u_copy_transactions’); \n        transactionIdExist.addQuery(‘u_transaction_id’, transactionId); \n        transactionIdExist.query(); \n \n        if (transactionIdExist.hasNext()) { \n            return ‘verification_key’; \n        } \n        else { \n            return null; \n        } \n    }, \n \n    shouldCopy: function(recordData) { \n        var namespacedNameSkip = [ \n            ‘tech_store/u_device_specs/u_phone’, \n            ‘tech_store/u_device_specs/u_storage’ \n        ]; \n        var recordNamespacedName = String(recordData.get(‘namespaced_name’)); \n        if (namespacedNameSkip.includes(recordNamespacedName)) { \n            return false; \n        } \n        return true; \n    }, \n \n    getCopyName: function(recordData) { \n        return String(recordData.get(‘name’) + ‘_copy’); \n    }, \n \n    type: 'DynamicSchemaCopyController' \n\n}; \n```\n\nOutput:\n\n```\n“verification_key”\n```\n\n"}}