I’ll provide a complete solution covering API payload size limits, batch processing optimization, and error handling for large requests.
Understanding API Payload Size Limits:
The 413 Payload Too Large error occurs because Adobe Experience Cloud enforces a 1MB limit on synchronous API requests at the gateway level. This isn’t a record count limit but a total payload size restriction. Your 200-case limit suggests each case object is approximately 5KB, which is typical when including all fields from GET responses.
Batch Processing Optimization:
Step 1: Minimize Payload Size
First, reduce your payload by sending only the fields being updated:
PUT /api/service-cases/bulk-update
{
"updates": [
{"id": 1001, "status": "closed"},
{"id": 1002, "status": "closed", "assigned_to": 456},
{"id": 1003, "status": "resolved"}
]
}
This minimal format reduces each case object from ~5KB to ~50-100 bytes, allowing 800-1000 cases per request within the 1MB limit.
Step 2: Use Asynchronous Bulk Operations API
For 1,000+ cases, switch to the async bulk operations endpoint designed for large-scale updates:
POST /api/v2/service-cases/bulk-operations
Content-Type: application/json
{
"operation": "update",
"idempotency_key": "weekly-closure-2025-09-22",
"cases": [
{"id": 1001, "status": "closed"},
{"id": 1002, "status": "closed"},
// ... up to 5000 cases
]
}
Response:
{
"job_id": "job_abc123",
"status": "queued",
"total_records": 1000
}
The async API has higher limits (5,000 records or 10MB per job) and processes in the background.
Step 3: Poll Job Status
Monitor the job completion:
GET /api/v2/service-cases/bulk-operations/job_abc123
Response:
{
"job_id": "job_abc123",
"status": "completed",
"processed": 1000,
"succeeded": 998,
"failed": 2,
"results_url": "/api/v2/bulk-operations/job_abc123/results"
}
Error Handling for Large Requests:
Implement Retry Logic with Exponential Backoff:
def submit_bulk_job(cases, max_retries=3):
for attempt in range(max_retries):
try:
response = POST bulk_operations_endpoint
if response.status == 202: # Accepted
return response.json()['job_id']
except PayloadTooLarge:
# Split into smaller batches
batch_size = len(cases) // 2
job_ids = []
for batch in chunk(cases, batch_size):
job_ids.append(submit_bulk_job(batch))
return job_ids
except TransientError:
sleep(2 ** attempt)
raise BulkUpdateFailed()
Handle Partial Failures:
Retrieve and process failed records:
GET /api/v2/bulk-operations/job_abc123/results
Response:
{
"succeeded": [
{"id": 1001, "status": "closed"},
// 998 successful updates
],
"failed": [
{
"id": 1005,
"error": "Case locked by another user",
"error_code": "CASE_LOCKED"
},
{
"id": 1023,
"error": "Invalid status transition",
"error_code": "INVALID_TRANSITION"
}
]
}
Retry failed cases after resolving the errors (unlock cases, fix invalid transitions).
Optimized Batch Processing Strategy:
- Split Large Datasets: For 1,000+ cases, use 500-1000 per job to balance throughput and error handling
- Parallel Job Submission: Submit multiple jobs concurrently (max 5 active jobs per account)
- Idempotency Keys: Use unique keys per batch to prevent duplicate processing if jobs are retried
- Compression: Enable gzip compression on requests to reduce network transfer time
Complete Implementation:
def bulk_update_cases(cases, batch_size=800):
job_ids = []
# Split into optimal batches
for i, batch in enumerate(chunk(cases, batch_size)):
# Minimize payload - only updated fields
minimal_batch = [
{"id": c["id"], "status": c["status"]}
for c in batch
]
# Submit async job with idempotency
job = {
"operation": "update",
"idempotency_key": f"batch_{i}_{date.today()}",
"cases": minimal_batch
}
response = POST(
"/api/v2/service-cases/bulk-operations",
json=job,
headers={"Content-Encoding": "gzip"}
)
job_ids.append(response.json()["job_id"])
# Monitor all jobs
return monitor_jobs(job_ids)
def monitor_jobs(job_ids):
results = {"succeeded": 0, "failed": 0}
while job_ids:
for job_id in job_ids[:]:
status = GET(f"/api/v2/bulk-operations/{job_id}")
if status["status"] == "completed":
results["succeeded"] += status["succeeded"]
results["failed"] += status["failed"]
# Handle failures
if status["failed"] > 0:
retry_failed_cases(job_id)
job_ids.remove(job_id)
sleep(5) # Poll every 5 seconds
return results
Best Practices:
- Monitor payload sizes before submission to avoid 413 errors
- Use async API for any operation affecting 200+ records
- Implement idempotency to safely retry failed jobs
- Handle partial failures by retrieving and reprocessing failed records
- Set up monitoring for job completion times and failure rates
- Schedule large updates during off-peak hours for better performance
With this optimized approach, your 1,000+ weekly case updates will process reliably in 5-10 minutes with proper error handling and recovery.
This draft is based on general Adobe Experience Cloud knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.