← Back to blog

Oracle Fusion REST API Framework Versions Explained (v1–v8)

By Mostafa Mansour 7 min read Oracle Fusion CloudREST APIREST-Framework-VersionReference

Half a dozen posts on this site mention the REST-Framework-Version header in passing — it fixes a q syntax error here, it’s required for a terminate action there, it changes how expand paginates somewhere else. What’s missing is the thing that ties all of that together: what each version actually changes, in one place. This is that reference.

The short version

Oracle Fusion’s REST layer runs on an internal ADF REST framework with eight versions (1 through 8). Every tenant defaults to version 1 unless a client explicitly asks for something newer via the REST-Framework-Version HTTP header. The versions are cumulative and backward-incompatible — asking for v4 doesn’t just add v4’s features, it also carries every breaking change from v2 and v3, so a client written against the default silently breaks if you bump the header without re-checking your payload assumptions.

Finding your resource’s actual default and allowed versions

Don’t guess — every resource tells you. GET the resource’s context root and look at defaultFrameworkVersion and allowedFrameworkVersions under adf:extension:

GET /hcmRestApi/resources/latest
{
  "items": [
    {
      "version": "11.13.18.05",
      "isLatest": true,
      "adf:extension": {
        "defaultFrameworkVersion": "3",
        "allowedFrameworkVersions": ["1", "2", "3", "4"]
      }
    }
  ]
}

A resource whose defaultFrameworkVersion is already "3" behaves like version 3 with no header at all — sending an older header can actually downgrade the response shape. This is worth checking before you copy a REST-Framework-Version value from a tutorial written against a different resource.

What each version changes

VersionWhat changes
1 (default)Base framework. Uses query-by-example resource query syntax for q — not compatible with later versions.
2Introduces the expanded query expression syntax (RowMatch: and/or keywords instead of semicolons) for the q parameter. Backward-incompatible with v1’s q syntax — see the q parameter guide.
3Nested child resources returned via expand come back as a collection resource (items, count, hasMore, links) instead of a bare array. This is what makes expanded-child pagination possible — see the pagination guide.
4Error response payloads gain structure: o:errorCode, o:errorPath, and o:errorDetails instead of a plain string message. This is the version several action endpoints (like terminate on a work relationship) expect — see the workers endpoint post and the 400 Bad Request guide.
5Custom-method responses return values in their real data type instead of stringified. Some dependent list-of-values (LOV) resources move from a sub-resource (/emps/{id}/lov/CitizenshipLegislationCodeLOV) to a root resource (/hcmCountriesLov), filterable by a finder.
6Introduces a @context field on each item, consolidating key/headers/links/warnings that were previously scattered (links existed before v6 too, just not grouped).
7Hides row-level LOV sub-resource links from resource metadata and data; only root-level LOV resources are shown. Matters if your client was reading LOV URLs off individual rows.
8ClobDomain fields return as plain strings instead of base64. Multi-select Fixed Choice List (FCL) fields return as an array instead of a comma-separated string. Identifier values with special characters get URL-encoded automatically in resource URLs.

Setting the header

REST-Framework-Version: 4

No default is assumed to mean “latest” — if the header is absent and the resource has no explicit defaultFrameworkVersion set, you get version 1. Oracle’s own guidance is to use the latest version your client supports, since older versions can eventually be deprecated; in practice, most integrations settle on whatever version their q syntax and error-handling code was written against, and stay there deliberately (see “why not just always use v8” below).

Version 1/2 vs. version 3, same request

Requesting grades with an expanded steps child looks structurally different depending on the version. Version 1 or 2:

GET /hcmRestApi/resources/latest/grades?fields=GradeName,GradeCode;steps:GradeStepName&onlyData=true
REST-Framework-Version: 2
{
  "items": [
    {
      "GradeName": "VEN.1.East",
      "GradeCode": "GRDCD_1838",
      "steps": [
        { "GradeStepName": "Step 1" },
        { "GradeStepName": "Step 2" }
      ]
    }
  ]
}

Version 3 — steps becomes a collection resource, not a bare array:

GET /hcmRestApi/resources/latest/grades?fields=GradeName,GradeCode;steps:GradeStepName&onlyData=true
REST-Framework-Version: 3
{
  "items": [
    {
      "GradeName": "VEN.1.East",
      "GradeCode": "GRDCD_1838",
      "steps": {
        "items": [
          { "GradeStepName": "Step 1" },
          { "GradeStepName": "Step 2" }
        ],
        "count": 2,
        "hasMore": false,
        "limit": 25,
        "offset": 0
      }
    }
  ]
}

Code written to expect steps as an array will break the moment the header changes to 3 — steps.length becomes steps.items.length. This exact shape change is why the pagination guide’s expand section calls out checking hasMore on the child, not just the parent.

Version 4’s structured errors, in practice

Pre-v4, a failed request just returns an error string. From v4 on, you get a real error object you can branch on programmatically:

POST /hcmRestApi/resources/latest/emps/{empsUniqID}
REST-Framework-Version: 4
Accept: application/vnd.oracle.adf.resourceitem+json,application/vnd.oracle.adf.error+json
{
  "MiddleName": "John",
  "TerminationDate": "2026-08-01"
}
{
  "title": "Bad Request",
  "status": "400",
  "o:errorDetails": [
    {
      "detail": "TerminationDate: Attribute TerminationDate in view object EmployeeVO cannot be set.",
      "o:errorCode": "27008",
      "o:errorPath": "/TerminationDate"
    }
  ]
}

o:errorPath pointing at the exact attribute is the detail that makes v4+ worth the migration for any integration doing real error handling instead of just logging the raw response body — it’s the same structure the 400 Bad Request guide assumes when it tells you to check the error body for the specific rule that failed.

Why not just always request version 8?

Because “backward-incompatible” is not a formality — each version boundary is a real payload shape change somewhere in your integration. Jumping straight to 8 on an existing integration written against v1/v2 responses means: q syntax has to move to RowMatch (v2), every expanded-child consumer has to handle the collection wrapper (v3), every error handler has to parse the structured format instead of a string (v4), and so on through 5–8’s smaller LOV and encoding changes. New integrations have no reason not to start at the latest version the resource allows; existing ones should treat a version bump as a breaking-change migration, not a header tweak — test against every endpoint and payload shape the integration touches before flipping it in production.

Quick decision guide

If you need…Minimum version
and/or RowMatch syntax in q2
Paginated expand on large child resources3
Structured, machine-parseable error responses4
Root-level dependent LOV resources5
Consolidated @context metadata per item6
Hidden row-level LOV clutter in metadata7
Native-typed ClobDomain / FCL arrays / encoded identifiers8

Checking this without a live instance

Which framework version a specific resource defaults to — and what its allowedFrameworkVersions actually permits — varies by resource and by release, so the only reliable source is that resource’s own context-root response on your tenant. OPAL bundles the Oracle Fusion Cloud OpenAPI specification locally so you can inspect a resource’s fields, finders, and child structure offline while you plan which framework version your integration needs, before you’re anywhere near 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.