Oracle ERP Cloud (Fusion) REST API Capabilities

Type: ERP Integration System: Oracle ERP Cloud (Fusion) (24B) Confidence: 0.92 Sources: 7 Verified: 2026-03-01 Freshness: 2026-03-01

TL;DR

System Profile

Oracle ERP Cloud (Fusion) is Oracle's cloud-native ERP suite covering Financials, Procurement, Project Management, and Supply Chain. The REST API surface uses the Oracle Fusion Applications REST framework, which has evolved through multiple versions (most recently Framework v3, introducing collection-based pagination for expanded child resources). This card covers the REST API specifically — SOAP services, FBDI, BI Publisher, and the Oracle Integration Cloud (OIC) adapter are separate integration surfaces with different capabilities and constraints.

PropertyValue
VendorOracle
SystemOracle ERP Cloud (Fusion) 24B
API SurfaceREST (HTTPS/JSON)
Current Framework VersionREST Framework v3+
Editions CoveredAll (Enterprise, Standard)
DeploymentCloud
API DocsOracle Fusion Cloud REST API
StatusGA

API Surfaces & Capabilities

Oracle Fusion Cloud offers multiple integration surfaces. The REST API is one of several; choosing the right surface depends on data volume, latency requirements, and integration pattern. [src5]

API SurfaceProtocolBest ForMax Records/RequestRate LimitReal-time?Bulk?
REST APIHTTPS/JSONIndividual record CRUD, queries <500 records500 (practical 499)Tiered: 150-5,000/minYesNo
SOAP Web ServicesHTTPS/XMLLegacy integrations, some metadata opsVaries by serviceShared with RESTYesNo
FBDICSV via UCMBulk data import >500 records, data migration100K rows/file (10 MB)N/A (async)NoYes
BI Publisher ReportsHTTPS/XMLBulk data export, scheduled reportingNo hard limitN/A (async)NoYes
Business EventsOracle AQ/JMSEvent-driven integration, CDCN/AN/AYesN/A
OIC ERP Cloud AdapterPre-built connectorOrchestrated multi-step integrationsDepends on patternOIC-managedBothBoth

Rate Limits & Quotas

Per-Request Limits

Limit TypeValueApplies ToNotes
Max records per GET500 (practical 499)REST API collection queriesDefault 25 if limit not specified; server may override downward [src3]
Max request body size1 MBREST API POST/PATCH/PUTApplies to request payload [src2]
Max batch operations50Bulk API (batch endpoint)Operations per single batch call [src2]
CSV import max rows100,000FBDI file uploadsPer file, max 10 MB file size [src2]
CSV export max rows100,000BI Publisher/exportPer export operation [src2]

Rolling / Daily Limits

Rate limits in Oracle Fusion Cloud are managed at the OCI IAM identity domain level, not at the Fusion application level. [src2]

Limit TypeFree TierOracle Apps TierPremium TierWindow
Authentication requests150/min1,000/min4,500/minPer minute
Token management150/min1,000/min3,400/minPer minute
Other API calls150/min1,500/min5,000/minPer minute
Bulk API operations200/min200/min200/minPer minute

Authentication

Oracle Fusion Cloud REST APIs support multiple authentication methods, with OAuth 2.0 being the recommended approach for production integrations. [src6]

FlowUse WhenToken LifetimeRefresh?Notes
OAuth 2.0 JWT BearerServer-to-server, unattended integrationsConfigurable (default ~1h)New JWT per requestRecommended for production [src6]
OAuth 2.0 3-LeggedUser-context operations, interactive appsAccess: ~1h, Refresh: until revokedYesRequires callback URL and user consent [src6]
Basic Auth (username/password)Development, testing, quick prototypingSession-basedN/ANot recommended for production — no MFA support [src6]

Authentication Gotchas

Constraints

Integration Pattern Decision Tree

