Migrate content between SitecoreAI environments using the Content Transfer API and the Item Transfer API

This walkthrough describes how to use the Content Transfer API and the Item Transfer API to migrate content from one SitecoreAI environment to another. The instructions cover all the steps required to complete a migration:

  1. Create the transfer
  2. Wait for the transfer to be ready
  3. Transfer chunks
  4. Delete the transfer in the source environment
  5. Load the content into the destination database

Note that the same instructions are also available in the Migrating content sections of the Content Transfer API and the Item Transfer API specifications. This allows AI coding assistants and agent tools that directly consume the OpenAPI specifications to guide you through the migration workflow without leaving your development environment.

Before you begin
  • Ensure you have the Organization Admin or Organization Owner role in the Sitecore Cloud Portal. Both APIs require this role.
  • Find the host names for your source and destination environments in SitecoreAI Deploy > Projects > your project > Authoring environments > your environment > Details > Environment host name. You use the host name to construct the base URL for each API request.
  • Create automation client credentials for both environments and generate a JWT for each. See the Content Transfer API and Item Transfer API specifications for instructions.

Create the transfer

Make the following API request in your source environment:

POST /sitecore/api/content/transfer/v1/transfers

Specify a unique TransferId UUID of your choice, and one or more entries in DataTrees. Use one entry per item path you want to transfer. For each entry, set:

  • ItemPath - the Sitecore content path of the item.
  • Scope - choose SingleItem to transfer only the item. Choose ItemAndDescendants to transfer the item and its entire subtree. Ensure that the item's parent chain exists in the destination environment with the same item IDs. If it does not, the item will transfer successfully but will not appear in the content tree. To avoid this, transfer from a common ancestor using ItemAndDescendants, or ensure all parent items are transferred first.
  • MergeStrategy - how to handle conflicts with items that already exist in the destination. The options are:
    • OverrideExistingItem - replace the existing item with the transferred version.
    • KeepExistingItem - leave the existing item unchanged.
    • OverrideExistingTree - remove the item and all its descendants from the destination, then write all items from the transfer. This is the only merge strategy that can delete existing items. Use with caution.

Example request body:

{
  "TransferId": "12345678-1234-1234-1234-123456789abc",
  "Configuration": {
    "DataTrees": [
      {
        "ItemPath": "/sitecore/content/Home",
        "Scope": "ItemAndDescendants",
        "MergeStrategy": "OverrideExistingItem"
      }
    ],
    "Database": "master"
  }
}

A successful request returns 202 Accepted.

Wait for the transfer to be ready

Make the following API request in your source environment using the TransferId from the previous procedure:

GET /sitecore/api/content/transfer/v1/transfers/{transferId}/status

Poll this endpoint until State is Completed. If State is Failed, the transfer was not successful and cannot continue. In this scenario, create a new transfer. The response includes a ChunkSetsMetadata array. For each chunk set, record:

  • ChunkSetId - the unique identifier of the chunk set, used as a path parameter in subsequent requests.
  • ChunkCount - the number of chunks to retrieve. Chunks are numbered 0 through ChunkCount - 1.

Transfer chunks

For each chunk, repeat the retrieve and save steps. After all chunks in a set are saved, complete the chunk set once.

Retrieve a chunk from the source environment

Make the following API request in your source environment:

GET /sitecore/api/content/transfer/v1/transfers/{transferId}/chunksets/{chunksetId}/chunks/{chunkId}

Make one request per chunk, using chunkId values 0 through ChunkCount - 1. The response body is a binary stream. Note the IsMedia value from the Content-Disposition response header because you'll use it in the next step.

You can retrieve multiple chunks in parallel.

Save the chunk in the destination environment

Make the following API request in your destination environment:

PUT /sitecore/api/content/transfer/v1/transfers/{transferId}/chunksets/{chunksetId}/chunks/{chunkId}

  • Set Content-Type: application/octet-stream.
  • Set the isMedia query parameter to the IsMedia value from the previous step.
  • Forward the binary stream exactly as received. Do not decompress, decrypt, or modify the data.

A successful request returns 201 Created.

You can save chunks in parallel with retrieval, but all chunks in a set must be saved before you complete that chunk set.

Complete the chunk set in the destination environment

After all chunks in a set are saved, make the following API request in your destination environment:

POST /sitecore/api/content/transfer/v1/transfers/{transferId}/chunksets/{chunksetId}/complete

This generates a .raif file in the destination and returns its name:

{
  "ContentTransferFileName": "content-transfer-12345678-1234-1234-1234-123456789abc.raif"
}

Record this file name because you'll use it in a later procedure.

Delete the transfer in the source environment

Make the following API request in your source environment:

DELETE /sitecore/api/content/transfer/v1/transfers/{transferId}

This cleans up the transfer operation and all associated resources. You can do this immediately after downloading all chunks from the source environment.

Load the content into the destination database

To complete the migration, use the Item Transfer API in your destination environment to incorporate the .raif files into the database.

Verify the blob is available

Before consuming a .raif file, confirm it is available in Azure Blob Storage by making the following API request in your destination environment:

GET /sources/blobs

The response lists available blob sources and their states. The .raif file you recorded in the previous step should appear with a BlobState of Uploaded, which means that the file is ready to consume.

Start consuming the blob

Make the following API request in your destination environment:

POST /transfers/databases/{databaseName}/sources?blobName={ContentTransferFileName}

The location response header contains a URL. The final path segment of this URL is the transfer ID used in subsequent requests.

Transferred items are immediately available to work with in the destination environment while the system completes the sync to the database in the background.

Monitor the transfer

Although items are available immediately, poll the transfer status to detect failures. If the background sync fails before completing, items that were not yet synced will become unavailable and the transfer must be retried.

Make the following API request in your destination environment and poll it until TransferState is Finished:

GET /transfers/{transferId}

If TransferState is Failed, retry the transfer using the following endpoint:

PUT /transfers/databases/{databaseName}/sources/{sourceName}

Clean up the destination environment

After the transfer is finished, make the following API request in your destination environment:

DELETE /sources/blobs/{blobName}

This removes the .raif file, which is no longer needed.

Transferred items follow your normal publishing workflow.

Troubleshooting

TransferredWithErrors state

If BlobState is TransferredWithErrors, this is a terminal state indicating a partial success. To investigate, retrieve the transfer details to review the ValidationErrors list:

GET /transfers/{transferId}

Items transferred but not visible in the content tree

If a transferred item does not appear in the destination content tree, the most likely cause is that the parent chain does not exist in the destination environment with the same item IDs. To fix this, either transfer from a common ancestor using Scope: ItemAndDescendants, or transfer the parent items first before transferring the child item.

If you have suggestions for improving this article, let us know!