Oracle Fusion REST API Bulk Operations: The Parts Payload Batch Pattern
Looping POST /workers or PATCH /invoices/{id} one record at a time works, but it’s slow, it burns through rate limits fast, and each call is a separate network round trip. Oracle Fusion’s REST layer has a generic answer to this that most integration guides either skip entirely or only describe from inside Oracle Integration Cloud’s mapper UI: a batch media type that lets you send a mixed list of create, update, delete, and even read operations in a single HTTP request. This post covers it the way a direct REST client — not OIC — actually calls it, with real payload shapes.
All examples use an anonymized pod (acme.fa.us2.oraclecloud.com) and placeholder identifiers — swap in your own.
The batch media type
A batch request is a normal POST, but instead of the usual application/vnd.oracle.adf.resourceitem+json content type, you send application/vnd.oracle.adf.batch+json against the resources root:
POST /hcmRestApi/resources/latest
Content-Type: application/vnd.oracle.adf.batch+json
The body is a parts array. Each part is one independent operation with its own id, path, operation, and (for writes) payload:
{
"parts": [
{
"id": "part1",
"path": "/workers/300000012345678",
"operation": "get"
},
{
"id": "part2",
"path": "/workers/300000012345678",
"operation": "update",
"payload": {
"emails": [
{ "EmailType": "W1", "EmailAddress": "[email protected]" }
]
}
}
]
}
id— any string you choose; it’s how you match each part’s result back to its request in the response.path— the resource path relative to the resources root you posted to (not the full URL, and no leadinghcmRestApi/resources/latestrepeated).operation—get,create(orpost),update(orpatch), ordelete.payload— required forcreate/update, omitted forget/delete.
Mixing operation types in one batch — a get to check current state alongside a update that depends on it — is the main thing this pattern buys you over N separate calls.
Bulk create: multiple new records in one request
create parts each carry their own payload, built the same way a standalone POST body would be. Using the real Workers endpoint child structure covered in the workers guide:
{
"parts": [
{
"id": "hire1",
"path": "/workers",
"operation": "create",
"payload": {
"names": [
{ "LegislationCode": "GLOBAL", "FirstName": "Test", "LastName": "EmployeeOne" }
],
"workRelationships": [
{
"LegalEmployerName": "Acme Corp",
"WorkerType": "E",
"PrimaryFlag": true,
"assignments": [
{ "ActionCode": "HIRE", "BusinessUnitName": "Acme US BU", "PrimaryFlag": true }
]
}
]
}
},
{
"id": "hire2",
"path": "/workers",
"operation": "create",
"payload": {
"names": [
{ "LegislationCode": "GLOBAL", "FirstName": "Test", "LastName": "EmployeeTwo" }
],
"workRelationships": [
{
"LegalEmployerName": "Acme Corp",
"WorkerType": "E",
"PrimaryFlag": true,
"assignments": [
{ "ActionCode": "HIRE", "BusinessUnitName": "Acme US BU", "PrimaryFlag": true }
]
}
]
}
}
]
}
Every rule that applies to a standalone POST /workers — required child resources, Effective-Of for the hire date, WorkerType values — still applies per-part; batching doesn’t relax field-level validation, it just avoids the extra round trips.
Bulk update and delete
update parts send only the changed fields, same as a standalone PATCH. delete parts need no payload at all:
{
"parts": [
{
"id": "close1",
"path": "/invoices/300000098765432",
"operation": "update",
"payload": { "PaymentTerms": "Immediate" }
},
{
"id": "remove1",
"path": "/invoices/300000098765433",
"operation": "delete"
}
]
}
For resources with ETag/If-Match protection, the same If-Match requirement applies to update and delete parts — you can’t batch around optimistic locking, you just move the header logic into building each part.
How partial failure works
This is the detail most third-party writeups skip, and it’s the one that actually determines whether batching is safe for your use case. By default, Oracle processes each part independently — one part failing doesn’t roll back the others, and the response tells you which parts succeeded and which didn’t, part-by-part, matched by the id you assigned. If you need all-or-nothing semantics instead, that’s a request-level setting, not something you get for free just by using the batch media type — check the current behavior against a real response before relying on it in production, since it’s easy to assume atomicity that isn’t actually there.
Practical implication: always check every part’s individual result, never just the outer HTTP status code. A batch request can return 200 OK at the top level while three of ten parts inside it failed — the same trap as ignoring o:errorDetails on a 400 response, just multiplied across a whole batch.
Practical batch size
Oracle’s own guidance is to keep batches modest — around 50 operations per request is the commonly cited practical ceiling, not a hard-documented maximum baked into every resource. Treat it the same way you’d treat the 500-row page-size cap: don’t assume you can push an arbitrarily large batch through and get a clean response back. For a true bulk-load scenario — thousands of rows, not dozens — HDL or FBDI is still the right tool; the batch media type is for combining a handful of related REST operations into one round trip, not for replacing bulk data-load pipelines.
Not the same thing as a resource’s own “Bulk” action
A few Supply Chain resources (buyerPlanningSupplies, collaborationCustomerDemands, and similar) additionally expose their own dedicated bulk-style POST action that accepts an array of records directly in a single resource-specific payload shape — a different mechanism from the generic parts batch media type described above, scoped to that one resource. If you’re integrating with one of those specific SCM resources, check its own REST API reference for whether it has this dedicated action before reaching for the generic batch pattern; the two aren’t interchangeable and use different payload shapes.
Common mistakes
- Repeating the resources-root path inside
path.pathis relative to what you posted to —/workers, not/hcmRestApi/resources/latest/workers. - Assuming one part’s failure fails the whole batch. Check every part’s result individually; a
200at the top doesn’t mean every part succeeded. - Skipping
Effective-Of/If-Matchon parts that need them. Every header requirement a standalone call has still applies inside a batch part. - Using this for a genuine bulk load. Hundreds or thousands of rows belong in HDL/FBDI, not a hand-built
partsarray. - Forgetting the
idfield. Without a uniqueidper part, you can’t reliably match results back to requests once the response comes back.
Checking a resource’s real fields before you batch
The batch mechanism is generic, but the payload inside each create/update part still has to match that specific resource’s real schema — the same q-fields, finders, and child resources documented per endpoint. OPAL bundles the Oracle Fusion Cloud OpenAPI specification offline, so you can look up an endpoint’s exact fields and required child resources in the endpoint catalog before building a batch part, without burning API calls on trial and error against a live pod.
This post is part of our complete Oracle Fusion API guide — base URLs, authentication, q filters, finders, and common errors in one place.
Explore Oracle Fusion APIs offline
OPAL bundles 59,000+ Oracle Fusion REST endpoints, fully searchable offline, with a visual Q Builder and Finder Builder that only offer fields the endpoint actually accepts — so your filter can't 400.
Free, no account required. Pro adds live requests and multi-step Flows.