START - User needs to integrate with Oracle ERP Cloud (Fusion) via REST API
|-- What's the integration pattern?
|   |-- Real-time (individual records, <1s)
|   |   |-- Data volume < 500 records/operation?
|   |   |   |-- YES -> REST API: use standard CRUD endpoints
|   |   |   |   |-- Multi-object in single call? -> Use batch endpoint (max 50 ops)
|   |   |   |   +-- Single object -> Standard POST/PATCH/GET/DELETE
|   |   |   +-- NO -> NOT suitable for REST API -> Use FBDI
|   |   +-- Need response shaping?
|   |       |-- Fewer fields -> Use fields parameter (reduces payload)
|   |       |-- Child resources -> Use expand parameter (avoids N+1)
|   |       +-- No links needed -> Use onlyData=true (smaller payload)
|   |-- Batch/Bulk (scheduled, high volume)
|   |   |-- Data volume < 500 records? -> REST API acceptable
|   |   +-- Data volume > 500 records? -> FBDI for import, BI Publisher for export
|   |-- Event-driven (webhook, CDC)
|   |   +-- REST API does NOT support events
|   |       |-- Use Business Events for ERP-originated events
|   |       +-- Use OIC ERP Cloud Adapter for orchestrated handling
|   +-- File-based (CSV/XML) -> Use FBDI
|-- Which direction?
|   |-- Inbound (writing to Fusion) -> POST/PATCH; check payload < 1 MB
|   |-- Outbound (reading from Fusion) -> GET with pagination; use finder
|   +-- Bidirectional -> Design conflict resolution first
+-- Error tolerance?
    |-- Zero-loss -> Implement idempotency + retry with backoff on 429
    +-- Best-effort -> Fire-and-forget with basic 429 retry

Quick Reference

Key Query Parameters

ParameterPurposeExampleNotes
limitMax records per page?limit=499Default 25, max 500 (practical 499). Server can override. [src1]
offsetPagination start index?offset=4990-indexed. offset=0 returns from first item. [src1]
fieldsSelect specific fields?fields=InvoiceId,InvoiceNumberReduces payload size; comma-separated. [src1]
expandInclude child resources?expand=invoiceLinesComma-separated or expand=all. Framework v3+: returns paginated collection. [src1]
onlyDataOmit HATEOAS links?onlyData=trueDefault false. Cannot combine with links parameter. [src1]
finderNamed predefined query?finder=PrimaryKey;InvoiceId=12345Uses predefined WHERE clause with bind variables. [src1]
qAd-hoc filter/query?q=InvoiceNumber='INV-001'SCIM-style operators: eq, ne, co, sw, gt, lt, ge, le. [src1]
orderBySort results?orderBy=CreationDate:descAscending default. Use :asc or :desc suffix. [src1]
totalResultsInclude total count?totalResults=truePerformance cost — avoid for large collections. [src1]
linksControl link relations?links=self,canonicalMutually exclusive with onlyData=true. [src1]

Common Financial REST Endpoints

OperationMethodEndpointPayloadNotes
List invoicesGET/fscmRestApi/resources/v1/invoicesN/APaginated; use limit and offset [src7]
Get invoice by IDGET/fscmRestApi/resources/v1/invoices/{InvoiceId}N/AReturns single resource with child links [src7]
Create invoicePOST/fscmRestApi/resources/v1/invoicesJSONRequired fields per describe endpoint [src7]
Update invoicePATCH/fscmRestApi/resources/v1/invoices/{InvoiceId}JSONPartial update — only changed fields [src7]
Delete invoiceDELETE/fscmRestApi/resources/v1/invoices/{InvoiceId}N/ANot supported on all resources [src7]
Describe resourceGET/fscmRestApi/resources/v1/invoices/describeN/AReturns metadata: fields, types, children, actions [src1]
Execute actionPOST/fscmRestApi/resources/v1/invoices/{id}JSONCustom actions defined per resource [src1]
Access childGET/fscmRestApi/resources/v1/invoices/{id}/invoiceLinesN/ANavigate parent-child relationships [src7]

Step-by-Step Integration Guide

1. Authenticate with OAuth 2.0 JWT Bearer

Obtain an access token from the OCI IAM domain linked to your Fusion instance. [src6]

# Request OAuth token from OCI IAM
curl -X POST "https://idcs-{tenant}.identity.oraclecloud.com/oauth2/v1/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u "{client_id}:{client_secret}" \
  -d "grant_type=client_credentials&scope=https://{pod}.fa.{dc}.oraclecloud.com:443urn:opc:resource:consumer::all"

Verify: Response contains access_token field with JWT string and expires_in value.

2. Query a resource collection with pagination

Fetch records using offset-based pagination. The response includes hasMore (boolean) and count (records in current page). [src1, src4]

