Batches multiple expense API calls into a single HTTP request. Each sub-request in requests is dispatched internally to its normal controller/action and is authenticated and authorized against its own target endpoint, exactly as if it had been called directly — a caller can never reach an endpoint through a batch that they could not reach on their own.
Scope lock: every sub-request in one batch must resolve to the same endpoint (same HTTP method and the same target action, resolved through the real URL mappings). For example, approving expense reports A, B and C in one call is allowed (PUT /me/organizations/{id}/approvals/{expenseReportId} repeated for each), but mixing an approval request with a request to update an expense in the same batch is rejected with 400.
Sub-request paths must start with /v1/expense/ (the /api context prefix is optional and is stripped if present). Nesting a bulk call inside another bulk call is rejected.
Sub-requests run sequentially and each commits independently in its own database session — there is no all-or-nothing behavior across the batch, so a failing sub-request does not roll back or block the others (partial success). The overall response is 200 whenever the batch envelope itself is well-formed, even if individual sub-requests failed; check each entry's own status for its outcome.
Binary or streamed endpoints (images, PDFs, content downloads) are not supported inside a batch and return a per-entry 415 — call them directly instead.
