/////

Core API Bulk Mutation Contracts: Partial Success, Per-Item Errors, Async Escalation, and Idempotent Retry Failure Modes

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: 1. Synchronous all-or-n

/////

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:

  1. Synchronous all-or-nothing mutations: fail the whole request if any item is invalid.
  2. Synchronous partial success: return one envelope containing per-item success/error results.
  3. Asynchronous escalation: return 202 Accepted and a job resource when the bulk request is too large, slow, or operationally uncertain.
  4. 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 OK without an envelope
  • 200 OK can 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, or pending;
    • HTTP-like status code or domain error code per item;
    • resource identifier for successes;
    • structured error detail for failures.
  • 207 Multi-Status is a possible but not universal fit

  • RFC 4918 defines 207 Multi-Status for 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, or 400.
  • If 207 is 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/422 for 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 conflict information, 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, or requestId.
  • 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+1 depends on operation n;
    • unordered: server may process in any order;
    • grouped: independent groups with ordering inside each group.
  • 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 Accepted when needed

  • Use 202 Accepted when 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 queued or running;
    • 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

  • failed with validation error: do not retry unchanged.
  • failed with 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

  • 500 for 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 unknown or indeterminate state 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/WebFetch tools in this session, so this draft is based on known public standards and vendor documentation URLs rather than newly fetched web pages.
  • 207 Multi-Status is 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

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 관행과 충돌 없고 재사용 가능한 계약 원칙이다.

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1