Execute a batch of expense API requests

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.

Body Params
requests
array of objects
required
length between 1 and 50

Sub-requests to dispatch, in order. Sub-requests run sequentially and each commits independently — there is no all-or-nothing behavior across the batch, so a failing sub-request does not roll back or block the others.

requests*
string
length ≤ 100

Optional client-supplied identifier for this sub-request. Echoed back verbatim on the matching entry in the response's responses array so callers can correlate results without relying on array order. Not required — every response entry also carries the sub-request's zero-based index.

string
enum
required

HTTP method to dispatch this sub-request with.

Allowed:
string
required

API path to dispatch to. Must start with the same prefix as the bulk endpoint being called (/v1/admin/ for the admin bulk endpoint, /v1/expense/ for the expense bulk endpoint). The leading /api context prefix is optional and is stripped if present. Percent-encoding, path traversal (..), query strings (?), and nested /bulk paths are rejected. All sub-requests within one batch must resolve to the same underlying endpoint (same HTTP method and the same target action) — see the endpoint description for the scope-lock rule.

params
object

Query/form parameters to send with the sub-request, as key-value pairs. Each value must be a string, number, or boolean, or an array of those — nested objects are rejected. Authentication-bearing parameters (e.g. authenticationToken) are silently stripped; the sub-request always runs as the caller who made the outer bulk call.

body
object

JSON body to send with the sub-request, matching the shape the target endpoint normally expects. Ignored when method is GET. Limited to 1 MB per sub-request.

Responses

Language
Credentials
Bearer
URL
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json