# Batch APIs: outer status vs per-item outcome — source table

Pulled 2026-10-08, 22:40 to about 22:44 CEST (last clock reading 22:43:57), by a research agent working for Vesper. Primary sources only (official documentation pages). Page text was read either from WebFetch output (AWS SQS, Kinesis, DynamoDB, Microsoft Graph came back as near-raw page markdown) or by downloading the page with `curl` and stripping HTML (everything else). Quotes below are copied from that text; they are not paraphrased. Nothing here was tested against a live API: this is what the documentation says, not what the services do.

Note: the sentence "If the action is successful, the service sends back an HTTP 200 response" is generic boilerplate and appears identically on the SQS, DynamoDB and Kinesis pages; only SQS adds prose tying 200 to partial failure.

Three different kinds of "outer status" evidence are kept apart on purpose:

- **STATED** = a prose sentence in the doc says the outer status.
- **EXAMPLE ONLY** = the doc shows `HTTP/1.1 200` in a sample response but no prose sentence ties it to partial failure.
- **NOT STATED** = neither.

## Table

| API | Outer status on partial failure | Where per-item failures live | Explicit warning to check? | URL | Fetched |
|---|---|---|---|---|---|
| Elasticsearch `_bulk` | NOT STATED (the response schema is listed under "Responses 200" on the API page, which is a schema heading, not a sentence about partial failure) | top-level `errors` boolean; `items[]` each with `status` and an `error` object | Partly: defines `errors`, says individual results do not affect each other; no sentence says "check it" | https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk ; versioned text: https://raw.githubusercontent.com/elastic/elasticsearch/8.15/docs/reference/docs/bulk.asciidoc | 2026-10-08 22:40 |
| OpenSearch `_bulk` | NOT STATED as a number; "always returns a complete response, even when some operations fail" | top-level `errors` boolean; `items[]` each with `status`, `error` | YES: "Your application should always check the errors field in the response" | https://docs.opensearch.org/latest/api-reference/document-apis/bulk/ | 2026-10-08 22:40 |
| AWS SQS SendMessageBatch | 200 (STATED: "If the action is successful, the service sends back an HTTP 200 response", plus the 200 warning below; the sample response is `HTTP/1.1 200 OK` with an empty `Failed` list) | `Failed` list (`Id`, `Code`, `Message`, `SenderFault`) beside `Successful` list | YES, and says it in terms of 200 | https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessageBatch.html | 2026-10-08 22:40 |
| AWS DynamoDB BatchWriteItem | 200 (STATED only generically: "If the action is successful, the service sends back an HTTP 200 response"; the unprocessed-items example is `HTTP/1.1 200 OK`) | `UnprocessedItems` map; empty map means nothing left | Yes, as instruction: "Each iteration would check for unprocessed items"; "If DynamoDB returns any unprocessed items, you should retry" | https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html | 2026-10-08 22:40 |
| AWS Kinesis PutRecords | 200 (EXAMPLE ONLY for partial failure: the "partially successful response" sample is `HTTP/1.1 200 OK` with `FailedRecordCount: 2`; the generic 200 sentence is also present) | `FailedRecordCount` plus per-record `ErrorCode` / `ErrorMessage` in `Records[]`, same order as request | No explicit "check this" sentence; the page documents the fields and points to the developer guide "for more information about partially successful responses" | https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html | 2026-10-08 22:40 |
| Firebase Cloud Messaging (Admin SDK `sendEach`, `sendEachForMulticast`) | NOT STATED, and not applicable as one HTTP call: the SDK doc says it "makes a single RPC call for each message" | `BatchResponse.failureCount`, `successCount`, `responses[]` | YES, in effect: "Partial failures or no failures are only indicated by a BatchResponse return value." | https://firebase.google.com/docs/reference/admin/node/firebase-admin.messaging.messaging.md ; https://firebase.google.com/docs/reference/admin/node/firebase-admin.messaging.batchresponse ; https://firebase.google.com/docs/cloud-messaging/send/admin-sdk | 2026-10-08 22:41 |
| Google APIs batch (Gmail guide read) | EXAMPLE ONLY: sample batch response starts `HTTP/1.1 200`, with parts `200 OK`, `200 OK`, `304 Not Modified`; the sample has no failed part; no prose states the outer status | one complete HTTP response per `multipart/mixed` part, each with its own status line | NOT PRESENT (no warning found) | https://developers.google.com/workspace/gmail/api/guides/batch | 2026-10-08 22:40 |
| Microsoft Graph `$batch` | 200 if the batch is parseable, 400 if malformed (STATED) | `responses[]`, each with `id` and `status` | YES, explicit | https://learn.microsoft.com/en-us/graph/json-batching | 2026-10-08 22:40 (WebFetch) and 22:41 (curl) |
| Salesforce REST Composite | 200 (STATED, for both allOrNone settings) | `compositeResponse` entries per subrequest (field name `httpStatusCode` NOT confirmed on a page I could read, see gaps) | Not as a warning; the doc states the outer 200 plainly | https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/requests_composite.htm | 2026-10-08 22:41 |
| Salesforce sObject Collections (create) | 200 if the request is well formed (STATED) | per-item `success` flag and `errors` array | Implicit only | https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_sobjects_collections_create.htm | 2026-10-08 22:41 |
| Salesforce Bulk API / Bulk API 2.0 | UNVERIFIED (not read; it is job-based, a different shape) | UNVERIFIED | UNVERIFIED | none | not fetched |
| HTTP 207 Multi-Status, RFC 4918 | 207 (the standard's definition) | `multistatus` XML root with per-resource `response` elements | The definition says status is per-resource; no client warning | https://www.rfc-editor.org/rfc/rfc4918.txt (sections 11.1 and 13) | 2026-10-08 22:40 |
| RingCentral batch | 207 on any multipart batch response (STATED) | status code in each part | Not as a warning | https://developers.ringcentral.com/guide/basics/batch-requests | 2026-10-08, between 22:41 and 22:44 (not timed individually) |
| Microsoft Exchange 2007 WebDAV batch methods (legacy) | "usually" 207 (STATED) | per-resource status inside the 207 body | Not as a warning | https://learn.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2007/aa579405(v=exchg.80) | 2026-10-08, between 22:41 and 22:44 (not timed individually) |
| Stripe | UNVERIFIED. No claim that Stripe has no batch endpoint is made here; no page was read. | | | | not fetched |

## Evidence sentences

**Elasticsearch.** "If `true`, one or more of the operations in the bulk request did not complete successfully." (8.15 asciidoc, the `errors` field; the live page says the same: "If true, one or more of the operations in the bulk request did not complete successfully.") And: "The success or failure of an individual operation does not affect other operations in the request." The 8.15 text for its failure example says: "Because these operations cannot complete successfully, the API returns a response with an `errors` flag of `true`." No outer HTTP status is stated for this case in either version. The 8.15 text is a versioned branch on GitHub, not the current page; the live page was matched only on the `errors` description.

**OpenSearch.** "Pay particular attention to the top-level errors boolean. If true, one or more operations failed, and you can examine individual items for details. The Bulk API always returns a complete response, even when some operations fail due to shard failures or other errors." and "Your application should always check the errors field in the response and handle failed operations appropriately."

**SQS.** "The result of sending each message is reported individually in the response. Because the batch request can result in a combination of successful and unsuccessful actions, you should check for batch errors even when the call returns an HTTP status code of `200`." This is the strongest single sentence for the thesis in the set.

**DynamoDB.** "If any requested operations fail because the table's provisioned throughput is exceeded or an internal processing failure occurs, the failed operations are returned in the `UnprocessedItems` response parameter." Two different failure paths exist on the same page, and the status differs. Whole-batch rejection ("DynamoDB rejects the entire batch write operation" for a missing table, key mismatch, more than 25 requests, an item over 400 KB, and so on) comes back as an error; of those causes, the error list on the page covers a missing table as `ResourceNotFoundException` with "HTTP Status Code: 400". Throttling of the whole call returns "a `ProvisionedThroughputExceededException` or a `ThrottlingException`" (listed as HTTP 400). Only the partial case rides on 200. The sample response with a leftover item is `HTTP/1.1 200 OK` with `UnprocessedItems` holding one `PutRequest`. Note that `ValidationException` is named in the page text but its HTTP code is in the common-errors page, which I did not read.

**Kinesis.** "The response `Records` array includes both successfully and unsuccessfully processed records. Kinesis Data Streams attempts to process all records in each `PutRecords` request. A single record failure does not stop the processing of subsequent records." Sample for partial failure: `HTTP/1.1 200 OK` ... `"FailedRecordCount": 2`. Field definition: "The number of unsuccessfully processed records in a `PutRecords` request." with "Valid Range: Minimum value of 1" (the field is declared as a number; whether it is omitted on full success is not stated, but the complete-success sample shows `"FailedRecordCount": 0`).

**FCM.** "This method makes a single RPC call for each message in the given array." and "An error from this method or a BatchResponse with all failures indicates a total failure, meaning that none of the messages in the list could be sent. Partial failures or no failures are only indicated by a BatchResponse return value." `failureCount` is documented as "The number of messages that resulted in errors when sending." The page does not state any HTTP status for batches. The word `sendAll` does not appear on the reference page I fetched, and `sendEach` is described there; I did not read a deprecation notice, so I do not say what happened to `sendAll` beyond "not on this page".

**Google batch (Gmail guide).** "Like the parts in the request, each response part contains a complete HTTP response, including a status code, headers, and body." The sample shows outer `HTTP/1.1 200` and an inner `HTTP/1.1 304 Not Modified`. The doc gives a limit: "You're limited to 100 calls in a single batch request." The page does not say what the outer status is when inner parts fail, and it contains no warning to inspect each part. Which of the many per-API batch guides is the "Google APIs" one is a choice; this is the Gmail one, and the others were not read.

**Microsoft Graph.** "The status code on a batch response is typically `200` or `4xx`. If the batch request itself is malformed, the status code is `400`. If the batch request is parseable, the status code is `200`. A `200` status code on the batch response headers doesn't indicate that the individual requests inside the batch succeeded. This is why each individual response in the **responses** property has a status code." The page's own example has outer `HTTP/1.1 200 OK` with inner statuses 200, 403, 403, 405, 200. Page metadata shows `updated_at: 2025-02-26`.

**Salesforce Composite.** "If the value is `true`, the entire composite request is rolled back. The top-level request returns HTTP 200 and includes responses for each subrequest. If the value is `false`, the remaining subrequests that don't depend on the failed subrequest are executed. Dependent subrequests aren't executed. In either case, the top-level request returns HTTP 200 and includes responses for each subrequest." (Quote lightly normalised for HTML typography only.) For sObject Collections: "If the request isn't well formed, the API returns a 400 Bad Request HTTP Status. ... If the request is well formed, the API returns a 200 OK HTTP Status. If an item was processed successfully, the success flag shows for that item. Error information is returned in the errors array."

**RFC 4918.** Section 11.1: "The 207 (Multi-Status) status code provides status for multiple independent operations (see Section 13 for more information)." Section 13: "A Multi-Status response conveys information about multiple resources in situations where multiple status codes might be appropriate. The default Multi-Status response body is a text/xml or application/xml HTTP entity with a 'multistatus' root element." (Text read from the plain-text RFC by curl, not from a summary.)

**RingCentral (a 207 user).** "The HTTP status code 207 Multi-Status is returned in every multipart response object and indicates a bulk request." and "In bulk DELETE operations (if all resources are deleted successfully) the server returns the 204 No content instead of multi status ... In case of at least one failure the server returns the 207 Multi-Status." So even this 207 user does not use the status as a pass/fail signal: 207 is the normal "batch was read" answer, and a 204 is the all-clear. In this one case the status does carry some information (204 vs 207 on DELETE), which is the exception inside the exception.

**Exchange 2007 WebDAV (legacy 207 user).** "A response to a batch request is usually in the form of a 207 (Multi-Status) response."

## What this supports and what it does not

Supports (documentation only): for the AWS batch calls read here (SQS, DynamoDB, Kinesis), Microsoft Graph and Salesforce Composite, the docs say or show a 200 on partial failure with the real outcome in a separate field. Explicit client warnings exist for SQS, Graph and OpenSearch, and for FCM in different words; DynamoDB phrases it as a retry loop instruction. Elasticsearch, Google/Gmail and Kinesis give the field but no sentence of the form "do not trust the status".

Does not support: the claim that "clients misreport failures". That needs client-library or incident evidence. This file contains none; do not cite it for that.

Doc-phrasing lean to flag: a sampling of well-known APIs I chose because I expected them to fit; the list is not a random draw, and APIs that fail whole-batch on any item (for example, atomic batches) were not looked for. Every assumption leans toward the thesis.

## Gaps

- Stripe, Salesforce Bulk API 2.0: not fetched, UNVERIFIED.
- Salesforce: the per-subrequest field name `httpStatusCode` was not found on any page I could download (the "Composite Subrequest Result" page returned 404 under the URL I guessed). The "where failures live" cell for Composite is therefore from the doc's general statement ("includes responses for each subrequest"), not a named field.
- Elasticsearch: no HTTP status for partial failure stated in either version read; I did not run a cluster.
- Gmail/Google: the sample contains no failing part; whether the global batch endpoint is deprecated was not checked (the page I read has no deprecation text).
- DynamoDB `ValidationException` HTTP code: lives in the common-errors page, not read.
- FCM: no statement about the transport underneath beyond "a single RPC call for each message".
- Pages can change; all fetch times are 2026-10-08 CEST. WebFetch results for AWS and Graph were summarised by a small model on the way in but came back as raw page text; the Graph quote was re-checked against a curl download.
