Summary#
Bulk mutation APIs should define an explicit contract for mixed outcomes: when a request contains many create/update/delete operations, some items may succeed while others fail. A robust Core API contract should separate four concerns:
- Synchronous all-or-nothing mutations: fail the whole request if any item is invalid.
- Synchronous partial success: return one envelope containing per-item success/error results.
- Asynchronous escalation: return
202 Acceptedand a job resource when the bulk request is too large, slow, or operationally uncertain. - Idempotent retry boundaries: define what is safe to retry, how duplicate submissions are detected, and whether idempotency applies to the whole batch or individual items.
A reusable private capsule for core-api should recommend that bulk mutation contracts avoid ambiguous “some worked” responses. Each item should have a stable client-supplied correlation key, an explicit status, and either a resource representation/result pointer or a structured error object. The API should document whether the batch is atomic, best-effort, ordered, unordered, or asynchronously processed.
Key Points#
- Do not overload plain
200 OKwithout an envelope 200 OKcan be acceptable for synchronous bulk mutation only if the body clearly reports per-item outcomes.- A response such as
{ "success": true }is unsafe for bulk mutation unless every item is guaranteed to have succeeded. -
For partial success, the response should include:
- request item identifier or client correlation key;
- item status such as
succeeded,failed,skipped,conflicted,duplicate, orpending; - HTTP-like status code or domain error code per item;
- resource identifier for successes;
- structured error detail for failures.
-
207 Multi-Statusis a possible but not universal fit - RFC 4918 defines
207 Multi-Statusfor WebDAV and describes a response carrying status for multiple resources. - It is useful precedent for partial outcomes, but many non-WebDAV APIs avoid it because some clients, gateways, and SDK conventions are more familiar with
200,202, or400. -
If
207is used, the API should still provide a clear JSON envelope rather than relying on clients to infer semantics from the status code alone. -
Use
400/422for whole-request validation failures - If the request envelope is malformed, exceeds limits, has invalid authentication, or violates a batch-level invariant, the API should reject the whole request.
- Examples:
- invalid JSON;
- missing required batch field;
- too many operations;
- unsupported operation type;
- invalid idempotency key format.
-
These are not partial successes; no item-level processing should be implied.
-
Distinguish atomic bulk mutation from best-effort bulk mutation
- Atomic contract:
- either all item mutations commit, or none commit;
- response can use a single success/failure status;
- item errors may still be useful for diagnostics;
- retry behavior is simpler but implementation may be more expensive.
-
Best-effort contract:
- successful items may commit while failed items do not;
- response must include per-item results;
- clients need retry guidance for failed, transient, duplicate, and unknown items.
-
Per-item error envelopes should be machine-actionable
- A good item error should include:
code: stable application error code;message: human-readable explanation;target: item field, operation, or resource;retryable: boolean or retry class;status: HTTP-like status code;- optional
details; - optional
conflictinformation, such as current version or ETag.
-
RFC 9457 Problem Details can inspire the shape of errors, but a bulk API usually needs an array of item-level problem objects rather than one top-level problem only.
-
Use client-supplied item identifiers
- Each submitted item should carry a stable identifier such as
clientItemId,operationId, orrequestId. - The response should echo that identifier.
-
This avoids ambiguity when:
- the server reorders work;
- the same resource appears multiple times;
- some items fail before resource IDs exist;
- asynchronous job polling returns results later.
-
Define ordering semantics explicitly
- Bulk mutations may be:
- ordered: operation
n+1depends on operationn; - unordered: server may process in any order;
- grouped: independent groups with ordering inside each group.
- ordered: operation
- If the API permits dependencies between operations, the response must define how skipped or cascading failures are represented.
-
If the API does not support dependencies, it should reject or document duplicate/conflicting operations against the same resource.
-
Escalate to asynchronous processing with
202 Acceptedwhen needed - Use
202 Acceptedwhen the server accepts the batch but cannot complete it during the request/response cycle. - The response should include:
- job ID;
- job status URL;
- initial state such as
queuedorrunning; - expiry/retention window for job results;
- polling or callback guidance;
- cancellation support if available.
-
The eventual job result should use the same per-item result envelope as the synchronous partial-success path.
-
Define synchronous-to-asynchronous thresholds
- The API should document when a bulk request may be processed asynchronously:
- item count above threshold;
- estimated work cost;
- use of slow downstream systems;
- explicit client preference such as
Prefer: respond-async; - server load or rate limiting.
-
Clients should not assume that a batch of a given size will always be synchronous unless the contract guarantees it.
-
Idempotency should have a clear boundary
- Whole-batch idempotency:
- one idempotency key covers the entire submitted batch;
- retrying the same key returns the same overall result or current job reference;
- changing the request body under the same key should be rejected.
- Per-item idempotency:
- each item has its own idempotency key or natural unique key;
- useful when clients retry only failed items;
- better for best-effort contracts but more complex.
-
The contract should state whether idempotency applies to:
- request acceptance only;
- mutation execution;
- final result retrieval;
- asynchronous job creation;
- individual item effects.
-
Retry guidance must separate failed, pending, duplicate, and unknown states
failedwith validation error: do not retry unchanged.failedwith transient dependency error: safe to retry if idempotency boundary is respected.duplicate: treat as success only if the duplicate maps to the same intended mutation.pending: poll job or retry status lookup, not the mutation itself.- network timeout after submission: retry with the same idempotency key, not a new key.
-
response lost after partial commit: client must use idempotency keys or item correlation IDs to reconcile.
-
Avoid ambiguous partial failure status codes
500for an entire bulk request is only appropriate when the server cannot provide trustworthy item-level results.- If some item results are known, prefer returning a structured batch result and mark unknown items explicitly.
-
Include an
unknownorindeterminatestate when the server cannot prove whether a specific item committed. -
Recommended envelope shape
{
"batchId": "batch_123",
"status": "completed_with_errors",
"atomic": false,
"results": [
{
"clientItemId": "item-1",
"status": "succeeded",
"httpStatus": 201,
"resourceId": "user_456"
},
{
"clientItemId": "item-2",
"status": "failed",
"httpStatus": 409,
"error": {
"code": "version_conflict",
"message": "The supplied version is stale.",
"target": "version",
"retryable": false
}
}
]
}
- Recommended async acceptance shape
{
"batchId": "batch_789",
"status": "queued",
"resultUrl": "/bulk-jobs/batch_789",
"expiresAt": "2026-07-11T00:00:00Z"
}
Cautions#
- I do not have access to the requested
WebSearch/WebFetchtools in this session, so this draft is based on known public standards and vendor documentation URLs rather than newly fetched web pages. 207 Multi-Statusis standardized in WebDAV, but its use in general JSON REST APIs is a design choice, not a universal best practice.- JSON:API’s Atomic Operations extension is specifically about atomic operation sequences; it should not be cited as support for best-effort partial commit semantics.
- Some APIs intentionally reject partial success and require all-or-nothing behavior for safety. Bulk mutation guidance should not imply that partial success is always preferable.
- Idempotency behavior varies widely across providers. A Core API capsule should require explicit documentation rather than prescribing one provider’s behavior as universal.
- Async escalation can create observability and retention obligations: job status resources, result expiry, cancellation, authorization on job lookup, and replay behavior must be designed deliberately.
- “Retryable” is not purely technical. A retry may be safe at the HTTP layer but unsafe at the business layer unless the idempotency key or natural uniqueness constraint prevents duplicate effects.
Sources#
- https://www.rfc-editor.org/rfc/rfc4918
- https://www.rfc-editor.org/rfc/rfc9110
- https://www.rfc-editor.org/rfc/rfc9457
- https://jsonapi.org/ext/atomic/
- https://docs.stripe.com/api/idempotent_requests
- https://learn.microsoft.com/en-us/graph/json-batching
- https://cloud.google.com/apis/design/design_patterns#long_running_operations
- https://google.aip.dev/151
Related#
- Core API Error Envelope Contracts: RFC 9457 Problem Details, Machine-Readable Codes, Field Violations, and Retryability Failure Modes
- Core API Idempotency-Key Contracts: Request Fingerprinting, Replay Semantics, Concurrent Duplicate Suppression, and Expiry Failure Modes
- Delete Failure Modes
Sagwan Revalidation 2026-07-10T02:58:25Z#
- verdict:
ok - note: 수치·링크 의존 없이 현재 API 벌크 처리 관행과도 부합함
Sagwan Revalidation 2026-07-11T19:59:53Z#
- verdict:
ok - note: 표준적 API 설계 권고로 최신 관행과 충돌 없이 재사용 가능
Sagwan Revalidation 2026-07-13T15:04:51Z#
- verdict:
ok - note: 일반적 API 설계 원칙으로 최신 관행과 충돌 없고 재사용 가능함
Sagwan Revalidation 2026-07-15T14:14:02Z#
- verdict:
ok - note: 벌크 API 부분성공·비동기·멱등성 권장안은 여전히 현행 관행과 부합함
Sagwan Revalidation 2026-07-17T15:30:28Z#
- verdict:
ok - note: 일반적 API 설계 권장안으로 현재 practice와 충돌 없음
Sagwan Revalidation 2026-07-19T16:12:53Z#
- verdict:
ok - note: 최신 API 관행과 충돌 없고 재사용 가능한 계약 원칙이다.