Bulk entry operations
Bulk entry content operations provide an efficient way to create, update, or delete multiple entries simultaneously, reducing the number of API calls required for bulk content management. This feature is particularly useful when working with large datasets, as it significantly reduces the time and complexity required for handling a larger number of entries. The operation is asynchronous and returns immediately with a job ID that you can use to track the progress of the bulk operation.
Why bulk entry content operations?
Traditional entry management requires individual API calls for each entry, which can be time-consuming and inefficient when dealing with hundreds or thousands of entries, leading to several challenges:
- API rate limits: Creating entries one-by-one can quickly exhaust rate limits, especially for large datasets
- Network overhead: Each API call introduces latency, making bulk operations slow
- Complexity: Managing individual requests, error handling, and retry logic adds significant complexity to client code
- Resource consumption: Multiple HTTP connections consume more resources on both client and server
Key benefits
The bulk entry content operations feature uses an asynchronous processing model to handle large volumes of entries efficiently, providing the following benefits:
- Performance: Create, update, or delete hundreds of entries in seconds instead of minutes
- Efficiency: Significantly reduce API calls for a large number of operations
- Non-blocking operations: Your application can continue working while entries are being processed in the background
- Progress tracking: Real-time visibility into how many entries have been processed
- Reliability: Built-in error handling with detailed reporting for individual entry failures
- Graceful error handling: Individual entry failures don't halt the entire operation
- Scalability: The system can handle multiple concurrent bulk operations across different spaces
How it works
1. Prepare your data
Structure your entries as a JSON array in a file (e.g., entries.json). The format depends on the operation:
Create: Each entry must include
sys.contentTypeandfields. Omitsys.idfor auto-generated IDs.Update: Each entry must include
sys.id,sys.version(must match the current version), andfields.Delete: Each entry must include only
sys.id.Example: Preparing entries for bulk creation
[ { "sys": { "contentType": {"sys": {"id": "article"}} }, "fields": { "title": { "en-US": "Getting Started with Contentful" }, "body": { "en-US": "This is a comprehensive guide to getting started with Contentful." } } }, { "sys": { "contentType": {"sys": {"id": "article"}} }, "fields": { "title": { "en-US": "Advanced Content Modeling Techniques" } } } ]Example: Preparing entries for bulk deletion
[ {"sys": {"id": "existing-entry-id-1"}}, {"sys": {"id": "existing-entry-id-2"}} ]
2. Upload entries file
Upload your entries file to https://upload.contentful.com/spaces/{space_id}/environments/{environment_id}/uploads
Upload using cURL:
curl -X POST "https://upload.contentful.com/spaces/<space_id>/environments/<environment_id>/uploads" \
-H "Authorization: Bearer <cma_token>" \
-H "Content-Type: application/octet-stream" \
--data-binary @entries.json
Response:
The API returns an Upload resource containing the upload ID:
{
"sys": {
"id": "6gbwC4qRtakgsdqUcCPihF",
"type": "Upload",
"createdAt": "2025-11-27T13:47:57.000Z",
"expiresAt": "2025-11-29T00:00:00.000Z",
"space": {
"sys": {
"type": "Link",
"linkType": "Space",
"id": "ncbxgqx5v0xe"
}
},
"environment": {
"sys": {
"type": "Link",
"linkType": "Environment",
"id": "master"
}
}
}
}
3. Receive upload ID
The API returns an Upload resource with an ID.
4. Trigger bulk operation
Send a POST request to the factory endpoint for the desired action:
Create:
POST https://api.contentful.com/spaces/{space_id}/environments/{environment_id}/bulk_operations/entries/createUpdate:
POST https://api.contentful.com/spaces/{space_id}/environments/{environment_id}/bulk_operations/entries/updateDelete:
POST https://api.contentful.com/spaces/{space_id}/environments/{environment_id}/bulk_operations/entries/deleteTrigger a bulk creation using cURL:
curl -X POST "https://api.contentful.com/spaces/<space_id>/environments/<environment_id>/bulk_operations/entries/create" \ -H "Authorization: Bearer <cma_token>" \ -H "Content-Type: application/vnd.contentful.management.v1+json" \ -d '{"upload":{"sys":{"type":"Upload","id":"6gbwC4qRtakgsdqUcCPihF"}}}'Response:
The API returns a
BulkOperationresource withsys.statusset toin_progress:{ "sys": { "id": "bulkOperationId123", "type": "BulkOperation", "bulkType": "EntriesCreate", "status": "in_progress", "space": { "sys": { "type": "Link", "linkType": "Space", "id": "ncbxgqx5v0xe" } }, "environment": { "sys": { "type": "Link", "linkType": "Environment", "id": "master" } }, "createdBy": { "sys": { "type": "Link", "linkType": "User", "id": "userId" } }, "createdAt": "2025-11-27T13:50:00.000Z", "updatedAt": "2025-11-27T13:50:00.000Z" }, "payload": { "upload": { "sys": { "type": "Upload", "id": "6gbwC4qRtakgsdqUcCPihF" } } } }
5. Receive operation ID
The API returns a BulkOperation resource. Use sys.id to poll for status.
6. Track progress
Poll https://api.contentful.com/spaces/{space_id}/environments/{environment_id}/bulk_operations/{operation_id} until sys.status is completed or failed.
Check status using cURL:
curl -X GET "https://api.contentful.com/spaces/<space_id>/environments/<environment_id>/bulk_operations/<bulk_operation_id>" \
-H "Authorization: Bearer <cma_token>"
Response when completed:
{
"sys": {
"id": "bulkOperationId123",
"type": "BulkOperation",
"bulkType": "EntriesCreate",
"status": "completed",
"space": {
"sys": {
"type": "Link",
"linkType": "Space",
"id": "ncbxgqx5v0xe"
}
},
"environment": {
"sys": {
"type": "Link",
"linkType": "Environment",
"id": "master"
}
},
"createdBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "userId"
}
},
"createdAt": "2025-11-27T13:50:00.000Z",
"updatedAt": "2025-11-27T13:55:00.000Z"
},
"payload": {
"upload": {
"sys": {
"type": "Upload",
"id": "6gbwC4qRtakgsdqUcCPihF"
}
}
},
"result": {
"items": [
{
"status": "succeeded",
"entity": {
"sys": {
"type": "Entry",
"id": "newEntryId1"
}
}
},
{
"status": "succeeded",
"entity": {
"sys": {
"type": "Entry",
"id": "newEntryId2"
}
}
},
{
"status": "failed",
"error": {
"sys": {
"type": "Error",
"id": "InvalidEntry"
},
"message": "Validation error"
}
}
]
}
}
7. Retrieve results
Once sys.status is completed, check result.items for per-entry outcomes. Each item has a status of "succeeded" or "failed". Failed items include an error object with a machine-readable sys.id and a human-readable message.
Error handling
It's important to understand the difference between the status of the bulk operation itself and the status of individual entries within that operation.
The bulk operation status is available at sys.status and reflects the job lifecycle:
"in_progress": The operation is queued or currently being processed"completed": The operation finished processing (even if some individual entries failed)"failed": The entire bulk operation failed due to a system error (e.g., invalid upload file, timeout, or server error)
When a bulk operation fails at the job level (sys.status is "failed"), the response includes a top-level error field:
{
"sys": {
"id": "bulkOperationId123",
"type": "BulkOperation",
"bulkType": "EntriesCreate",
"status": "failed",
"space": {
"sys": {
"type": "Link",
"linkType": "Space",
"id": "ncbxgqx5v0xe"
}
},
"environment": {
"sys": {
"type": "Link",
"linkType": "Environment",
"id": "master"
}
},
"createdBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "userId"
}
},
"createdAt": "2025-11-27T13:50:00.000Z",
"updatedAt": "2025-11-27T13:50:05.000Z"
},
"error": {
"sys": {
"type": "Error",
"id": "NotFound"
},
"message": "Upload not found"
}
}
When a bulk operation completes (sys.status is "completed"), check result.items to see which individual entries succeeded and which failed. Each item has:
status:"succeeded"or"failed"entity(on success): minimalsysobject identifying the created/updated/deleted entryerror(on failure):sys.id(error code) andmessage
Individual entry failures typically occur due to validation errors (e.g., missing required fields, invalid field values, or content type mismatches).
Updating existing entries
To update existing entries, include sys.id, sys.version, and fields in your entries array. The sys.version field is required and must match the current version of the entry.
[
{
"sys": {
"id": "existing-entry-id-1",
"version": 5
},
"fields": {
"title": {
"en-US": "Updated Article Title"
},
"body": {
"en-US": "Updated content for the article."
}
}
}
]
The workflow for updates is the same as for creates, but use the update endpoint when triggering the bulk operation:
curl -X POST "https://api.contentful.com/spaces/<space_id>/environments/<environment_id>/bulk_operations/entries/update" \
-H "Authorization: Bearer <cma_token>" \
-H "Content-Type: application/vnd.contentful.management.v1+json" \
-d '{"upload":{"sys":{"type":"Upload","id":"<upload_id>"}}}'
Note: Updates work like PUT requests and will completely overwrite the fields of the entry. Any fields not included in the request will be deleted from the entry.
Deleting entries in bulk
To delete multiple entries at once, prepare a file containing the IDs of the entries to delete:
[
{"sys": {"id": "entry-id-1"}},
{"sys": {"id": "entry-id-2"}},
{"sys": {"id": "entry-id-3"}}
]
Upload the file the same way as for create/update, then trigger the delete operation:
curl -X POST "https://api.contentful.com/spaces/<space_id>/environments/<environment_id>/bulk_operations/entries/delete" \
-H "Authorization: Bearer <cma_token>" \
-H "Content-Type: application/vnd.contentful.management.v1+json" \
-d '{"upload":{"sys":{"type":"Upload","id":"<upload_id>"}}}'
When completed, each successfully deleted entry appears in result.items with status: "succeeded", along with an entity object containing the sys.type ("DeletedEntry" or "DeletedAsset") and sys.id:
{
"status": "succeeded",
"entity": {
"sys": {
"type": "DeletedEntry",
"id": "1XNAo19XTmwnEJiR0QAog0"
}
}
}
Limitations
- Maximum number of entries per request is subject to technical limits (currently 10,000 entries per file)
- Entries must reference valid content types that exist in the space
- File uploads are subject to the same size limits as any file upload (1000MB/1GB for paid plans)
For detailed API reference documentation, see the Bulk entry content operations API reference.