# First page: 499 records starting from offset 0
curl -X GET "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=499&offset=0&onlyData=true&fields=InvoiceId,InvoiceNumber,InvoiceAmount" \
  -H "Authorization: Bearer {access_token}"

Verify: Response JSON contains items array, hasMore boolean, and count integer.

3. Handle pagination loop for large datasets

When the dataset exceeds 499 records, implement an offset-based loop. [src4]

import requests

def fetch_all_records(base_url, resource, token, fields=None):
    all_items, offset, has_more = [], 0, True
    headers = {"Authorization": f"Bearer {token}"}
    while has_more:
        params = {"limit": 499, "offset": offset, "onlyData": "true"}
        if fields:
            params["fields"] = ",".join(fields)
        resp = requests.get(f"{base_url}/fscmRestApi/resources/v1/{resource}",
                            headers=headers, params=params)
        resp.raise_for_status()
        data = resp.json()
        all_items.extend(data.get("items", []))
        has_more = data.get("hasMore", False)
        offset += len(data.get("items", []))
    return all_items

Verify: Total record count matches expected total.

4. Use expand vs fields for response shaping

The expand parameter includes child resources inline (avoids N+1 queries). The fields parameter limits which fields are returned. [src1]

# Expand invoice lines, select specific fields, omit links
curl -X GET "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/{InvoiceId}?expand=invoiceLines&fields=InvoiceId,InvoiceNumber;invoiceLines:LineNumber,LineAmount&onlyData=true" \
  -H "Authorization: Bearer {access_token}"

Verify: Response includes invoiceLines as nested collection with only specified fields.

5. Implement error handling with exponential backoff

Handle rate limiting (429) and transient failures with exponential backoff. [src2]

import time, requests

def resilient_request(method, url, headers, max_retries=5, **kwargs):
    for attempt in range(max_retries):
        resp = requests.request(method, url, headers=headers, **kwargs)
        if resp.status_code == 429:
            wait = min(int(resp.headers.get("Retry-After", 2 ** attempt)), 60)
            time.sleep(wait)
            continue
        if resp.status_code >= 500:
            time.sleep(2 ** attempt)
            continue
        resp.raise_for_status()
        return resp
    raise Exception(f"Max retries exceeded for {url}")

Verify: On 429, function waits and retries; on 5xx, uses exponential backoff.

Code Examples

Python: Fetch All Suppliers with Pagination

# Input:  OAuth token, Fusion base URL
# Output: List of all supplier dicts with selected fields
import requests

BASE_URL = "https://{pod}.fa.{dc}.oraclecloud.com"
TOKEN = "{your_oauth_token}"
headers = {"Authorization": f"Bearer {TOKEN}"}

all_suppliers, offset, has_more = [], 0, True
while has_more:
    resp = requests.get(f"{BASE_URL}/fscmRestApi/resources/v1/suppliers",
        headers=headers,
        params={"limit": 499, "offset": offset, "onlyData": "true",
                "fields": "SupplierId,Supplier,SupplierNumber,Status"})
    resp.raise_for_status()
    data = resp.json()
    all_suppliers.extend(data.get("items", []))
    has_more = data.get("hasMore", False)
    offset += len(data.get("items", []))
print(f"Total suppliers: {len(all_suppliers)}")

JavaScript/Node.js: Query with Finder Parameter

// Input:  OAuth token, invoice number to look up
// Output: Invoice object matching the finder query
const fetch = require("node-fetch");

async function findInvoice(baseUrl, token, invoiceNumber) {
  const url = new URL(`${baseUrl}/fscmRestApi/resources/v1/invoices`);
  url.searchParams.set("finder", `PrimaryKey;InvoiceNumber=${invoiceNumber}`);
  url.searchParams.set("onlyData", "true");
  const resp = await fetch(url.toString(), {
    headers: { Authorization: `Bearer ${token}` }
  });
  if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
  const data = await resp.json();
  return data.items?.[0] || null;
}

cURL: Quick API Tests

# Test authentication
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=5&onlyData=true" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Describe resource schema
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/describe" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Filter with q parameter
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?q=CreationDate%20gt%20%272026-01-01%27&limit=10&onlyData=true" \
  -H "Authorization: Bearer {token}" | python -m json.tool

Data Mapping

REST API Response Structure

Response FieldTypeDescriptionPresent When
itemsArrayArray of resource objectsCollection GET
countIntegerNumber of records in current pageCollection GET
hasMoreBooleanWhether more pages existCollection GET
totalResultsIntegerTotal matching recordsOnly with totalResults=true
linksArrayHATEOAS navigation linksWhen onlyData is false (default)

