limit parameter caps at 500 but server can silently override it downward; always check hasMore attribute and implement pagination loops. [src3, src4]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.
| Property | Value |
|---|---|
| Vendor | Oracle |
| System | Oracle ERP Cloud (Fusion) 24B |
| API Surface | REST (HTTPS/JSON) |
| Current Framework Version | REST Framework v3+ |
| Editions Covered | All (Enterprise, Standard) |
| Deployment | Cloud |
| API Docs | Oracle Fusion Cloud REST API |
| Status | GA |
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 Surface | Protocol | Best For | Max Records/Request | Rate Limit | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| REST API | HTTPS/JSON | Individual record CRUD, queries <500 records | 500 (practical 499) | Tiered: 150-5,000/min | Yes | No |
| SOAP Web Services | HTTPS/XML | Legacy integrations, some metadata ops | Varies by service | Shared with REST | Yes | No |
| FBDI | CSV via UCM | Bulk data import >500 records, data migration | 100K rows/file (10 MB) | N/A (async) | No | Yes |
| BI Publisher Reports | HTTPS/XML | Bulk data export, scheduled reporting | No hard limit | N/A (async) | No | Yes |
| Business Events | Oracle AQ/JMS | Event-driven integration, CDC | N/A | N/A | Yes | N/A |
| OIC ERP Cloud Adapter | Pre-built connector | Orchestrated multi-step integrations | Depends on pattern | OIC-managed | Both | Both |
| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Max records per GET | 500 (practical 499) | REST API collection queries | Default 25 if limit not specified; server may override downward [src3] |
| Max request body size | 1 MB | REST API POST/PATCH/PUT | Applies to request payload [src2] |
| Max batch operations | 50 | Bulk API (batch endpoint) | Operations per single batch call [src2] |
| CSV import max rows | 100,000 | FBDI file uploads | Per file, max 10 MB file size [src2] |
| CSV export max rows | 100,000 | BI Publisher/export | Per export operation [src2] |
Rate limits in Oracle Fusion Cloud are managed at the OCI IAM identity domain level, not at the Fusion application level. [src2]
| Limit Type | Free Tier | Oracle Apps Tier | Premium Tier | Window |
|---|---|---|---|---|
| Authentication requests | 150/min | 1,000/min | 4,500/min | Per minute |
| Token management | 150/min | 1,000/min | 3,400/min | Per minute |
| Other API calls | 150/min | 1,500/min | 5,000/min | Per minute |
| Bulk API operations | 200/min | 200/min | 200/min | Per minute |
Oracle Fusion Cloud REST APIs support multiple authentication methods, with OAuth 2.0 being the recommended approach for production integrations. [src6]
| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| OAuth 2.0 JWT Bearer | Server-to-server, unattended integrations | Configurable (default ~1h) | New JWT per request | Recommended for production [src6] |
| OAuth 2.0 3-Legged | User-context operations, interactive apps | Access: ~1h, Refresh: until revoked | Yes | Requires callback URL and user consent [src6] |
| Basic Auth (username/password) | Development, testing, quick prototyping | Session-based | N/A | Not recommended for production — no MFA support [src6] |
offset and hasMore. [src3, src4]limit=500, the server may return fewer records. Always check hasMore rather than counting returned records. [src3]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
| Parameter | Purpose | Example | Notes |
|---|---|---|---|
limit | Max records per page | ?limit=499 | Default 25, max 500 (practical 499). Server can override. [src1] |
offset | Pagination start index | ?offset=499 | 0-indexed. offset=0 returns from first item. [src1] |
fields | Select specific fields | ?fields=InvoiceId,InvoiceNumber | Reduces payload size; comma-separated. [src1] |
expand | Include child resources | ?expand=invoiceLines | Comma-separated or expand=all. Framework v3+: returns paginated collection. [src1] |
onlyData | Omit HATEOAS links | ?onlyData=true | Default false. Cannot combine with links parameter. [src1] |
finder | Named predefined query | ?finder=PrimaryKey;InvoiceId=12345 | Uses predefined WHERE clause with bind variables. [src1] |
q | Ad-hoc filter/query | ?q=InvoiceNumber='INV-001' | SCIM-style operators: eq, ne, co, sw, gt, lt, ge, le. [src1] |
orderBy | Sort results | ?orderBy=CreationDate:desc | Ascending default. Use :asc or :desc suffix. [src1] |
totalResults | Include total count | ?totalResults=true | Performance cost — avoid for large collections. [src1] |
links | Control link relations | ?links=self,canonical | Mutually exclusive with onlyData=true. [src1] |
| Operation | Method | Endpoint | Payload | Notes |
|---|---|---|---|---|
| List invoices | GET | /fscmRestApi/resources/v1/invoices | N/A | Paginated; use limit and offset [src7] |
| Get invoice by ID | GET | /fscmRestApi/resources/v1/invoices/{InvoiceId} | N/A | Returns single resource with child links [src7] |
| Create invoice | POST | /fscmRestApi/resources/v1/invoices | JSON | Required fields per describe endpoint [src7] |
| Update invoice | PATCH | /fscmRestApi/resources/v1/invoices/{InvoiceId} | JSON | Partial update — only changed fields [src7] |
| Delete invoice | DELETE | /fscmRestApi/resources/v1/invoices/{InvoiceId} | N/A | Not supported on all resources [src7] |
| Describe resource | GET | /fscmRestApi/resources/v1/invoices/describe | N/A | Returns metadata: fields, types, children, actions [src1] |
| Execute action | POST | /fscmRestApi/resources/v1/invoices/{id} | JSON | Custom actions defined per resource [src1] |
| Access child | GET | /fscmRestApi/resources/v1/invoices/{id}/invoiceLines | N/A | Navigate parent-child relationships [src7] |
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.
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.
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.
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.
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.
# 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)}")
// 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;
}
# 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
| Response Field | Type | Description | Present When |
|---|---|---|---|
items | Array | Array of resource objects | Collection GET |
count | Integer | Number of records in current page | Collection GET |
hasMore | Boolean | Whether more pages exist | Collection GET |
totalResults | Integer | Total matching records | Only with totalResults=true |
links | Array | HATEOAS navigation links | When onlyData is false (default) |
2026-03-01T10:30:00+00:00). Always parse with timezone awareness. [src1]Y/N strings (not JSON true/false). Check the describe endpoint. [src1]q filter uses SCIM operators (eq, co, sw, gt, lt), not SQL. String values must be in single quotes. [src1]| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| 400 | Bad Request | Malformed JSON, invalid field names | Check payload against describe endpoint [src1] |
| 401 | Unauthorized | Expired/invalid token | Refresh OAuth token; verify integration user status [src6] |
| 403 | Forbidden | Insufficient security roles | Grant required Fusion security roles [src6] |
| 404 | Not Found | Wrong resource path or nonexistent record | Verify endpoint URL and resource version [src1] |
| 429 | Too Many Requests | Rate limit exceeded | Exponential backoff; check Retry-After header [src2] |
| 500 | Internal Server Error | Server-side processing failure | Retry with backoff; check Fusion EM Console logs [src1] |
| 503 | Service Unavailable | Maintenance window | Check Oracle Cloud Status Dashboard [src2] |
limit without explanation. Fix: Always use hasMore boolean instead of comparing count to limit. [src3]Track token expiry and refresh proactively before expiration. [src6]Use expand parameter for DFF/EFF child resources. [src1]Use semicolons; verify finders via describe endpoint. [src1]Test per resource in non-prod; implement single-record fallback. [src1]# 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)
# 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"])
# 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
# 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)
# BAD - Returns all fields including HATEOAS links
curl "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=499"
# 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"
limit parameter returns only 25 records per page. Fix: Always explicitly set limit=499 in production code. [src1, src3]expand returned flat arrays. In v3+, it returns paginated collections. Fix: Handle expanded children as collections with hasMore/count/offset. [src1]q filter uses SCIM operators, not SQL WHERE clauses. Using SQL syntax silently returns zero results. Fix: Use SCIM operators: eq, ne, co, sw, gt, lt, ge, le. [src1]totalResults=true forces counting all records, increasing response time up to 10x. Fix: Only use on first request if needed; omit for subsequent pages. [src1]11.13.18.05 vs v1). Fix: Pin to a specific version and use it consistently. [src1]Monitor API usage across all apps; consider separate IAM domains. [src2]# 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
| Framework Version | Approx. Release | Status | Breaking Changes | Migration Notes |
|---|---|---|---|---|
| REST Framework v3+ | 2022 | Current | expand returns collection resources (paginated) | Update expand parsing to handle collection structure |
| REST Framework v2 | 2019 | Legacy | N/A | Flat expand responses; no child pagination |
| REST Framework v1 | 2016 | Deprecated | N/A | Limited 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]
| Use When | Don't Use When | Use 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 load | FBDI + ESS scheduled processes [src5] |
| Metadata discovery (describe endpoint) | Event-driven / CDC integration | Business Events + OIC Adapter [src5] |
| Small-batch reads with field selection | Streaming or real-time notifications | Business Events subscriptions [src5] |
| Prototyping and testing with cURL/Postman | Scheduled nightly sync of entire tables | BI Publisher reports + OIC [src5] |