Moving Content Between SitecoreAI Environments: A Look at the Content Transfer API and Item Transfer API
Moving content between Sitecore environments is a common task. Content created in development often needs to be moved to staging and then to production. Depending on the project, this can become a regular part of the development and release process.
In traditional Sitecore XP implementations, we often used Package Designer to package content and install it in another environment. But with modern Sitecore SaaS solutions, we need approaches that fit better into automated workflows.
In my session at Sitecore User Group France, I discussed how the Content Transfer API and Item Transfer API can be used to move content between Sitecore environments. I also walked through a Postman collection to demonstrate how these APIs work together.
Let's look at how the APIs work, how to use them, and what to consider before building an automation solution around them.
Why Do We Need Another Way to Move Content?
The usual content promotion process looks something like this:
Development → Staging → Production
When this process is manual, someone needs to select the content, create a package, move it to the target environment, and install it. This becomes repetitive when content needs to be moved frequently.
Traditional packaging also has limitations when used in modern SaaS delivery workflows:
- Packages have size limitations.
- The merge strategy needs to be considered carefully.
- The package installation process does not fit naturally into every SaaS automation workflow.
- Manual steps make it harder to build repeatable content promotion pipelines.
The Content Transfer API and Item Transfer API provide another way to approach this problem. They allow content transfer and import operations to be orchestrated through API calls.
The APIs handle the transfer operations, but we still need an orchestration layer to coordinate the complete process.
Understanding the Two APIs
The important thing to understand is that the Content Transfer API and Item Transfer API perform different jobs. They are designed to work together.
1. Content Transfer API
The Content Transfer API handles the export and chunk-transfer part of the process. It creates a transfer operation on the source environment, provides information about the chunks, and allows those chunks to be transferred to the destination environment.
Its base path is:
/sitecore/api/content/transfer/v1
The result of completing the transfer is a blob name, represented by the ContentTransferFileName value.
2. Item Transfer API
The Item Transfer API handles importing the transferred content into the target database.
Its base path is:
/sitecore/shell/api/v3/ItemsTransfer
It uses the blob produced by the Content Transfer API to start the import operation, monitor its status, and clean up the transferred artifact when it is no longer needed.
In simple terms, the overall process looks like this:
- Start an export on the source environment.
- Wait for the export to complete.
- Download the chunks from the source.
- Upload the chunks to the destination.
- Complete the chunk set and obtain the blob name.
- Use the Item Transfer API to import the blob into the target database.
- Check the import status and clean up the blob.
The two APIs together form a scriptable content migration pipeline.
Step 1: Create a Transfer Operation
The first step is to create a transfer operation on the source environment.
You provide a transfer ID, the target database, the item path, the scope of the transfer, and the merge strategy.
For example, the following request exports an item and all its descendants:
POST {source}/sitecore/api/content/transfer/v1/transfers
Authorization: Bearer <token>
Content-Type: application/json
{
"TransferId": "3f2a9c1e-7d54-4b0e-9a12-8c6d4e5f2a11",
"Configuration": {
"Database": "master",
"DataTrees": [
{
"ItemPath": "/sitecore/content/Home/Getting Started",
"Scope": "ItemAndDescendants",
"MergeStrategy": "OverrideExistingTree"
}
]
}
}
The TransferId is a UUID generated by the client. It is used to identify the transfer operation throughout the process.
Using a consistent transfer ID is important because the subsequent calls need to refer to the same transfer.
Step 2: Poll the Export Status
Creating the transfer does not mean that the export is immediately ready. The next step is to check its status.
GET /transfers/{TransferId}/status
Authorization: Bearer <token>
The response includes the transfer state and metadata about the chunk sets.
A simplified response might look like this:
{
"State": "Completed",
"ChunkSetsMetadata": [
{
"ChunkSetId": "e2b7c0a4-...",
"ChunkCount": 4,
"TotalItemCount": 37,
"IsMedia": false
}
]
}
The important values are:
Statetells you whether the export has completed or failed.ChunkSetIdidentifies a chunk set.ChunkCounttells you how many chunks need to be transferred.TotalItemCountindicates the number of items represented by the chunk set.IsMediaidentifies whether the chunk set contains media data.
Your orchestration code should wait for the export to complete before downloading the chunks. If the operation fails, inspect the response and handle the error rather than proceeding with an incomplete transfer.
Step 3: Download the Chunks from the Source
Once the export is complete, the next step is to download the chunks.
The chunk endpoint follows this pattern:
GET /transfers/{TransferId}/chunksets/{ChunkSetId}/chunks/{chunkId}
Authorization: Bearer <token>
The chunk ID is sequential, starting at zero. You iterate from zero to ChunkCount - 1 for each chunk set.
The response contains binary data. It is important to treat the response as a binary payload rather than as ordinary JSON.
Also pay attention to the IsMedia information returned for the chunk. The corresponding value needs to be passed when uploading that chunk to the destination.
Step 4: Upload the Chunks to the Destination
After downloading a chunk from the source, upload it to the destination environment.
PUT {destination}/transfers/{TransferId}/chunksets/{ChunkSetId}/chunks/{chunkId}?isMedia={true|false}
Authorization: Bearer <token>
Content-Type: application/octet-stream
The request body must contain the original binary chunk data.
Use the same transfer ID, chunk set ID, and chunk ID when uploading the corresponding chunk to the destination.
There are a few things to keep in mind:
- Preserve the binary payload without converting it to a string or JSON representation.
- Pass the correct
isMediavalue. - Confirm that each upload succeeds before marking the chunk as transferred.
- Track failed uploads so they can be retried safely.
Although parallel uploads may be possible, they introduce additional complexity around tracking the state of individual chunks. Sequential uploads can be a simpler starting point when building an initial implementation.
Step 5: Complete the Chunk Set
After all chunks belonging to a chunk set have been uploaded, call the complete endpoint on the destination environment.
POST {destination}/sitecore/api/content/transfer/v1/transfers/{TransferId}/chunksets/{ChunkSetId}/complete
Authorization: Bearer <token>
The response contains the blob name:
{
"ContentTransferFileName": "a1b2c3d4-....data"
}
This value is important because it connects the Content Transfer API with the Item Transfer API.
Save the ContentTransferFileName value. You will need it when starting the import operation.
Step 6: Import the Blob Using the Item Transfer API
With the blob available on the destination environment, the next step is to import it into the target database.
The Item Transfer API provides three main operations for this part of the process.
6.1 Start the import
POST /sitecore/shell/api/v3/ItemsTransfer/transfers/databases/{database}/sources?blobName={ContentTransferFileName}
Authorization: Bearer <token>
The request starts the import job. A successful response returns 202 Accepted along with a Location header that identifies the job location.
6.2 Check the import status
GET /sitecore/shell/api/v3/ItemsTransfer/sources/blobs/{blobName}
Authorization: Bearer <token>
The response contains the current BlobState. The state can progress through stages such as:
Queued
-> Uploading
-> Uploaded
-> Initializing
-> Transferred
Other possible outcomes include TransferredWithErrors, Error, and Discarded.
Do not assume that receiving a successful response when starting the job means the content has already been imported. Monitor the state and handle unsuccessful outcomes appropriately.
6.3 Clean up the blob
After the transfer has reached an appropriate terminal state and you no longer need the artifact, use the cleanup endpoint:
DELETE /sitecore/shell/api/v3/ItemsTransfer/sources/blobs/{blobName}
Authorization: Bearer <token>
Cleanup should be part of the orchestration process, with suitable error handling and logging.
Choosing the Correct Scope and Merge Strategy
The scope and merge strategy are two important settings in the transfer configuration. Choosing the wrong merge strategy can result in unintended changes to the destination content.
Scope
- SingleItem: transfers only the specified item, without its children.
- ItemAndDescendants: transfers the specified item and its descendants.
Merge strategy
- OverrideExistingTree: replaces the existing tree. This can be appropriate for development-to-staging promotion when the destination tree should match the source.
- OverrideExistingItem: updates an item while preserving its children.
- KeepExistingItem: creates an item only if it does not already exist. This can be useful when seeding a fresh environment without overwriting existing items.
Always confirm the intended outcome before selecting a strategy, especially when running transfers against production. Test the chosen scope and merge behaviour in a non-production environment first.
Limitations to Consider
Although these APIs provide a useful way to move content between environments, they do not replace every part of a deployment pipeline.
Code and file-system artifacts
DLLs, configuration transforms, and other file-system artifacts are not migrated through these content transfer APIs. These artifacts should continue to be deployed through your normal CI/CD pipeline, such as Azure DevOps or GitHub Actions.
Security accounts
Sitecore security accounts are not included in content transfers. Depending on the implementation, alternatives include claims mapping through an external identity provider or using Sitecore CLI for scripted account provisioning.
Orchestration complexity
The APIs provide the operations needed for the transfer, but the client still needs to coordinate multiple calls. This includes generating and tracking transfer IDs, polling status, iterating over chunks, handling media, retrying failures, and cleaning up artifacts.
Without a reusable orchestration layer, this logic can become difficult to maintain as the number of transfers grows.
Authentication and Security
The APIs use OAuth 2.0 client credentials authentication. The client acts as an automation identity rather than relying on an individual user's login session.
A token can be requested from the Sitecore authentication endpoint:
POST https://auth.sitecorecloud.io/oauth/token
Content-Type: application/x-www-form-urlencoded
client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&grant_type=client_credentials
&audience=https://api.sitecorecloud.io
The token response includes an access token and its expiry information. The presentation uses 3600 seconds as the token lifetime example.
All API calls need the appropriate bearer token for the environment being accessed. When transferring content between separate source and destination environments, ensure that the credentials and permissions are configured correctly for both sides.
Some security practices worth following are:
- Store client secrets in a secrets vault, such as Azure Key Vault.
- Rotate credentials regularly.
- Use least-privilege permissions for automation identities.
- Never hardcode client secrets in source control.
- Refresh tokens before they expire to avoid failures during long-running transfers.
Building an Orchestration Layer
The API calls are only part of the solution. To make the process useful in day-to-day development, we need an orchestration layer that executes them in the correct order.
This layer should be responsible for:
- Creating and tracking transfer operations.
- Polling export and import status.
- Downloading and uploading every required chunk.
- Preserving media-related metadata.
- Handling retries and failures.
- Recording the result of each operation.
- Cleaning up transfer artifacts when appropriate.
For my SUG France session, I demonstrated a Postman collection that helps explore and execute the API workflow. A browser extension built on top of these APIs is another way to provide a more accessible interface for content transfer.
The choice between a Postman collection, a command-line tool, a browser extension like Bridge, or a CI/CD-integrated service depends on how frequently the operation runs, who needs to use it, and how much automation is required.
Conclusion
The Content Transfer API and Item Transfer API provide a way to move content between Sitecore environments without depending entirely on manual package-based processes.
The Content Transfer API handles the export and chunk-transfer stages, while the Item Transfer API imports the resulting blob into the target database. Together, they can form the basis of a repeatable content promotion workflow.
The most important part is not simply calling the APIs. It is orchestrating them correctly, choosing the right merge strategy, handling errors, and securing the credentials used by the automation.
If you are building a modern Sitecore content promotion process, these APIs are worth exploring. Start with a small transfer in a non-production environment, understand the complete lifecycle, and then build the automation around your team's requirements.
This article is based on my session, “Moving Content Between Sitecore Environments, the API Way,” presented at Sitecore User Group France.
You can connect with me on LinkedIn or find more Sitecore articles on my blog.
Comments
Post a Comment