Data Type Gotchas

Error Handling & Failure Points

Common Error Codes

CodeMeaningCauseResolution
400Bad RequestMalformed JSON, invalid field namesCheck payload against describe endpoint [src1]
401UnauthorizedExpired/invalid tokenRefresh OAuth token; verify integration user status [src6]
403ForbiddenInsufficient security rolesGrant required Fusion security roles [src6]
404Not FoundWrong resource path or nonexistent recordVerify endpoint URL and resource version [src1]
429Too Many RequestsRate limit exceededExponential backoff; check Retry-After header [src2]
500Internal Server ErrorServer-side processing failureRetry with backoff; check Fusion EM Console logs [src1]
503Service UnavailableMaintenance windowCheck Oracle Cloud Status Dashboard [src2]

Failure Points in Production

Anti-Patterns

Wrong: Fetching all records without pagination

# BAD - Assumes single request returns all records
resp = requests.get(f"{base_url}/invoices", headers=headers)
all_invoices = resp.json()["items"]  # Only gets first 25 records (default limit)

Correct: Always implement pagination with hasMore check

# GOOD - Paginates through all records using hasMore
all_invoices, offset, has_more = [], 0, True
while has_more:
    resp = requests.get(f"{base_url}/invoices", headers=headers,
        params={"limit": 499, "offset": offset, "onlyData": "true"})
    data = resp.json()
    all_invoices.extend(data["items"])
    has_more = data.get("hasMore", False)
    offset += len(data["items"])

Wrong: Using REST API for bulk data import

# BAD - Creating 10,000 records one by one via REST API
for invoice in ten_thousand_invoices:
    requests.post(f"{base_url}/invoices", json=invoice, headers=headers)
    # Takes hours, risks rate limiting, no batch rollback

Correct: Use FBDI for bulk operations

# GOOD - For >500 records, use File-Based Data Import
# 1. Generate CSV in FBDI template format
# 2. Upload CSV to UCM via REST
# 3. Invoke ESS import job via REST
# 4. Poll ESS job status until complete
resp = requests.get(f"{base_url}/erpintegrations/v1/ess-job-status/{job_id}",
    headers=headers)

Wrong: Fetching full payloads when only a few fields needed

# BAD - Returns all fields including HATEOAS links
curl "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=499"

Correct: Use fields + onlyData to minimize payload

# GOOD - Only returns needed fields, no links
curl "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=499&onlyData=true&fields=InvoiceId,InvoiceNumber,InvoiceAmount"

Common Pitfalls

Diagnostic Commands

# Test authentication — simple GET to verify token
curl -s -o /dev/null -w "%{http_code}" \
  "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=1" \
  -H "Authorization: Bearer {token}"
# Expected: 200 (success) or 401 (token issue)

# Discover available resources — list resource catalog
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Describe resource schema
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/describe" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Test q filter syntax
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?q=InvoiceNumber%20eq%20%27INV-001%27&onlyData=true&limit=1" \
  -H "Authorization: Bearer {token}" | python -m json.tool

Version History & Compatibility

Framework VersionApprox. ReleaseStatusBreaking ChangesMigration Notes
REST Framework v3+2022Currentexpand returns collection resources (paginated)Update expand parsing to handle collection structure
REST Framework v22019LegacyN/AFlat expand responses; no child pagination
REST Framework v12016DeprecatedN/ALimited query parameters; basic CRUD only

Resource versions (e.g., 11.13.18.05 vs v1) are independent of framework versions. Oracle does not publish a fixed deprecation timeline — monitor Release Readiness documents for each quarterly update. [src1]

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Real-time individual record CRUD (<500 records)Bulk data import/export (>500 records)FBDI for import, BI Publisher for export [src5]
Querying with complex filters (q parameter)Full data migration or initial loadFBDI + ESS scheduled processes [src5]
Metadata discovery (describe endpoint)Event-driven / CDC integrationBusiness Events + OIC Adapter [src5]
Small-batch reads with field selectionStreaming or real-time notificationsBusiness Events subscriptions [src5]
Prototyping and testing with cURL/PostmanScheduled nightly sync of entire tablesBI Publisher reports + OIC [src5]

Important Caveats

Related Units